webpack
Version:
Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jade, coffee, css, less, ... and your custom stuff.
239 lines (234 loc) • 8.66 kB
JavaScript
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var AMDRequireItemDependency = require("./AMDRequireItemDependency");
var AMDRequireContextDependency = require("./AMDRequireContextDependency");
var ConstDependency = require("./ConstDependency");
var AMDDefineDependency = require("./AMDDefineDependency");
var AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
var LocalModuleDependency = require("./LocalModuleDependency");
var ContextDependencyHelpers = require("./ContextDependencyHelpers");
var LocalModulesHelpers = require("./LocalModulesHelpers");
function isBoundFunctionExpression(expr) {
if(expr.type !== "CallExpression") return false;
if(expr.callee.type !== "MemberExpression") return false;
if(expr.callee.computed) return false;
if(expr.callee.object.type !== "FunctionExpression") return false;
if(expr.callee.property.type !== "Identifier") return false;
if(expr.callee.property.name !== "bind") return false;
return true;
}
function AMDDefineDependencyParserPlugin(options) {
this.options = options;
}
module.exports = AMDDefineDependencyParserPlugin;
AMDDefineDependencyParserPlugin.prototype.apply = function(parser) {
var options = this.options;
parser.plugin("call define", function(expr) {
var array, fn, obj, namedModule;
switch(expr.arguments.length) {
case 1:
if(expr.arguments[0].type === "FunctionExpression" || isBoundFunctionExpression(expr.arguments[0])) {
// define(f() {...})
fn = expr.arguments[0];
} else if(expr.arguments[0].type === "ObjectExpression") {
// define({...})
obj = expr.arguments[0];
} else {
// define(expr)
// unclear if function or object
obj = fn = expr.arguments[0];
}
break;
case 2:
if(expr.arguments[0].type === "Literal") {
namedModule = expr.arguments[0].value;
// define("...", ...)
if(expr.arguments[1].type === "FunctionExpression" || isBoundFunctionExpression(expr.arguments[1])) {
// define("...", f() {...})
fn = expr.arguments[1];
} else if(expr.arguments[1].type === "ObjectExpression") {
// define("...", {...})
obj = expr.arguments[1];
} else {
// define("...", expr)
// unclear if function or object
obj = fn = expr.arguments[1];
}
} else {
array = expr.arguments[0];
if(expr.arguments[1].type === "FunctionExpression" || isBoundFunctionExpression(expr.arguments[1])) {
// define([...], f() {})
fn = expr.arguments[1];
} else if(expr.arguments[1].type === "ObjectExpression") {
// define([...], {...})
obj = expr.arguments[1];
} else {
// define([...], expr)
// unclear if function or object
obj = fn = expr.arguments[1];
}
}
break;
case 3:
// define("...", [...], f() {...})
namedModule = expr.arguments[0].value;
array = expr.arguments[1];
if(expr.arguments[2].type === "FunctionExpression" || isBoundFunctionExpression(expr.arguments[2])) {
// define("...", [...], f() {})
fn = expr.arguments[2];
} else if(expr.arguments[2].type === "ObjectExpression") {
// define("...", [...], {...})
obj = expr.arguments[2];
} else {
// define("...", [...], expr)
// unclear if function or object
obj = fn = expr.arguments[2];
}
break;
default: return;
}
var fnParams = null;
var fnParamsOffset = 0;
if(fn) {
if(fn.type === "FunctionExpression") fnParams = fn.params;
else if(isBoundFunctionExpression(fn)) {
fnParams = fn.callee.object.params;
fnParamsOffset = fn.arguments.length - 1;
if(fnParamsOffset < 0) fnParamsOffset = 0;
}
}
var fnRenames = Object.create(this.scope.renames);
if(array) {
var identifiers = {};
var param = this.evaluateExpression(array);
var result = this.applyPluginsBailResult("call define:amd:array", expr, param, identifiers);
if(!result) return;
if(fnParams) fnParams = fnParams.slice(fnParamsOffset).filter(function(param, idx) {
if(identifiers[idx]) {
fnRenames["$"+param.name] = identifiers[idx];
return false;
}
return true;
});
} else {
var identifiers = ["require", "exports", "module"];
if(fnParams) fnParams = fnParams.slice(fnParamsOffset).filter(function(param, idx) {
if(identifiers[idx]) {
fnRenames["$"+param.name] = identifiers[idx];
return false;
}
return true;
});
}
if(fn && fn.type === "FunctionExpression") {
var inTry = this.scope.inTry;
this.inScope(fnParams, function() {
this.scope.renames = fnRenames;
this.scope.inTry = inTry;
if(fn.body.type === "BlockStatement")
this.walkStatement(fn.body);
else
this.walkExpression(fn.body);
}.bind(this));
} else if(fn && isBoundFunctionExpression(fn)) {
var inTry = this.scope.inTry;
this.inScope(fn.callee.object.params.filter(function(i) {
return ["require", "module", "exports"].indexOf(i.name) < 0;
}), function() {
this.scope.renames = fnRenames;
this.scope.inTry = inTry;
if(fn.callee.object.body.type === "BlockStatement")
this.walkStatement(fn.callee.object.body);
else
this.walkExpression(fn.callee.object.body);
}.bind(this));
if(fn.arguments)
this.walkExpressions(fn.arguments);
} else if(fn || obj) {
this.walkExpression(fn || obj);
}
var dep = new AMDDefineDependency(expr.range, array ? array.range : null, fn ? fn.range : null, obj ? obj.range : null);
dep.loc = expr.loc;
if(namedModule) {
dep.localModule = LocalModulesHelpers.addLocalModule(this.state, namedModule);
}
this.state.current.addDependency(dep);
return true;
});
parser.plugin("call define:amd:array", function(expr, param, identifiers) {
if(param.isArray()) {
param.items.forEach(function(param, idx) {
if(param.isString() && ["require", "module", "exports"].indexOf(param.string) >= 0)
identifiers[idx] = param.string;
var result = this.applyPluginsBailResult("call define:amd:item", expr, param);
if(result === undefined) {
this.applyPluginsBailResult("call define:amd:context", expr, param);
}
}, this);
return true;
} else if(param.isConstArray()) {
var deps = [];
param.array.forEach(function(request, idx) {
var dep, localModule;
if(request === "require") {
identifiers[idx] = request;
dep = "__webpack_require__";
} else if(["exports", "module"].indexOf(request) >= 0) {
identifiers[idx] = request;
dep = request;
} else if(localModule = LocalModulesHelpers.getLocalModule(this.state, request)) {
dep = new LocalModuleDependency(localModule);
dep.loc = expr.loc;
this.state.current.addDependency(dep);
} else {
dep = new AMDRequireItemDependency(request);
dep.loc = expr.loc;
dep.optional = !!this.scope.inTry;
this.state.current.addDependency(dep);
}
deps.push(dep);
}, this);
var dep = new AMDRequireArrayDependency(deps, param.range);
dep.loc = expr.loc;
dep.optional = !!this.scope.inTry;
this.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call define:amd:item", function(expr, param) {
if(param.isConditional()) {
param.options.forEach(function(param) {
var result = this.applyPluginsBailResult("call define:amd:item", expr, param);
if(result === undefined) {
this.applyPluginsBailResult("call define:amd:context", expr, param);
}
}, this);
return true;
} else if(param.isString()) {
var dep, localModule;
if(param.string === "require") {
dep = new ConstDependency("__webpack_require__", param.range);
} else if(["require", "exports", "module"].indexOf(param.string) >= 0) {
dep = new ConstDependency(param.string, param.range);
} else if(localModule = LocalModulesHelpers.getLocalModule(this.state, param.string)) {
dep = new LocalModuleDependency(localModule, param.range);
} else {
dep = new AMDRequireItemDependency(param.string, param.range);
}
dep.loc = expr.loc;
dep.optional = !!this.scope.inTry;
this.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call define:amd:context", function(expr, param) {
var dep = ContextDependencyHelpers.create(AMDRequireContextDependency, param.range, param, expr, options);
if(!dep) return;
dep.loc = expr.loc;
dep.optional = !!this.scope.inTry;
this.state.current.addDependency(dep);
return true;
});
};