wrapup-partition
Version:
Convert Node/CommonJS modules for the browser with on demand loading of JS files
173 lines (140 loc) • 5.69 kB
JavaScript
;
var prime = require('prime')
var async = require('async')
var path = require('path')
var mkdirp = require('mkdirp')
var fs = require('fs')
var forOwn = require('mout/object/forOwn')
var Output = require('wrapup/lib/output')
var util = require('wrapup/lib/util')
var errors = require('wrapup/lib/errors')
var escodegen = require('escodegen')
var resolveMapping = require('./resolveMapping')
var includes = __dirname + '/../includes'
var getDefineAST = util.getAST('module', includes)
var getWrapperAST = util.getAST('wrapper', includes)
var getMainAST = util.getAST('main', includes)
var Partition = prime({
inherits: Output,
up: function(callback){
var self = this
if (!this.options.output){
callback(new errors.RequiredOutputError())
return this
}
var options = this.options
this._path = (options.path ? options.path : process.cwd()) + '/a'
async.parallel([
getDefineAST,
getWrapperAST,
getMainAST
], function(err, results){
if (err) callback(err)
else self.output(callback, results[0], results[1], results[2])
})
},
output: function(callback, defineAST, wrapperAST, mainAST){
var self = this
var options = this.options
var map = options.map || {}
var output = options.output
var modules = []
var tasks = []
var first = 0
var resolved = resolveMapping(map, this.storage, this._path)
forOwn(resolved.notFound, function(id, out){
self.emit("warn", new Error("Module '" + id + "' in mapping not found"))
})
forOwn(resolved.modules, function(modules, file){
var ast = util.clone(wrapperAST)
if (first++ === 0) self.addMainToAST(ast, resolved.modules, mainAST)
self.addModulesToAST(ast, modules, defineAST)
tasks.push(function(callback){
self.writeFile(file, ast, callback)
})
})
async.parallel(tasks, callback)
},
getModuleName: function(module){
return this.options.compress ? module.uid : module.getModuleID(this._path);
},
addMainToAST: function(ast, map, mainAST){
var self = this
var main = util.clone(mainAST.body[0])
ast.body.push(main)
var mapping = main.expression.callee.body.body[0].declarations[0].init.properties
var files = mapping[0].value.elements
var modules = mapping[1].value.properties
forOwn(map, function(mods, file){
var i = files.push({type: "Literal", value: file})
mods.forEach(function(module){
modules.push({
type: "Property",
key: {type: "Literal", value: module.getModuleID(self._path)},
value: {
type: "ArrayExpression",
elements: [
{type: "Literal", value: i - 1},
{type: "Literal", value: module.uid}
]
},
kind: "init"
})
})
})
// replace the true/false defines/paths object construction mapping
var forIn = main.expression.callee.body.body[3].body
var testOne = forIn.body[0].expression.left.property.test
var testTwo = forIn.body[1].expression.right.test
testOne.value = testTwo.value = !!this.options.compress
},
addModulesToAST: function(wrapper, modules, defineAST){
var self = this
modules.forEach(function(module){
if (!module || !module.full || module.err) return
var ast = util.clone(module.ast)
// replace require() calls
Output.replaceRequire(ast, module, function(dep){
return self.getModuleName(dep)
})
var newAST = util.clone(defineAST.body[0])
var args = newAST.expression['arguments']
// change module ID
args[0].value = self.getModuleName(module)
// add dependencies to the dependency array
var deps = args[1].elements
module.dependencies.forEach(function(dep){
if (dep) deps.push({type: "Literal", value: self.getModuleName(dep)})
})
// body of the define function
var body = args[2].body.body
// put the module JS in the define factory function
for (var i = 0; i < ast.body.length; i++){
body.push(ast.body[i])
}
// and add the define() function to the wrapper
wrapper.body.push(newAST)
})
},
writeFile: function(file, ast, callback){
var self = this
var output = this.options.output
var asASTJSON = this.options.ast
var filename = path.normalize(output + '/' + file)
if (asASTJSON){
var ext = path.extname(filename);
filename = filename.slice(0, - ext.length) + '.json'
}
var code = asASTJSON ?
JSON.stringify(ast, null, 2) :
escodegen.generate(ast)
async.series([
async.apply(mkdirp, path.dirname(filename)),
async.apply(fs.writeFile, filename, code)
], function(err){
if (!err) self.emit("output", filename)
callback(err, filename)
})
}
})
module.exports = Partition