wip: bundling work
This commit is contained in:
+8
-46
@@ -1,53 +1,15 @@
|
||||
import Mfs from 'memory-fs'
|
||||
import webpack from 'webpack'
|
||||
import {
|
||||
FuseBox,
|
||||
CSSPlugin,
|
||||
JSONPlugin,
|
||||
HTMLPlugin } from 'fuse-box'
|
||||
import { fromCallback } from 'bluebird'
|
||||
import { resolve, join, relative } from 'path'
|
||||
|
||||
const isObject = (x) => typeof x === 'object'
|
||||
const isString = (x) => x instanceof String || typeof x === 'string'
|
||||
import * as path from 'path'
|
||||
|
||||
export default async function bundle (compiler, next) {
|
||||
let bundleConfig = compiler.options.bundle
|
||||
if (!bundleConfig) {
|
||||
let options = compiler.options.bundle
|
||||
if (!options) {
|
||||
return next()
|
||||
}
|
||||
|
||||
const inputFilePath = compiler.options.input || require.resolve(process.cwd())
|
||||
const mfs = new Mfs()
|
||||
const path = resolve('nexe')
|
||||
const filename = 'virtual-bundle.js'
|
||||
|
||||
if (isString(bundleConfig)) {
|
||||
bundleConfig = require(relative(process.cwd(), bundleConfig))
|
||||
} else if (!isObject(bundleConfig)) {
|
||||
bundleConfig = {
|
||||
entry: resolve(inputFilePath),
|
||||
target: 'node',
|
||||
module: {
|
||||
rules: [
|
||||
{ test: /\.html$/, use: 'html-loader' },
|
||||
{ test: /\.json$/, use: 'json-loader' },
|
||||
{ test: /\.node$/, use: 'xbin-loader' },
|
||||
{ test: /license$|\.md$/, use: 'raw-loader' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bundleConfig.output = { path, filename }
|
||||
|
||||
const bundler = webpack(bundleConfig)
|
||||
bundler.outputFileSystem = mfs
|
||||
const stats = await fromCallback(cb => bundler.run(cb))
|
||||
|
||||
if (stats.hasErrors()) {
|
||||
// compiler.log.error(stats.toString())
|
||||
return null
|
||||
}
|
||||
|
||||
compiler.input = mfs.readFileSync(
|
||||
join(bundleConfig.output.path, bundleConfig.output.filename)
|
||||
)
|
||||
|
||||
return next()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import * as child from 'child_process'
|
||||
|
||||
function findNativeModulePath (filePath, bindingsArg) {
|
||||
const dirname = path.dirname(filePath)
|
||||
const tempFile = Math.random() * 100 + '.js'
|
||||
const tempFilePath = path.join(dirname, tempFile)
|
||||
fs.writeFileSync(tempFilePath, `
|
||||
var bindings = require('bindings');
|
||||
var Module = require('module');
|
||||
var originalRequire = Module.prototype.require;
|
||||
Module.prototype.require = function(path) {
|
||||
const mod = originalRequire.apply(this, arguments);
|
||||
process.stdout.write(path)
|
||||
return mod
|
||||
};
|
||||
bindings('${bindingsArg}')
|
||||
`)
|
||||
//using exec because it can be done syncronously
|
||||
const nativeFileName = child.execSync('node ' + tempFile, { cwd: dirname }).toString()
|
||||
fs.unlinkSync(tempFilePath)
|
||||
const relativePath = './' + path.relative(dirname, nativeFileName).replace(/\\/g, '/')
|
||||
return relativePath
|
||||
}
|
||||
/**
|
||||
* Traverse all nodes in a file and evaluate usages of the bindings module
|
||||
*/
|
||||
export class BindingsRewrite {
|
||||
|
||||
constructor () {
|
||||
this.bindingsIdNodes = []
|
||||
this.nativeModulePaths = []
|
||||
this.rewrite = false
|
||||
}
|
||||
|
||||
isRequireBindings (node) {
|
||||
return node.callee.name === 'require' && node.arguments[0].value === 'bindings'
|
||||
}
|
||||
|
||||
onNode (absolutePath, node, parent) {
|
||||
if (node.type === 'CallExpression') {
|
||||
if (this.isRequireBindings(node) && parent.type === 'VariableDeclarator') {
|
||||
/**
|
||||
* const loadBindings = require('bindings');
|
||||
* -> const loadBindings = String('');
|
||||
*/
|
||||
this.bindingsIdNodes.push(parent.id)
|
||||
node.callee.name = 'String'
|
||||
node.arguments[0].value = ''
|
||||
this.rewrite = true
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isRequireBindings(node) && parent.type === 'CallExpression') {
|
||||
/**
|
||||
*const bindings = require('bindings')('native-module')....
|
||||
* -> const bindings = require('./path/to/native/module.node').....
|
||||
*/
|
||||
const bindingsArgNode = parent.arguments[0]
|
||||
if (bindingsArgNode.type === 'Literal') {
|
||||
parent.callee = { type: 'Identifier', name: 'require' }
|
||||
bindingsArgNode.value = findNativeModulePath(absolutePath, bindingsArgNode.value)
|
||||
this.nativeModulePaths.push(bindingsArgNode.value)
|
||||
this.rewrite = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const bindingsInvocationIdx = this.bindingsIdNodes.findIndex(x => node.callee.name === x.name)
|
||||
|
||||
if (this.bindingsIdNodes[bindingsInvocationIdx]) {
|
||||
/**
|
||||
* const bindings = loadBindings('native-module')
|
||||
* -> const bindings = require('./path/to/native/module.node')
|
||||
*/
|
||||
const bindingsIdNode = this.bindingsIdNodes[bindingsInvocationIdx]
|
||||
const bindingsArgNode = node.arguments[0]
|
||||
this.bindingsIdNodes.splice(bindingsInvocationIdx, 1)
|
||||
|
||||
if (bindingsArgNode.type === 'Literal') {
|
||||
node.callee.name = 'require'
|
||||
bindingsArgNode.value = findNativeModulePath(absolutePath, bindingsArgNode.value)
|
||||
this.nativeModulePaths.push(bindingsArgNode.value)
|
||||
this.rewrite = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { BindingsRewrite } from './bindings-rewrite'
|
||||
|
||||
export class NativeModulePlugin {
|
||||
constructor (...moduleNames) {
|
||||
this.test = new RegExp(`node_modules\/(${moduleNames.join('|')}).*\.js`)
|
||||
this.limit2project = false
|
||||
}
|
||||
|
||||
transform (file) {
|
||||
const bindingsRewrite = new BindingsRewrite()
|
||||
file.loadContents()
|
||||
file.makeAnalysis(null, {
|
||||
plugins: [{
|
||||
onNode(file, node, parent) {
|
||||
bindingsRewrite.onNode(file.info.absPath, node, parent)
|
||||
},
|
||||
onEnd(file) {
|
||||
if (bindingsRewrite.rewrite) {
|
||||
const index = file.analysis.dependencies.indexOf('bindings')
|
||||
if (~index) {
|
||||
file.analysis.dependencies.splice(index, 1)
|
||||
}
|
||||
file.analysis.dependencies.push(...bindingsRewrite.nativeModulePaths)
|
||||
file.analysis.requiresRegeneration = true
|
||||
}
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user