nav tabs on admin dashboard

This commit is contained in:
2019-03-07 00:20:34 -06:00
parent f73d6ae228
commit e4f473f376
11661 changed files with 216240 additions and 1544253 deletions
+21 -26
View File
@@ -13,6 +13,7 @@ class AMDDefineDependency extends NullDependency {
this.functionRange = functionRange;
this.objectRange = objectRange;
this.namedModule = namedModule;
this.localModule = null;
}
get type() {
@@ -28,10 +29,7 @@ AMDDefineDependency.Template = class AMDDefineDependencyTemplate {
`!(__WEBPACK_AMD_DEFINE_RESULT__ = (#).call(exports, __webpack_require__, exports, module),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))`
],
o: [
"",
"!(module.exports = #)"
],
o: ["", "!(module.exports = #)"],
of: [
"var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;",
`!(__WEBPACK_AMD_DEFINE_FACTORY__ = (#),
@@ -45,10 +43,7 @@ AMDDefineDependency.Template = class AMDDefineDependencyTemplate {
`!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_RESULT__ = (#).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))`
],
ao: [
"",
"!(#, module.exports = #)"
],
ao: ["", "!(#, module.exports = #)"],
aof: [
"var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;",
`!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_FACTORY__ = (#),
@@ -60,10 +55,7 @@ AMDDefineDependency.Template = class AMDDefineDependencyTemplate {
"var XXX, XXXmodule;",
"!(XXXmodule = { id: YYY, exports: {}, loaded: false }, XXX = #.call(XXXmodule.exports, __webpack_require__, XXXmodule.exports, XXXmodule), XXXmodule.loaded = true, XXX === undefined && (XXX = XXXmodule.exports))"
],
lo: [
"var XXX;",
"!(XXX = #)"
],
lo: ["var XXX;", "!(XXX = #)"],
lof: [
"var XXX, XXXfactory, XXXmodule;",
"!(XXXfactory = (#), (XXXmodule = { id: YYY, exports: {}, loaded: false }), XXX = (typeof XXXfactory === 'function' ? (XXXfactory.call(XXXmodule.exports, __webpack_require__, XXXmodule.exports, XXXmodule)) : XXXfactory), (XXXmodule.loaded = true), XXX === undefined && (XXX = XXXmodule.exports))"
@@ -72,10 +64,7 @@ AMDDefineDependency.Template = class AMDDefineDependencyTemplate {
"var __WEBPACK_AMD_DEFINE_ARRAY__, XXX;",
"!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, XXX = ((#).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)))"
],
lao: [
"var XXX;",
"!(#, XXX = #)"
],
lao: ["var XXX;", "!(#, XXX = #)"],
laof: [
"var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_FACTORY__, XXX;",
`!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_FACTORY__ = (#),
@@ -94,7 +83,11 @@ AMDDefineDependency.Template = class AMDDefineDependencyTemplate {
}
localModuleVar(dependency) {
return dependency.localModule && dependency.localModule.used && dependency.localModule.variableName();
return (
dependency.localModule &&
dependency.localModule.used &&
dependency.localModule.variableName()
);
}
branch(dependency) {
@@ -107,35 +100,37 @@ AMDDefineDependency.Template = class AMDDefineDependencyTemplate {
replace(dependency, source, definition, text) {
const localModuleVar = this.localModuleVar(dependency);
if(localModuleVar) {
if (localModuleVar) {
text = text.replace(/XXX/g, localModuleVar.replace(/\$/g, "$$$$"));
definition = definition.replace(/XXX/g, localModuleVar.replace(/\$/g, "$$$$"));
definition = definition.replace(
/XXX/g,
localModuleVar.replace(/\$/g, "$$$$")
);
}
if(dependency.namedModule) {
if (dependency.namedModule) {
text = text.replace(/YYY/g, JSON.stringify(dependency.namedModule));
}
const texts = text.split("#");
if(definition) source.insert(0, definition);
if (definition) source.insert(0, definition);
let current = dependency.range[0];
if(dependency.arrayRange) {
if (dependency.arrayRange) {
source.replace(current, dependency.arrayRange[0] - 1, texts.shift());
current = dependency.arrayRange[1];
}
if(dependency.objectRange) {
if (dependency.objectRange) {
source.replace(current, dependency.objectRange[0] - 1, texts.shift());
current = dependency.objectRange[1];
} else if(dependency.functionRange) {
} else if (dependency.functionRange) {
source.replace(current, dependency.functionRange[0] - 1, texts.shift());
current = dependency.functionRange[1];
}
source.replace(current, dependency.range[1] - 1, texts.shift());
if(texts.length > 0)
throw new Error("Implementation error");
if (texts.length > 0) throw new Error("Implementation error");
}
};
+297 -227
View File
@@ -13,254 +13,324 @@ const LocalModuleDependency = require("./LocalModuleDependency");
const ContextDependencyHelpers = require("./ContextDependencyHelpers");
const 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;
const 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 isUnboundFunctionExpression(expr) {
if(expr.type === "FunctionExpression") return true;
if(expr.type === "ArrowFunctionExpression") return true;
const isUnboundFunctionExpression = expr => {
if (expr.type === "FunctionExpression") return true;
if (expr.type === "ArrowFunctionExpression") return true;
return false;
}
};
function isCallable(expr) {
if(isUnboundFunctionExpression(expr)) return true;
if(isBoundFunctionExpression(expr)) return true;
const isCallable = expr => {
if (isUnboundFunctionExpression(expr)) return true;
if (isBoundFunctionExpression(expr)) return true;
return false;
}
};
class AMDDefineDependencyParserPlugin {
constructor(options) {
this.options = options;
}
newDefineDependency(range, arrayRange, functionRange, objectRange, namedModule) {
return new AMDDefineDependency(range, arrayRange, functionRange, objectRange, namedModule);
apply(parser) {
parser.hooks.call
.for("define")
.tap(
"AMDDefineDependencyParserPlugin",
this.processCallDefine.bind(this, parser)
);
}
apply(parser) {
const options = this.options;
parser.plugin("call define", (expr) => {
let array, fn, obj, namedModule;
switch(expr.arguments.length) {
case 1:
if(isCallable(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(isCallable(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(isCallable(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(isCallable(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;
}
let fnParams = null;
let fnParamsOffset = 0;
if(fn) {
if(isUnboundFunctionExpression(fn)) fnParams = fn.params;
else if(isBoundFunctionExpression(fn)) {
fnParams = fn.callee.object.params;
fnParamsOffset = fn.arguments.length - 1;
if(fnParamsOffset < 0) fnParamsOffset = 0;
processArray(parser, expr, param, identifiers, namedModule) {
if (param.isArray()) {
param.items.forEach((param, idx) => {
if (
param.isString() &&
["require", "module", "exports"].includes(param.string)
)
identifiers[idx] = param.string;
const result = this.processItem(parser, expr, param, namedModule);
if (result === undefined) {
this.processContext(parser, expr, param);
}
}
let fnRenames = Object.create(parser.scope.renames);
let identifiers;
if(array) {
identifiers = {};
const param = parser.evaluateExpression(array);
const result = parser.applyPluginsBailResult("call define:amd:array", expr, param, identifiers, namedModule);
if(!result) return;
if(fnParams) fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
if(identifiers[idx]) {
fnRenames["$" + param.name] = identifiers[idx];
return false;
}
return true;
});
} else {
identifiers = ["require", "exports", "module"];
if(fnParams) fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
if(identifiers[idx]) {
fnRenames["$" + param.name] = identifiers[idx];
return false;
}
return true;
});
}
let inTry;
if(fn && isUnboundFunctionExpression(fn)) {
inTry = parser.scope.inTry;
parser.inScope(fnParams, () => {
parser.scope.renames = fnRenames;
parser.scope.inTry = inTry;
if(fn.body.type === "BlockStatement")
parser.walkStatement(fn.body);
else
parser.walkExpression(fn.body);
});
} else if(fn && isBoundFunctionExpression(fn)) {
inTry = parser.scope.inTry;
parser.inScope(fn.callee.object.params.filter((i) => ["require", "module", "exports"].indexOf(i.name) < 0), () => {
parser.scope.renames = fnRenames;
parser.scope.inTry = inTry;
if(fn.callee.object.body.type === "BlockStatement")
parser.walkStatement(fn.callee.object.body);
else
parser.walkExpression(fn.callee.object.body);
});
if(fn.arguments)
parser.walkExpressions(fn.arguments);
} else if(fn || obj) {
parser.walkExpression(fn || obj);
}
const dep = this.newDefineDependency(
expr.range,
array ? array.range : null,
fn ? fn.range : null,
obj ? obj.range : null,
namedModule ? namedModule : null
);
dep.loc = expr.loc;
if(namedModule) {
dep.localModule = LocalModulesHelpers.addLocalModule(parser.state, namedModule);
}
parser.state.current.addDependency(dep);
});
return true;
});
parser.plugin("call define:amd:array", (expr, param, identifiers, namedModule) => {
if(param.isArray()) {
param.items.forEach((param, idx) => {
if(param.isString() && ["require", "module", "exports"].indexOf(param.string) >= 0)
identifiers[idx] = param.string;
const result = parser.applyPluginsBailResult("call define:amd:item", expr, param, namedModule);
if(result === undefined) {
parser.applyPluginsBailResult("call define:amd:context", expr, param);
}
});
return true;
} else if(param.isConstArray()) {
const deps = [];
param.array.forEach((request, idx) => {
let dep;
let 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(parser.state, request)) { // eslint-disable-line no-cond-assign
dep = new LocalModuleDependency(localModule);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
} else {
dep = new AMDRequireItemDependency(request);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
}
deps.push(dep);
});
const dep = new AMDRequireArrayDependency(deps, param.range);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call define:amd:item", (expr, param, namedModule) => {
if(param.isConditional()) {
param.options.forEach((param) => {
const result = parser.applyPluginsBailResult("call define:amd:item", expr, param);
if(result === undefined) {
parser.applyPluginsBailResult("call define:amd:context", expr, param);
}
});
return true;
} else if(param.isString()) {
let 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(parser.state, param.string, namedModule)) { // eslint-disable-line no-cond-assign
dep = new LocalModuleDependency(localModule, param.range);
} else if (param.isConstArray()) {
const deps = [];
param.array.forEach((request, idx) => {
let dep;
let localModule;
if (request === "require") {
identifiers[idx] = request;
dep = "__webpack_require__";
} else if (["exports", "module"].includes(request)) {
identifiers[idx] = request;
dep = request;
} else if (
(localModule = LocalModulesHelpers.getLocalModule(
parser.state,
request
))
) {
dep = new LocalModuleDependency(localModule, undefined, false);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
} else {
dep = new AMDRequireItemDependency(param.string, param.range);
dep = this.newRequireItemDependency(request);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
}
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call define:amd:context", (expr, param) => {
const dep = ContextDependencyHelpers.create(AMDRequireContextDependency, param.range, param, expr, options);
if(!dep) return;
deps.push(dep);
});
const dep = this.newRequireArrayDependency(deps, param.range);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
});
}
}
processItem(parser, expr, param, namedModule) {
if (param.isConditional()) {
param.options.forEach(param => {
const result = this.processItem(parser, expr, param);
if (result === undefined) {
this.processContext(parser, expr, param);
}
});
return true;
} else if (param.isString()) {
let dep, localModule;
if (param.string === "require") {
dep = new ConstDependency("__webpack_require__", param.range);
} else if (["require", "exports", "module"].includes(param.string)) {
dep = new ConstDependency(param.string, param.range);
} else if (
(localModule = LocalModulesHelpers.getLocalModule(
parser.state,
param.string,
namedModule
))
) {
dep = new LocalModuleDependency(localModule, param.range, false);
} else {
dep = this.newRequireItemDependency(param.string, param.range);
}
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
}
processContext(parser, expr, param) {
const dep = ContextDependencyHelpers.create(
AMDRequireContextDependency,
param.range,
param,
expr,
this.options,
{},
parser
);
if (!dep) return;
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
processCallDefine(parser, expr) {
let array, fn, obj, namedModule;
switch (expr.arguments.length) {
case 1:
if (isCallable(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 (isCallable(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 (isCallable(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 (isCallable(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;
}
let fnParams = null;
let fnParamsOffset = 0;
if (fn) {
if (isUnboundFunctionExpression(fn)) {
fnParams = fn.params;
} else if (isBoundFunctionExpression(fn)) {
fnParams = fn.callee.object.params;
fnParamsOffset = fn.arguments.length - 1;
if (fnParamsOffset < 0) {
fnParamsOffset = 0;
}
}
}
let fnRenames = parser.scope.renames.createChild();
if (array) {
const identifiers = {};
const param = parser.evaluateExpression(array);
const result = this.processArray(
parser,
expr,
param,
identifiers,
namedModule
);
if (!result) return;
if (fnParams) {
fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
if (identifiers[idx]) {
fnRenames.set(param.name, identifiers[idx]);
return false;
}
return true;
});
}
} else {
const identifiers = ["require", "exports", "module"];
if (fnParams) {
fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
if (identifiers[idx]) {
fnRenames.set(param.name, identifiers[idx]);
return false;
}
return true;
});
}
}
let inTry;
if (fn && isUnboundFunctionExpression(fn)) {
inTry = parser.scope.inTry;
parser.inScope(fnParams, () => {
parser.scope.renames = fnRenames;
parser.scope.inTry = inTry;
if (fn.body.type === "BlockStatement") {
parser.walkStatement(fn.body);
} else {
parser.walkExpression(fn.body);
}
});
} else if (fn && isBoundFunctionExpression(fn)) {
inTry = parser.scope.inTry;
parser.inScope(
fn.callee.object.params.filter(
i => !["require", "module", "exports"].includes(i.name)
),
() => {
parser.scope.renames = fnRenames;
parser.scope.inTry = inTry;
if (fn.callee.object.body.type === "BlockStatement") {
parser.walkStatement(fn.callee.object.body);
} else {
parser.walkExpression(fn.callee.object.body);
}
}
);
if (fn.arguments) {
parser.walkExpressions(fn.arguments);
}
} else if (fn || obj) {
parser.walkExpression(fn || obj);
}
const dep = this.newDefineDependency(
expr.range,
array ? array.range : null,
fn ? fn.range : null,
obj ? obj.range : null,
namedModule ? namedModule : null
);
dep.loc = expr.loc;
if (namedModule) {
dep.localModule = LocalModulesHelpers.addLocalModule(
parser.state,
namedModule
);
}
parser.state.current.addDependency(dep);
return true;
}
newDefineDependency(
range,
arrayRange,
functionRange,
objectRange,
namedModule
) {
return new AMDDefineDependency(
range,
arrayRange,
functionRange,
objectRange,
namedModule
);
}
newRequireArrayDependency(depsArray, range) {
return new AMDRequireArrayDependency(depsArray, range);
}
newRequireItemDependency(request, range) {
return new AMDRequireItemDependency(request, range);
}
}
module.exports = AMDDefineDependencyParserPlugin;
+197 -67
View File
@@ -31,88 +31,218 @@ class AMDPlugin {
apply(compiler) {
const options = this.options;
const amdOptions = this.amdOptions;
compiler.plugin("compilation", (compilation, params) => {
const normalModuleFactory = params.normalModuleFactory;
const contextModuleFactory = params.contextModuleFactory;
compiler.hooks.compilation.tap(
"AMDPlugin",
(compilation, { contextModuleFactory, normalModuleFactory }) => {
compilation.dependencyFactories.set(
AMDRequireDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
AMDRequireDependency,
new AMDRequireDependency.Template()
);
compilation.dependencyFactories.set(AMDRequireDependency, new NullFactory());
compilation.dependencyTemplates.set(AMDRequireDependency, new AMDRequireDependency.Template());
compilation.dependencyFactories.set(
AMDRequireItemDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
AMDRequireItemDependency,
new AMDRequireItemDependency.Template()
);
compilation.dependencyFactories.set(AMDRequireItemDependency, normalModuleFactory);
compilation.dependencyTemplates.set(AMDRequireItemDependency, new AMDRequireItemDependency.Template());
compilation.dependencyFactories.set(
AMDRequireArrayDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
AMDRequireArrayDependency,
new AMDRequireArrayDependency.Template()
);
compilation.dependencyFactories.set(AMDRequireArrayDependency, new NullFactory());
compilation.dependencyTemplates.set(AMDRequireArrayDependency, new AMDRequireArrayDependency.Template());
compilation.dependencyFactories.set(
AMDRequireContextDependency,
contextModuleFactory
);
compilation.dependencyTemplates.set(
AMDRequireContextDependency,
new AMDRequireContextDependency.Template()
);
compilation.dependencyFactories.set(AMDRequireContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(AMDRequireContextDependency, new AMDRequireContextDependency.Template());
compilation.dependencyFactories.set(
AMDDefineDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
AMDDefineDependency,
new AMDDefineDependency.Template()
);
compilation.dependencyFactories.set(AMDDefineDependency, new NullFactory());
compilation.dependencyTemplates.set(AMDDefineDependency, new AMDDefineDependency.Template());
compilation.dependencyFactories.set(
UnsupportedDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
UnsupportedDependency,
new UnsupportedDependency.Template()
);
compilation.dependencyFactories.set(UnsupportedDependency, new NullFactory());
compilation.dependencyTemplates.set(UnsupportedDependency, new UnsupportedDependency.Template());
compilation.dependencyFactories.set(
LocalModuleDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
LocalModuleDependency,
new LocalModuleDependency.Template()
);
compilation.dependencyFactories.set(LocalModuleDependency, new NullFactory());
compilation.dependencyTemplates.set(LocalModuleDependency, new LocalModuleDependency.Template());
const handler = (parser, parserOptions) => {
if (parserOptions.amd !== undefined && !parserOptions.amd) return;
params.normalModuleFactory.plugin("parser", (parser, parserOptions) => {
const setExpressionToModule = (outerExpr, module) => {
parser.hooks.expression.for(outerExpr).tap("AMDPlugin", expr => {
const dep = new AMDRequireItemDependency(module, expr.range);
dep.userRequest = outerExpr;
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
});
};
if(typeof parserOptions.amd !== "undefined" && !parserOptions.amd)
return;
new AMDRequireDependenciesBlockParserPlugin(options).apply(parser);
new AMDDefineDependencyParserPlugin(options).apply(parser);
function setExpressionToModule(outerExpr, module) {
parser.plugin("expression " + outerExpr, (expr) => {
const dep = new AMDRequireItemDependency(module, expr.range);
dep.userRequest = outerExpr;
setExpressionToModule("require.amd", "!!webpack amd options");
setExpressionToModule("define.amd", "!!webpack amd options");
setExpressionToModule("define", "!!webpack amd define");
parser.hooks.expression
.for("__webpack_amd_options__")
.tap("AMDPlugin", () =>
parser.state.current.addVariable(
"__webpack_amd_options__",
JSON.stringify(amdOptions)
)
);
parser.hooks.evaluateTypeof
.for("define.amd")
.tap(
"AMDPlugin",
ParserHelpers.evaluateToString(typeof amdOptions)
);
parser.hooks.evaluateTypeof
.for("require.amd")
.tap(
"AMDPlugin",
ParserHelpers.evaluateToString(typeof amdOptions)
);
parser.hooks.evaluateIdentifier
.for("define.amd")
.tap(
"AMDPlugin",
ParserHelpers.evaluateToIdentifier("define.amd", true)
);
parser.hooks.evaluateIdentifier
.for("require.amd")
.tap(
"AMDPlugin",
ParserHelpers.evaluateToIdentifier("require.amd", true)
);
parser.hooks.typeof
.for("define")
.tap(
"AMDPlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("function")
)
);
parser.hooks.evaluateTypeof
.for("define")
.tap("AMDPlugin", ParserHelpers.evaluateToString("function"));
parser.hooks.canRename
.for("define")
.tap("AMDPlugin", ParserHelpers.approve);
parser.hooks.rename.for("define").tap("AMDPlugin", expr => {
const dep = new AMDRequireItemDependency(
"!!webpack amd define",
expr.range
);
dep.userRequest = "define";
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
return false;
});
}
parser.hooks.typeof
.for("require")
.tap(
"AMDPlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("function")
)
);
parser.hooks.evaluateTypeof
.for("require")
.tap("AMDPlugin", ParserHelpers.evaluateToString("function"));
};
parser.apply(
new AMDRequireDependenciesBlockParserPlugin(options),
new AMDDefineDependencyParserPlugin(options)
);
setExpressionToModule("require.amd", "!!webpack amd options");
setExpressionToModule("define.amd", "!!webpack amd options");
setExpressionToModule("define", "!!webpack amd define");
parser.plugin("expression __webpack_amd_options__", () =>
parser.state.current.addVariable("__webpack_amd_options__", JSON.stringify(amdOptions)));
parser.plugin("evaluate typeof define.amd", ParserHelpers.evaluateToString(typeof amdOptions));
parser.plugin("evaluate typeof require.amd", ParserHelpers.evaluateToString(typeof amdOptions));
parser.plugin("evaluate Identifier define.amd", ParserHelpers.evaluateToIdentifier("define.amd", true));
parser.plugin("evaluate Identifier require.amd", ParserHelpers.evaluateToIdentifier("require.amd", true));
parser.plugin("typeof define", ParserHelpers.toConstantDependency(JSON.stringify("function")));
parser.plugin("evaluate typeof define", ParserHelpers.evaluateToString("function"));
parser.plugin("can-rename define", ParserHelpers.approve);
parser.plugin("rename define", (expr) => {
const dep = new AMDRequireItemDependency("!!webpack amd define", expr.range);
dep.userRequest = "define";
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return false;
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("AMDPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("AMDPlugin", handler);
}
);
compiler.hooks.afterResolvers.tap("AMDPlugin", () => {
compiler.resolverFactory.hooks.resolver
.for("normal")
.tap("AMDPlugin", resolver => {
new AliasPlugin(
"described-resolve",
{
name: "amdefine",
alias: path.join(
__dirname,
"..",
"..",
"buildin",
"amd-define.js"
)
},
"resolve"
).apply(resolver);
new AliasPlugin(
"described-resolve",
{
name: "webpack amd options",
alias: path.join(
__dirname,
"..",
"..",
"buildin",
"amd-options.js"
)
},
"resolve"
).apply(resolver);
new AliasPlugin(
"described-resolve",
{
name: "webpack amd define",
alias: path.join(
__dirname,
"..",
"..",
"buildin",
"amd-define.js"
)
},
"resolve"
).apply(resolver);
});
parser.plugin("typeof require", ParserHelpers.toConstantDependency(JSON.stringify("function")));
parser.plugin("evaluate typeof require", ParserHelpers.evaluateToString("function"));
});
});
compiler.plugin("after-resolvers", () => {
compiler.resolvers.normal.apply(
new AliasPlugin("described-resolve", {
name: "amdefine",
alias: path.join(__dirname, "..", "..", "buildin", "amd-define.js")
}, "resolve"),
new AliasPlugin("described-resolve", {
name: "webpack amd options",
alias: path.join(__dirname, "..", "..", "buildin", "amd-options.js")
}, "resolve"),
new AliasPlugin("described-resolve", {
name: "webpack amd define",
alias: path.join(__dirname, "..", "..", "buildin", "amd-define.js")
}, "resolve")
);
});
}
}
+13 -22
View File
@@ -4,7 +4,6 @@
*/
"use strict";
const Dependency = require("../Dependency");
const webpackMissingModuleModule = require("./WebpackMissingModule").module;
class AMDRequireArrayDependency extends Dependency {
constructor(depsArray, range) {
@@ -19,39 +18,31 @@ class AMDRequireArrayDependency extends Dependency {
}
AMDRequireArrayDependency.Template = class AMDRequireArrayDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
const content = this.getContent(dep, outputOptions, requestShortener);
apply(dep, source, runtime) {
const content = this.getContent(dep, runtime);
source.replace(dep.range[0], dep.range[1] - 1, content);
}
getContent(dep, outputOptions, requestShortener) {
const requires = dep.depsArray.map((dependency) => {
const optionalComment = this.optionalComment(outputOptions.pathinfo, requestShortener.shorten(dependency.request));
return this.contentForDependency(dependency, optionalComment);
getContent(dep, runtime) {
const requires = dep.depsArray.map(dependency => {
return this.contentForDependency(dependency, runtime);
});
return `[${requires.join(", ")}]`;
}
optionalComment(pathInfo, shortenedRequest) {
if(!pathInfo) {
return "";
}
return `/*! ${shortenedRequest} */ `;
}
contentForDependency(dep, comment) {
if(typeof dep === "string") {
contentForDependency(dep, runtime) {
if (typeof dep === "string") {
return dep;
}
if(dep.module) {
const stringifiedId = JSON.stringify(dep.module.id);
return `__webpack_require__(${comment}${stringifiedId})`;
} else if(dep.localModule) {
if (dep.localModule) {
return dep.localModule.variableName();
} else {
return runtime.moduleExports({
module: dep.module,
request: dep.request
});
}
return webpackMissingModuleModule(dep.request);
}
};
+2 -2
View File
@@ -6,8 +6,8 @@
const ContextDependency = require("./ContextDependency");
class AMDRequireContextDependency extends ContextDependency {
constructor(request, recursive, regExp, range, valueRange) {
super(request, recursive, regExp);
constructor(options, range, valueRange) {
super(options);
this.range = range;
this.valueRange = valueRange;
}
+21 -7
View File
@@ -7,27 +7,41 @@ const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
const AMDRequireDependency = require("./AMDRequireDependency");
module.exports = class AMDRequireDependenciesBlock extends AsyncDependenciesBlock {
constructor(expr, arrayRange, functionRange, errorCallbackRange, module, loc) {
super(null, module, loc);
constructor(
expr,
arrayRange,
functionRange,
errorCallbackRange,
module,
loc,
request
) {
super(null, module, loc, request);
this.expr = expr;
this.outerRange = expr.range;
this.arrayRange = arrayRange;
this.functionBindThis = false;
this.functionRange = functionRange;
this.errorCallbackBindThis = false;
this.errorCallbackRange = errorCallbackRange;
this.bindThis = true;
if(arrayRange && functionRange && errorCallbackRange) {
if (arrayRange && functionRange && errorCallbackRange) {
this.range = [arrayRange[0], errorCallbackRange[1]];
} else if(arrayRange && functionRange) {
} else if (arrayRange && functionRange) {
this.range = [arrayRange[0], functionRange[1]];
} else if(arrayRange) {
} else if (arrayRange) {
this.range = arrayRange;
} else if(functionRange) {
} else if (functionRange) {
this.range = functionRange;
} else {
this.range = expr.range;
}
const dep = new AMDRequireDependency(this);
const dep = this.newRequireDependency();
dep.loc = loc;
this.addDependency(dep);
}
newRequireDependency() {
return new AMDRequireDependency(this);
}
};
@@ -24,17 +24,21 @@ class AMDRequireDependenciesBlockParserPlugin {
processFunctionArgument(parser, expression) {
let bindThis = true;
const fnData = getFunctionExpression(expression);
if(fnData) {
parser.inScope(fnData.fn.params.filter((i) => {
return ["require", "module", "exports"].indexOf(i.name) < 0;
}), () => {
if(fnData.fn.body.type === "BlockStatement")
parser.walkStatement(fnData.fn.body);
else
parser.walkExpression(fnData.fn.body);
});
if (fnData) {
parser.inScope(
fnData.fn.params.filter(i => {
return !["require", "module", "exports"].includes(i.name);
}),
() => {
if (fnData.fn.body.type === "BlockStatement") {
parser.walkStatement(fnData.fn.body);
} else {
parser.walkExpression(fnData.fn.body);
}
}
);
parser.walkExpressions(fnData.expressions);
if(fnData.needThis === false) {
if (fnData.needThis === false) {
bindThis = false;
}
} else {
@@ -44,134 +48,227 @@ class AMDRequireDependenciesBlockParserPlugin {
}
apply(parser) {
const options = this.options;
parser.plugin("call require", (expr) => {
let param;
let dep;
let result;
parser.hooks.call
.for("require")
.tap(
"AMDRequireDependenciesBlockParserPlugin",
this.processCallRequire.bind(this, parser)
);
}
const old = parser.state.current;
if(expr.arguments.length >= 1) {
param = parser.evaluateExpression(expr.arguments[0]);
dep = new AMDRequireDependenciesBlock(
expr,
param.range,
(expr.arguments.length > 1) ? expr.arguments[1].range : null,
(expr.arguments.length > 2) ? expr.arguments[2].range : null,
parser.state.module,
expr.loc
);
parser.state.current = dep;
}
if(expr.arguments.length === 1) {
parser.inScope([], () => {
result = parser.applyPluginsBailResult("call require:amd:array", expr, param);
});
parser.state.current = old;
if(!result) return;
parser.state.current.addBlock(dep);
return true;
}
if(expr.arguments.length === 2 || expr.arguments.length === 3) {
try {
parser.inScope([], () => {
result = parser.applyPluginsBailResult("call require:amd:array", expr, param);
});
if(!result) {
dep = new UnsupportedDependency("unsupported", expr.range);
old.addDependency(dep);
if(parser.state.module)
parser.state.module.errors.push(new UnsupportedFeatureWarning(parser.state.module, "Cannot statically analyse 'require(..., ...)' in line " + expr.loc.start.line));
dep = null;
return true;
}
dep.functionBindThis = this.processFunctionArgument(parser, expr.arguments[1]);
if(expr.arguments.length === 3) {
dep.errorCallbackBindThis = this.processFunctionArgument(parser, expr.arguments[2]);
}
} finally {
parser.state.current = old;
if(dep)
parser.state.current.addBlock(dep);
processArray(parser, expr, param) {
if (param.isArray()) {
for (const p of param.items) {
const result = this.processItem(parser, expr, p);
if (result === undefined) {
this.processContext(parser, expr, p);
}
return true;
}
});
parser.plugin("call require:amd:array", (expr, param) => {
if(param.isArray()) {
param.items.forEach((param) => {
const result = parser.applyPluginsBailResult("call require:amd:item", expr, param);
if(result === undefined) {
parser.applyPluginsBailResult("call require:amd:context", expr, param);
}
});
return true;
} else if(param.isConstArray()) {
const deps = [];
param.array.forEach((request) => {
let dep, localModule;
if(request === "require") {
dep = "__webpack_require__";
} else if(["exports", "module"].indexOf(request) >= 0) {
dep = request;
} else if(localModule = LocalModulesHelpers.getLocalModule(parser.state, request)) { // eslint-disable-line no-cond-assign
dep = new LocalModuleDependency(localModule);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
} else {
dep = new AMDRequireItemDependency(request);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
}
deps.push(dep);
});
const dep = new AMDRequireArrayDependency(deps, param.range);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call require:amd:item", (expr, param) => {
if(param.isConditional()) {
param.options.forEach((param) => {
const result = parser.applyPluginsBailResult("call require:amd:item", expr, param);
if(result === undefined) {
parser.applyPluginsBailResult("call require:amd:context", expr, param);
}
});
return true;
} else if(param.isString()) {
return true;
} else if (param.isConstArray()) {
const deps = [];
for (const request of param.array) {
let dep, localModule;
if(param.string === "require") {
dep = new ConstDependency("__webpack_require__", param.string);
} else if(param.string === "module") {
dep = new ConstDependency(parser.state.module.moduleArgument || "module", param.range);
} else if(param.string === "exports") {
dep = new ConstDependency(parser.state.module.exportsArgument || "exports", param.range);
} else if(localModule = LocalModulesHelpers.getLocalModule(parser.state, param.string)) { // eslint-disable-line no-cond-assign
dep = new LocalModuleDependency(localModule, param.range);
if (request === "require") {
dep = "__webpack_require__";
} else if (["exports", "module"].includes(request)) {
dep = request;
} else if (
(localModule = LocalModulesHelpers.getLocalModule(
parser.state,
request
))
) {
dep = new LocalModuleDependency(localModule, undefined, false);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
} else {
dep = new AMDRequireItemDependency(param.string, param.range);
dep = this.newRequireItemDependency(request);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
}
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
deps.push(dep);
}
});
parser.plugin("call require:amd:context", (expr, param) => {
const dep = ContextDependencyHelpers.create(AMDRequireContextDependency, param.range, param, expr, options);
if(!dep) return;
const dep = this.newRequireArrayDependency(deps, param.range);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
});
}
}
processItem(parser, expr, param) {
if (param.isConditional()) {
for (const p of param.options) {
const result = this.processItem(parser, expr, p);
if (result === undefined) {
this.processContext(parser, expr, p);
}
}
return true;
} else if (param.isString()) {
let dep, localModule;
if (param.string === "require") {
dep = new ConstDependency("__webpack_require__", param.string);
} else if (param.string === "module") {
dep = new ConstDependency(
parser.state.module.buildInfo.moduleArgument,
param.range
);
} else if (param.string === "exports") {
dep = new ConstDependency(
parser.state.module.buildInfo.exportsArgument,
param.range
);
} else if (
(localModule = LocalModulesHelpers.getLocalModule(
parser.state,
param.string
))
) {
dep = new LocalModuleDependency(localModule, param.range, false);
} else {
dep = this.newRequireItemDependency(param.string, param.range);
}
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
}
processContext(parser, expr, param) {
const dep = ContextDependencyHelpers.create(
AMDRequireContextDependency,
param.range,
param,
expr,
this.options,
{},
parser
);
if (!dep) return;
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
processArrayForRequestString(param) {
if (param.isArray()) {
const result = param.items.map(item =>
this.processItemForRequestString(item)
);
if (result.every(Boolean)) return result.join(" ");
} else if (param.isConstArray()) {
return param.array.join(" ");
}
}
processItemForRequestString(param) {
if (param.isConditional()) {
const result = param.options.map(item =>
this.processItemForRequestString(item)
);
if (result.every(Boolean)) return result.join("|");
} else if (param.isString()) {
return param.string;
}
}
processCallRequire(parser, expr) {
let param;
let dep;
let result;
const old = parser.state.current;
if (expr.arguments.length >= 1) {
param = parser.evaluateExpression(expr.arguments[0]);
dep = this.newRequireDependenciesBlock(
expr,
param.range,
expr.arguments.length > 1 ? expr.arguments[1].range : null,
expr.arguments.length > 2 ? expr.arguments[2].range : null,
parser.state.module,
expr.loc,
this.processArrayForRequestString(param)
);
parser.state.current = dep;
}
if (expr.arguments.length === 1) {
parser.inScope([], () => {
result = this.processArray(parser, expr, param);
});
parser.state.current = old;
if (!result) return;
parser.state.current.addBlock(dep);
return true;
}
if (expr.arguments.length === 2 || expr.arguments.length === 3) {
try {
parser.inScope([], () => {
result = this.processArray(parser, expr, param);
});
if (!result) {
dep = new UnsupportedDependency("unsupported", expr.range);
old.addDependency(dep);
if (parser.state.module) {
parser.state.module.errors.push(
new UnsupportedFeatureWarning(
parser.state.module,
"Cannot statically analyse 'require(…, …)' in line " +
expr.loc.start.line,
expr.loc
)
);
}
dep = null;
return true;
}
dep.functionBindThis = this.processFunctionArgument(
parser,
expr.arguments[1]
);
if (expr.arguments.length === 3) {
dep.errorCallbackBindThis = this.processFunctionArgument(
parser,
expr.arguments[2]
);
}
} finally {
parser.state.current = old;
if (dep) parser.state.current.addBlock(dep);
}
return true;
}
}
newRequireDependenciesBlock(
expr,
arrayRange,
functionRange,
errorCallbackRange,
module,
loc,
request
) {
return new AMDRequireDependenciesBlock(
expr,
arrayRange,
functionRange,
errorCallbackRange,
module,
loc,
request
);
}
newRequireItemDependency(request, range) {
return new AMDRequireItemDependency(request, range);
}
newRequireArrayDependency(depsArray, range) {
return new AMDRequireArrayDependency(depsArray, range);
}
}
module.exports = AMDRequireDependenciesBlockParserPlugin;
+99 -31
View File
@@ -4,7 +4,6 @@
*/
"use strict";
const NullDependency = require("./NullDependency");
const DepBlockHelpers = require("./DepBlockHelpers");
class AMDRequireDependency extends NullDependency {
constructor(block) {
@@ -14,52 +13,121 @@ class AMDRequireDependency extends NullDependency {
}
AMDRequireDependency.Template = class AMDRequireDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
apply(dep, source, runtime) {
const depBlock = dep.block;
const wrapper = DepBlockHelpers.getLoadDepBlockWrapper(depBlock, outputOptions, requestShortener, "require");
const promise = runtime.blockPromise({
block: depBlock,
message: "AMD require"
});
// has array range but no function range
if(depBlock.arrayRange && !depBlock.functionRange) {
const startBlock = wrapper[0] + "function() {";
const endBlock = `;}${wrapper[1]}__webpack_require__.oe${wrapper[2]}`;
source.replace(depBlock.outerRange[0], depBlock.arrayRange[0] - 1, startBlock);
source.replace(depBlock.arrayRange[1], depBlock.outerRange[1] - 1, endBlock);
if (depBlock.arrayRange && !depBlock.functionRange) {
const startBlock = `${promise}.then(function() {`;
const endBlock = `;}).catch(${runtime.onError()})`;
source.replace(
depBlock.outerRange[0],
depBlock.arrayRange[0] - 1,
startBlock
);
source.replace(
depBlock.arrayRange[1],
depBlock.outerRange[1] - 1,
endBlock
);
return;
}
// has function range but no array range
if(depBlock.functionRange && !depBlock.arrayRange) {
const startBlock = wrapper[0] + "function() {(";
const endBlock = `.call(exports, __webpack_require__, exports, module));}${wrapper[1]}__webpack_require__.oe${wrapper[2]}`;
source.replace(depBlock.outerRange[0], depBlock.functionRange[0] - 1, startBlock);
source.replace(depBlock.functionRange[1], depBlock.outerRange[1] - 1, endBlock);
if (depBlock.functionRange && !depBlock.arrayRange) {
const startBlock = `${promise}.then((`;
const endBlock = `).bind(exports, __webpack_require__, exports, module)).catch(${runtime.onError()})`;
source.replace(
depBlock.outerRange[0],
depBlock.functionRange[0] - 1,
startBlock
);
source.replace(
depBlock.functionRange[1],
depBlock.outerRange[1] - 1,
endBlock
);
return;
}
// has array range, function range, and errorCallbackRange
if(depBlock.arrayRange && depBlock.functionRange && depBlock.errorCallbackRange) {
const startBlock = wrapper[0] + "function() { ";
const errorRangeBlock = `}${depBlock.functionBindThis ? ".bind(this)" : ""}${wrapper[1]}`;
const endBlock = `${depBlock.errorCallbackBindThis ? ".bind(this)" : ""}${wrapper[2]}`;
if (
depBlock.arrayRange &&
depBlock.functionRange &&
depBlock.errorCallbackRange
) {
const startBlock = `${promise}.then(function() { `;
const errorRangeBlock = `}${
depBlock.functionBindThis ? ".bind(this)" : ""
}).catch(`;
const endBlock = `${
depBlock.errorCallbackBindThis ? ".bind(this)" : ""
})`;
source.replace(depBlock.outerRange[0], depBlock.arrayRange[0] - 1, startBlock);
source.insert(depBlock.arrayRange[0] + 0.9, "var __WEBPACK_AMD_REQUIRE_ARRAY__ = ");
source.replace(depBlock.arrayRange[1], depBlock.functionRange[0] - 1, "; ((");
source.insert(depBlock.functionRange[1], ").apply(null, __WEBPACK_AMD_REQUIRE_ARRAY__));");
source.replace(depBlock.functionRange[1], depBlock.errorCallbackRange[0] - 1, errorRangeBlock);
source.replace(depBlock.errorCallbackRange[1], depBlock.outerRange[1] - 1, endBlock);
source.replace(
depBlock.outerRange[0],
depBlock.arrayRange[0] - 1,
startBlock
);
source.insert(
depBlock.arrayRange[0] + 0.9,
"var __WEBPACK_AMD_REQUIRE_ARRAY__ = "
);
source.replace(
depBlock.arrayRange[1],
depBlock.functionRange[0] - 1,
"; ("
);
source.insert(
depBlock.functionRange[1],
").apply(null, __WEBPACK_AMD_REQUIRE_ARRAY__);"
);
source.replace(
depBlock.functionRange[1],
depBlock.errorCallbackRange[0] - 1,
errorRangeBlock
);
source.replace(
depBlock.errorCallbackRange[1],
depBlock.outerRange[1] - 1,
endBlock
);
return;
}
// has array range, function range, but no errorCallbackRange
if(depBlock.arrayRange && depBlock.functionRange) {
const startBlock = wrapper[0] + "function() { ";
const endBlock = `}${depBlock.functionBindThis ? ".bind(this)" : ""}${wrapper[1]}__webpack_require__.oe${wrapper[2]}`;
source.replace(depBlock.outerRange[0], depBlock.arrayRange[0] - 1, startBlock);
source.insert(depBlock.arrayRange[0] + 0.9, "var __WEBPACK_AMD_REQUIRE_ARRAY__ = ");
source.replace(depBlock.arrayRange[1], depBlock.functionRange[0] - 1, "; ((");
source.insert(depBlock.functionRange[1], ").apply(null, __WEBPACK_AMD_REQUIRE_ARRAY__));");
source.replace(depBlock.functionRange[1], depBlock.outerRange[1] - 1, endBlock);
if (depBlock.arrayRange && depBlock.functionRange) {
const startBlock = `${promise}.then(function() { `;
const endBlock = `}${
depBlock.functionBindThis ? ".bind(this)" : ""
}).catch(${runtime.onError()})`;
source.replace(
depBlock.outerRange[0],
depBlock.arrayRange[0] - 1,
startBlock
);
source.insert(
depBlock.arrayRange[0] + 0.9,
"var __WEBPACK_AMD_REQUIRE_ARRAY__ = "
);
source.replace(
depBlock.arrayRange[1],
depBlock.functionRange[0] - 1,
"; ("
);
source.insert(
depBlock.functionRange[1],
").apply(null, __WEBPACK_AMD_REQUIRE_ARRAY__);"
);
source.replace(
depBlock.functionRange[1],
depBlock.outerRange[1] - 1,
endBlock
);
}
}
};
+127 -58
View File
@@ -25,65 +25,134 @@ class CommonJsPlugin {
apply(compiler) {
const options = this.options;
compiler.plugin("compilation", (compilation, params) => {
const normalModuleFactory = params.normalModuleFactory;
const contextModuleFactory = params.contextModuleFactory;
compilation.dependencyFactories.set(CommonJsRequireDependency, normalModuleFactory);
compilation.dependencyTemplates.set(CommonJsRequireDependency, new CommonJsRequireDependency.Template());
compilation.dependencyFactories.set(CommonJsRequireContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(CommonJsRequireContextDependency, new CommonJsRequireContextDependency.Template());
compilation.dependencyFactories.set(RequireResolveDependency, normalModuleFactory);
compilation.dependencyTemplates.set(RequireResolveDependency, new RequireResolveDependency.Template());
compilation.dependencyFactories.set(RequireResolveContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(RequireResolveContextDependency, new RequireResolveContextDependency.Template());
compilation.dependencyFactories.set(RequireResolveHeaderDependency, new NullFactory());
compilation.dependencyTemplates.set(RequireResolveHeaderDependency, new RequireResolveHeaderDependency.Template());
compilation.dependencyFactories.set(RequireHeaderDependency, new NullFactory());
compilation.dependencyTemplates.set(RequireHeaderDependency, new RequireHeaderDependency.Template());
params.normalModuleFactory.plugin("parser", (parser, parserOptions) => {
if(typeof parserOptions.commonjs !== "undefined" && !parserOptions.commonjs)
return;
const requireExpressions = ["require", "require.resolve", "require.resolveWeak"];
for(let expression of requireExpressions) {
parser.plugin(`typeof ${expression}`, ParserHelpers.toConstantDependency(JSON.stringify("function")));
parser.plugin(`evaluate typeof ${expression}`, ParserHelpers.evaluateToString("function"));
parser.plugin(`evaluate Identifier ${expression}`, ParserHelpers.evaluateToIdentifier(expression, true));
}
parser.plugin("evaluate typeof module", ParserHelpers.evaluateToString("object"));
parser.plugin("assign require", (expr) => {
// to not leak to global "require", we need to define a local require here.
const dep = new ConstDependency("var require;", 0);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
parser.scope.definitions.push("require");
return true;
});
parser.plugin("can-rename require", () => true);
parser.plugin("rename require", (expr) => {
// define the require variable. It's still undefined, but not "not defined".
const dep = new ConstDependency("var require;", 0);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return false;
});
parser.plugin("typeof module", () => true);
parser.plugin("evaluate typeof exports", ParserHelpers.evaluateToString("object"));
parser.apply(
new CommonJsRequireDependencyParserPlugin(options),
new RequireResolveDependencyParserPlugin(options)
compiler.hooks.compilation.tap(
"CommonJsPlugin",
(compilation, { contextModuleFactory, normalModuleFactory }) => {
compilation.dependencyFactories.set(
CommonJsRequireDependency,
normalModuleFactory
);
});
});
compilation.dependencyTemplates.set(
CommonJsRequireDependency,
new CommonJsRequireDependency.Template()
);
compilation.dependencyFactories.set(
CommonJsRequireContextDependency,
contextModuleFactory
);
compilation.dependencyTemplates.set(
CommonJsRequireContextDependency,
new CommonJsRequireContextDependency.Template()
);
compilation.dependencyFactories.set(
RequireResolveDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
RequireResolveDependency,
new RequireResolveDependency.Template()
);
compilation.dependencyFactories.set(
RequireResolveContextDependency,
contextModuleFactory
);
compilation.dependencyTemplates.set(
RequireResolveContextDependency,
new RequireResolveContextDependency.Template()
);
compilation.dependencyFactories.set(
RequireResolveHeaderDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
RequireResolveHeaderDependency,
new RequireResolveHeaderDependency.Template()
);
compilation.dependencyFactories.set(
RequireHeaderDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
RequireHeaderDependency,
new RequireHeaderDependency.Template()
);
const handler = (parser, parserOptions) => {
if (parserOptions.commonjs !== undefined && !parserOptions.commonjs)
return;
const requireExpressions = [
"require",
"require.resolve",
"require.resolveWeak"
];
for (let expression of requireExpressions) {
parser.hooks.typeof
.for(expression)
.tap(
"CommonJsPlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("function")
)
);
parser.hooks.evaluateTypeof
.for(expression)
.tap(
"CommonJsPlugin",
ParserHelpers.evaluateToString("function")
);
parser.hooks.evaluateIdentifier
.for(expression)
.tap(
"CommonJsPlugin",
ParserHelpers.evaluateToIdentifier(expression, true)
);
}
parser.hooks.evaluateTypeof
.for("module")
.tap("CommonJsPlugin", ParserHelpers.evaluateToString("object"));
parser.hooks.assign.for("require").tap("CommonJsPlugin", expr => {
// to not leak to global "require", we need to define a local require here.
const dep = new ConstDependency("var require;", 0);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
parser.scope.definitions.add("require");
return true;
});
parser.hooks.canRename
.for("require")
.tap("CommonJsPlugin", () => true);
parser.hooks.rename.for("require").tap("CommonJsPlugin", expr => {
// define the require variable. It's still undefined, but not "not defined".
const dep = new ConstDependency("var require;", 0);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return false;
});
parser.hooks.typeof.for("module").tap("CommonJsPlugin", () => true);
parser.hooks.evaluateTypeof
.for("exports")
.tap("CommonJsPlugin", ParserHelpers.evaluateToString("object"));
new CommonJsRequireDependencyParserPlugin(options).apply(parser);
new RequireResolveDependencyParserPlugin(options).apply(parser);
};
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("CommonJsPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("CommonJsPlugin", handler);
}
);
}
}
module.exports = CommonJsPlugin;
+2 -3
View File
@@ -7,8 +7,8 @@ const ContextDependency = require("./ContextDependency");
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
class CommonJsRequireContextDependency extends ContextDependency {
constructor(request, recursive, regExp, range, valueRange) {
super(request, recursive, regExp);
constructor(options, range, valueRange) {
super(options);
this.range = range;
this.valueRange = valueRange;
}
@@ -16,7 +16,6 @@ class CommonJsRequireContextDependency extends ContextDependency {
get type() {
return "cjs require context";
}
}
CommonJsRequireContextDependency.Template = ContextDependencyTemplateAsRequireCall;
@@ -19,46 +19,100 @@ class CommonJsRequireDependencyParserPlugin {
apply(parser) {
const options = this.options;
parser.plugin("expression require.cache", ParserHelpers.toConstantDependency("__webpack_require__.c"));
parser.plugin("expression require", (expr) => {
const dep = new CommonJsRequireContextDependency(options.unknownContextRequest, options.unknownContextRecursive, options.unknownContextRegExp, expr.range);
dep.critical = options.unknownContextCritical && "require function is used in a way in which dependencies cannot be statically extracted";
const processItem = (expr, param) => {
if (param.isString()) {
const dep = new CommonJsRequireDependency(param.string, param.range);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
};
const processContext = (expr, param) => {
const dep = ContextDependencyHelpers.create(
CommonJsRequireContextDependency,
expr.range,
param,
expr,
options,
{},
parser
);
if (!dep) return;
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
});
parser.plugin("call require", (expr) => {
if(expr.arguments.length !== 1) return;
};
parser.hooks.expression
.for("require.cache")
.tap(
"CommonJsRequireDependencyParserPlugin",
ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
"__webpack_require__.c"
)
);
parser.hooks.expression
.for("require")
.tap("CommonJsRequireDependencyParserPlugin", expr => {
const dep = new CommonJsRequireContextDependency(
{
request: options.unknownContextRequest,
recursive: options.unknownContextRecursive,
regExp: options.unknownContextRegExp,
mode: "sync"
},
expr.range
);
dep.critical =
options.unknownContextCritical &&
"require function is used in a way in which dependencies cannot be statically extracted";
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
});
const createHandler = callNew => expr => {
if (expr.arguments.length !== 1) return;
let localModule;
const param = parser.evaluateExpression(expr.arguments[0]);
if(param.isConditional()) {
if (param.isConditional()) {
let isExpression = false;
const prevLength = parser.state.current.dependencies.length;
const dep = new RequireHeaderDependency(expr.callee.range);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
param.options.forEach(function(param) {
const result = parser.applyPluginsBailResult("call require:commonjs:item", expr, param);
if(result === undefined) {
for (const p of param.options) {
const result = processItem(expr, p);
if (result === undefined) {
isExpression = true;
}
});
if(isExpression) {
}
if (isExpression) {
parser.state.current.dependencies.length = prevLength;
} else {
return true;
}
}
if(param.isString() && (localModule = LocalModulesHelpers.getLocalModule(parser.state, param.string))) {
const dep = new LocalModuleDependency(localModule, expr.range);
if (
param.isString() &&
(localModule = LocalModulesHelpers.getLocalModule(
parser.state,
param.string
))
) {
const dep = new LocalModuleDependency(localModule, expr.range, callNew);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
} else {
const result = parser.applyPluginsBailResult("call require:commonjs:item", expr, param);
if(result === undefined) {
parser.applyPluginsBailResult("call require:commonjs:context", expr, param);
const result = processItem(expr, param);
if (result === undefined) {
processContext(expr, param);
} else {
const dep = new RequireHeaderDependency(expr.callee.range);
dep.loc = expr.loc;
@@ -66,24 +120,19 @@ class CommonJsRequireDependencyParserPlugin {
}
return true;
}
});
parser.plugin("call require:commonjs:item", (expr, param) => {
if(param.isString()) {
const dep = new CommonJsRequireDependency(param.string, param.range);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call require:commonjs:context", (expr, param) => {
const dep = ContextDependencyHelpers.create(CommonJsRequireContextDependency, expr.range, param, expr, options);
if(!dep) return;
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
});
};
parser.hooks.call
.for("require")
.tap("CommonJsRequireDependencyParserPlugin", createHandler(false));
parser.hooks.new
.for("require")
.tap("CommonJsRequireDependencyParserPlugin", createHandler(true));
parser.hooks.call
.for("module.require")
.tap("CommonJsRequireDependencyParserPlugin", createHandler(false));
parser.hooks.new
.for("module.require")
.tap("CommonJsRequireDependencyParserPlugin", createHandler(true));
}
}
module.exports = CommonJsRequireDependencyParserPlugin;
+3 -2
View File
@@ -6,10 +6,11 @@
const NullDependency = require("./NullDependency");
class ConstDependency extends NullDependency {
constructor(expression, range) {
constructor(expression, range, requireWebpackRequire) {
super();
this.expression = expression;
this.range = range;
this.requireWebpackRequire = requireWebpackRequire;
}
updateHash(hash) {
@@ -20,7 +21,7 @@ class ConstDependency extends NullDependency {
ConstDependency.Template = class ConstDependencyTemplate {
apply(dep, source) {
if(typeof dep.range === "number") {
if (typeof dep.range === "number") {
source.insert(dep.range, dep.expression);
return;
}
+42 -23
View File
@@ -6,44 +6,63 @@
const Dependency = require("../Dependency");
const CriticalDependencyWarning = require("./CriticalDependencyWarning");
class ContextDependency extends Dependency {
constructor(request, recursive, regExp) {
super();
this.request = request;
this.userRequest = request;
this.recursive = recursive;
this.regExp = regExp;
this.async = false;
const regExpToString = r => (r ? r + "" : "");
class ContextDependency extends Dependency {
// options: { request, recursive, regExp, include, exclude, mode, chunkName, groupOptions }
constructor(options) {
super();
this.options = options;
this.userRequest = this.options.request;
/** @type {false | string} */
this.critical = false;
this.hadGlobalOrStickyRegExp = false;
if(this.regExp.global || this.regExp.sticky) {
this.regExp = null;
if (this.options.regExp.global || this.options.regExp.sticky) {
this.options.regExp = null;
this.hadGlobalOrStickyRegExp = true;
}
}
isEqualResource(other) {
if(!(other instanceof ContextDependency))
return false;
return this.request === other.request &&
this.recursive === other.recursive &&
this.regExp === other.regExp &&
this.async === other.async;
getResourceIdentifier() {
return (
`context${this.options.request} ${this.options.recursive} ` +
`${regExpToString(this.options.regExp)} ${regExpToString(
this.options.include
)} ${regExpToString(this.options.exclude)} ` +
`${this.options.mode} ${this.options.chunkName} ` +
`${JSON.stringify(this.options.groupOptions)}`
);
}
getWarnings() {
let warnings = super.getWarnings() || [];
if(this.critical) {
if (this.critical) {
warnings.push(new CriticalDependencyWarning(this.critical));
}
if(this.hadGlobalOrStickyRegExp) {
warnings.push(new CriticalDependencyWarning("Contexts can't use RegExps with the 'g' or 'y' flags."));
if (this.hadGlobalOrStickyRegExp) {
warnings.push(
new CriticalDependencyWarning(
"Contexts can't use RegExps with the 'g' or 'y' flags."
)
);
}
return warnings;
}
}
// TODO remove in webpack 5
Object.defineProperty(ContextDependency.prototype, "async", {
configurable: false,
get() {
throw new Error(
"ContextDependency.async was removed. Use ContextDependency.options.mode instead."
);
},
set() {
throw new Error(
"ContextDependency.async was removed. Pass options.mode to constructor instead"
);
}
});
module.exports = ContextDependency;
+209 -48
View File
@@ -9,63 +9,224 @@ const ContextDependencyHelpers = exports;
/**
* Escapes regular expression metacharacters
* @param {string} str String to quote
* @return {string} Escaped string
* @returns {string} Escaped string
*/
function quotemeta(str) {
const quotemeta = str => {
return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
}
};
ContextDependencyHelpers.create = function(Dep, range, param, expr, options, chunkName) {
let dep;
let prefix;
let postfix;
let prefixRange;
let valueRange;
let idx;
let context;
let regExp;
if(param.isTemplateString()) {
prefix = param.quasis[0].string;
postfix = param.quasis.length > 1 ? param.quasis[param.quasis.length - 1].string : "";
prefixRange = [param.quasis[0].range[0], param.quasis[0].range[1]];
valueRange = param.range;
idx = prefix.lastIndexOf("/");
context = ".";
if(idx >= 0) {
context = prefix.substr(0, idx);
prefix = `.${prefix.substr(idx)}`;
}
// If there are more than two quasis, maybe the generated RegExp can be more precise?
regExp = new RegExp(`^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(postfix)}$`);
dep = new Dep(context, options.wrappedContextRecursive, regExp, range, valueRange, chunkName);
const splitContextFromPrefix = prefix => {
const idx = prefix.lastIndexOf("/");
let context = ".";
if (idx >= 0) {
context = prefix.substr(0, idx);
prefix = `.${prefix.substr(idx)}`;
}
return {
context,
prefix
};
};
const splitQueryFromPostfix = postfix => {
const idx = postfix.indexOf("?");
let query = "";
if (idx >= 0) {
query = postfix.substr(idx);
postfix = postfix.substr(0, idx);
}
return {
postfix,
query
};
};
ContextDependencyHelpers.create = (
Dep,
range,
param,
expr,
options,
contextOptions,
// when parser is not passed in, expressions won't be walked
parser = null
) => {
if (param.isTemplateString()) {
let prefixRaw = param.quasis[0].string;
let postfixRaw =
param.quasis.length > 1
? param.quasis[param.quasis.length - 1].string
: "";
const valueRange = param.range;
const { context, prefix } = splitContextFromPrefix(prefixRaw);
const { postfix, query } = splitQueryFromPostfix(postfixRaw);
// When there are more than two quasis, the generated RegExp can be more precise
// We join the quasis with the expression regexp
const innerQuasis = param.quasis.slice(1, param.quasis.length - 1);
const innerRegExp =
options.wrappedContextRegExp.source +
innerQuasis
.map(q => quotemeta(q.string) + options.wrappedContextRegExp.source)
.join("");
// Example: `./context/pre${e}inner${e}inner2${e}post?query`
// context: "./context"
// prefix: "./pre"
// innerQuasis: [BEE("inner"), BEE("inner2")]
// (BEE = BasicEvaluatedExpression)
// postfix: "post"
// query: "?query"
// regExp: /^\.\/pre.*inner.*inner2.*post$/
const regExp = new RegExp(
`^${quotemeta(prefix)}${innerRegExp}${quotemeta(postfix)}$`
);
const dep = new Dep(
Object.assign(
{
request: context + query,
recursive: options.wrappedContextRecursive,
regExp,
mode: "sync"
},
contextOptions
),
range,
valueRange
);
dep.loc = expr.loc;
dep.replaces = [{
range: prefixRange,
value: prefix
}];
dep.critical = options.wrappedContextCritical && "a part of the request of a dependency is an expression";
const replaces = [];
param.parts.forEach((part, i) => {
if (i % 2 === 0) {
// Quasis or merged quasi
let range = part.range;
let value = part.string;
if (param.templateStringKind === "cooked") {
value = JSON.stringify(value);
value = value.slice(1, value.length - 1);
}
if (i === 0) {
// prefix
value = prefix;
range = [param.range[0], part.range[1]];
value =
(param.templateStringKind === "cooked" ? "`" : "String.raw`") +
value;
} else if (i === param.parts.length - 1) {
// postfix
value = postfix;
range = [part.range[0], param.range[1]];
value = value + "`";
} else if (
part.expression &&
part.expression.type === "TemplateElement" &&
part.expression.value.raw === value
) {
// Shortcut when it's a single quasi and doesn't need to be replaced
return;
}
replaces.push({
range,
value
});
} else {
// Expression
if (parser) {
parser.walkExpression(part.expression);
}
}
});
dep.replaces = replaces;
dep.critical =
options.wrappedContextCritical &&
"a part of the request of a dependency is an expression";
return dep;
} else if(param.isWrapped() && (param.prefix && param.prefix.isString() || param.postfix && param.postfix.isString())) {
prefix = param.prefix && param.prefix.isString() ? param.prefix.string : "";
postfix = param.postfix && param.postfix.isString() ? param.postfix.string : "";
prefixRange = param.prefix && param.prefix.isString() ? param.prefix.range : null;
valueRange = [prefixRange ? prefixRange[1] : param.range[0], param.range[1]];
idx = prefix.lastIndexOf("/");
context = ".";
if(idx >= 0) {
context = prefix.substr(0, idx);
prefix = `.${prefix.substr(idx)}`;
}
regExp = new RegExp(`^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(postfix)}$`);
dep = new Dep(context, options.wrappedContextRecursive, regExp, range, valueRange, chunkName);
} else if (
param.isWrapped() &&
((param.prefix && param.prefix.isString()) ||
(param.postfix && param.postfix.isString()))
) {
let prefixRaw =
param.prefix && param.prefix.isString() ? param.prefix.string : "";
let postfixRaw =
param.postfix && param.postfix.isString() ? param.postfix.string : "";
const prefixRange =
param.prefix && param.prefix.isString() ? param.prefix.range : null;
const postfixRange =
param.postfix && param.postfix.isString() ? param.postfix.range : null;
const valueRange = param.range;
const { context, prefix } = splitContextFromPrefix(prefixRaw);
const { postfix, query } = splitQueryFromPostfix(postfixRaw);
const regExp = new RegExp(
`^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(
postfix
)}$`
);
const dep = new Dep(
Object.assign(
{
request: context + query,
recursive: options.wrappedContextRecursive,
regExp,
mode: "sync"
},
contextOptions
),
range,
valueRange
);
dep.loc = expr.loc;
dep.prepend = param.prefix && param.prefix.isString() ? prefix : null;
dep.critical = options.wrappedContextCritical && "a part of the request of a dependency is an expression";
const replaces = [];
if (prefixRange) {
replaces.push({
range: prefixRange,
value: JSON.stringify(prefix)
});
}
if (postfixRange) {
replaces.push({
range: postfixRange,
value: JSON.stringify(postfix)
});
}
dep.replaces = replaces;
dep.critical =
options.wrappedContextCritical &&
"a part of the request of a dependency is an expression";
if (parser && param.wrappedInnerExpressions) {
for (const part of param.wrappedInnerExpressions) {
if (part.expression) parser.walkExpression(part.expression);
}
}
return dep;
} else {
dep = new Dep(options.exprContextRequest, options.exprContextRecursive, options.exprContextRegExp, range, param.range, chunkName);
const dep = new Dep(
Object.assign(
{
request: options.exprContextRequest,
recursive: options.exprContextRecursive,
regExp: options.exprContextRegExp,
mode: "sync"
},
contextOptions
),
range,
param.range
);
dep.loc = expr.loc;
dep.critical = options.exprContextCritical && "the request of a dependency is an expression";
dep.critical =
options.exprContextCritical &&
"the request of a dependency is an expression";
if (parser) {
parser.walkExpression(param.expression);
}
return dep;
}
};
+23 -12
View File
@@ -5,27 +5,38 @@
"use strict";
class ContextDependencyTemplateAsId {
apply(dep, source, runtime) {
const moduleExports = runtime.moduleExports({
module: dep.module,
request: dep.request
});
apply(dep, source, outputOptions, requestShortener) {
const comment = outputOptions.pathinfo ?
"/*! " + requestShortener.shorten(dep.request) + " */ " : "";
if(dep.module && dep.module.dependencies && dep.module.dependencies.length > 0) {
if(dep.valueRange) {
if(Array.isArray(dep.replaces)) {
for(let i = 0; i < dep.replaces.length; i++) {
if (dep.module) {
if (dep.valueRange) {
if (Array.isArray(dep.replaces)) {
for (let i = 0; i < dep.replaces.length; i++) {
const rep = dep.replaces[i];
source.replace(rep.range[0], rep.range[1] - 1, rep.value);
}
}
source.replace(dep.valueRange[1], dep.range[1] - 1, ")");
source.replace(dep.range[0], dep.valueRange[0] - 1, "__webpack_require__(" + comment + JSON.stringify(dep.module.id) + ").resolve(" + (typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : "") + "");
// TODO webpack 5 remove `prepend` it's no longer used
source.replace(
dep.range[0],
dep.valueRange[0] - 1,
`${moduleExports}.resolve(${
typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : ""
}`
);
} else {
source.replace(dep.range[0], dep.range[1] - 1, "__webpack_require__(" + comment + JSON.stringify(dep.module.id) + ").resolve");
source.replace(
dep.range[0],
dep.range[1] - 1,
`${moduleExports}.resolve`
);
}
} else {
const content = require("./WebpackMissingModule").module(dep.request);
source.replace(dep.range[0], dep.range[1] - 1, content);
source.replace(dep.range[0], dep.range[1] - 1, moduleExports);
}
}
}
@@ -5,29 +5,34 @@
"use strict";
class ContextDependencyTemplateAsRequireCall {
apply(dep, source, runtime) {
const moduleExports = runtime.moduleExports({
module: dep.module,
request: dep.request
});
apply(dep, source, outputOptions, requestShortener) {
const comment = outputOptions.pathinfo ?
"/*! " + requestShortener.shorten(dep.request) + " */ " : "";
const containsDeps = dep.module && dep.module.dependencies && dep.module.dependencies.length > 0;
const isAsync = dep.module && dep.module.async;
if(dep.module && (isAsync || containsDeps)) {
if(dep.valueRange) {
if(Array.isArray(dep.replaces)) {
for(let i = 0; i < dep.replaces.length; i++) {
if (dep.module) {
if (dep.valueRange) {
if (Array.isArray(dep.replaces)) {
for (let i = 0; i < dep.replaces.length; i++) {
const rep = dep.replaces[i];
source.replace(rep.range[0], rep.range[1] - 1, rep.value);
}
}
source.replace(dep.valueRange[1], dep.range[1] - 1, ")");
source.replace(dep.range[0], dep.valueRange[0] - 1, "__webpack_require__(" + comment + JSON.stringify(dep.module.id) + ")(" + (typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : "") + "");
// TODO webpack 5 remove `prepend` it's no longer used
source.replace(
dep.range[0],
dep.valueRange[0] - 1,
`${moduleExports}(${
typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : ""
}`
);
} else {
source.replace(dep.range[0], dep.range[1] - 1, "__webpack_require__(" + comment + JSON.stringify(dep.module.id) + ")");
source.replace(dep.range[0], dep.range[1] - 1, moduleExports);
}
} else {
const content = require("./WebpackMissingModule").module(dep.request);
source.replace(dep.range[0], dep.range[1] - 1, content);
source.replace(dep.range[0], dep.range[1] - 1, moduleExports);
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ const ModuleDependency = require("./ModuleDependency");
class ContextElementDependency extends ModuleDependency {
constructor(request, userRequest) {
super(request);
if(userRequest) {
if (userRequest) {
this.userRequest = userRequest;
}
}
+5 -5
View File
@@ -3,6 +3,8 @@
Author Tobias Koppers @sokra
*/
"use strict";
const DependencyReference = require("./DependencyReference");
const NullDependency = require("./NullDependency");
class DelegatedExportsDependency extends NullDependency {
@@ -17,15 +19,13 @@ class DelegatedExportsDependency extends NullDependency {
}
getReference() {
return {
module: this.originModule,
importedNames: true
};
return new DependencyReference(this.originModule, true, false);
}
getExports() {
return {
exports: this.exports
exports: this.exports,
dependencies: undefined
};
}
}
-39
View File
@@ -1,39 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const DepBlockHelpers = exports;
DepBlockHelpers.getLoadDepBlockWrapper = (depBlock, outputOptions, requestShortener, name) => {
const promiseCode = DepBlockHelpers.getDepBlockPromise(depBlock, outputOptions, requestShortener, name);
return [
promiseCode + ".then(",
").catch(",
")"
];
};
DepBlockHelpers.getDepBlockPromise = (depBlock, outputOptions, requestShortener, name) => {
if(depBlock.chunks) {
const chunks = depBlock.chunks.filter(chunk => !chunk.hasRuntime() && chunk.id !== null);
const pathChunkCheck = outputOptions.pathinfo && depBlock.chunkName;
const shortChunkName = requestShortener.shorten(depBlock.chunkName);
const chunkReason = asComment(depBlock.chunkReason);
const requireChunkId = chunk => "__webpack_require__.e(" + JSON.stringify(chunk.id) + ")";
name = asComment(name);
if(chunks.length === 1) {
const chunkId = JSON.stringify(chunks[0].id);
return `__webpack_require__.e${name}(${chunkId}${pathChunkCheck ? "/*! " + shortChunkName + " */" : ""}${chunkReason})`;
} else if(chunks.length > 0) {
return `Promise.all${name}(${pathChunkCheck ? "/*! " + shortChunkName + " */" : ""}[${chunks.map(requireChunkId).join(", ")}])`;
}
}
return "new Promise(function(resolve) { resolve(); })";
};
function asComment(str) {
if(!str) return "";
return `/* ${str} */`;
}
+17 -11
View File
@@ -3,8 +3,9 @@
Author Tobias Koppers @sokra
*/
"use strict";
const NullDependency = require("./NullDependency");
const makeHarmonyImportStatement = require("./HarmonyImportDependency").makeImportStatement;
const HarmonyImportDependency = require("./HarmonyImportDependency");
class HarmonyAcceptDependency extends NullDependency {
constructor(range, dependencies, hasCallback) {
@@ -20,18 +21,23 @@ class HarmonyAcceptDependency extends NullDependency {
}
HarmonyAcceptDependency.Template = class HarmonyAcceptDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
apply(dep, source, runtime) {
const content = dep.dependencies
.map(dependency => makeHarmonyImportStatement(
false,
dependency,
outputOptions,
requestShortener
)).join("");
.filter(dependency =>
HarmonyImportDependency.Template.isImportEmitted(dependency, source)
)
.map(dependency => dependency.getImportStatement(true, runtime))
.join("");
if(dep.hasCallback) {
source.insert(dep.range[0], `function(__WEBPACK_OUTDATED_DEPENDENCIES__) { ${content}(`);
source.insert(dep.range[1], ")(__WEBPACK_OUTDATED_DEPENDENCIES__); }");
if (dep.hasCallback) {
source.insert(
dep.range[0],
`function(__WEBPACK_OUTDATED_DEPENDENCIES__) { ${content}(`
);
source.insert(
dep.range[1],
")(__WEBPACK_OUTDATED_DEPENDENCIES__); }.bind(this)"
);
return;
}
+5 -4
View File
@@ -6,8 +6,9 @@
const HarmonyImportDependency = require("./HarmonyImportDependency");
class HarmonyAcceptImportDependency extends HarmonyImportDependency {
constructor(request, importedVar, range) {
super(request, importedVar, range);
constructor(request, originModule, parserScope) {
super(request, originModule, NaN, parserScope);
this.weak = true;
}
get type() {
@@ -15,8 +16,8 @@ class HarmonyAcceptImportDependency extends HarmonyImportDependency {
}
}
HarmonyAcceptImportDependency.Template = class HarmonyAcceptImportDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {}
HarmonyAcceptImportDependency.Template = class HarmonyAcceptImportDependencyTemplate extends HarmonyImportDependency.Template {
apply(dep, source, runtime) {}
};
module.exports = HarmonyAcceptImportDependency;
+5 -4
View File
@@ -17,11 +17,12 @@ class HarmonyCompatibilityDependency extends NullDependency {
}
HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate {
apply(dep, source) {
apply(dep, source, runtime) {
const usedExports = dep.originModule.usedExports;
if(usedExports && !Array.isArray(usedExports)) {
const exportName = dep.originModule.exportsArgument || "exports";
const content = `Object.defineProperty(${exportName}, "__esModule", { value: true });\n`;
if (usedExports !== false && !Array.isArray(usedExports)) {
const content = runtime.defineEsModuleFlagStatement({
exportsArgument: dep.originModule.exportsArgument
});
source.insert(-10, content);
}
}
+66 -26
View File
@@ -5,17 +5,38 @@
"use strict";
const HarmonyCompatibilityDependency = require("./HarmonyCompatibilityDependency");
const HarmonyInitDependency = require("./HarmonyInitDependency");
module.exports = class HarmonyDetectionParserPlugin {
apply(parser) {
parser.plugin("program", (ast) => {
const isHarmony = ast.body.some(statement => {
return /^(Import|Export).*Declaration$/.test(statement.type);
});
if(isHarmony) {
parser.hooks.program.tap("HarmonyDetectionParserPlugin", ast => {
const isStrictHarmony = parser.state.module.type === "javascript/esm";
const isHarmony =
isStrictHarmony ||
ast.body.some(
statement =>
statement.type === "ImportDeclaration" ||
statement.type === "ExportDefaultDeclaration" ||
statement.type === "ExportNamedDeclaration" ||
statement.type === "ExportAllDeclaration"
);
if (isHarmony) {
const module = parser.state.module;
const dep = new HarmonyCompatibilityDependency(module);
dep.loc = {
const compatDep = new HarmonyCompatibilityDependency(module);
compatDep.loc = {
start: {
line: -1,
column: 0
},
end: {
line: -1,
column: 0
},
index: -3
};
module.addDependency(compatDep);
const initDep = new HarmonyInitDependency(module);
initDep.loc = {
start: {
line: -1,
column: 0
@@ -26,31 +47,50 @@ module.exports = class HarmonyDetectionParserPlugin {
},
index: -2
};
module.addDependency(dep);
module.meta.harmonyModule = true;
module.strict = true;
module.exportsArgument = "__webpack_exports__";
module.addDependency(initDep);
parser.state.harmonyParserScope = parser.state.harmonyParserScope || {};
parser.scope.isStrict = true;
module.buildMeta.exportsType = "namespace";
module.buildInfo.strict = true;
module.buildInfo.exportsArgument = "__webpack_exports__";
if (isStrictHarmony) {
module.buildMeta.strictHarmonyModule = true;
module.buildInfo.moduleArgument = "__webpack_module__";
}
}
});
const nonHarmonyIdentifiers = ["define", "exports"];
nonHarmonyIdentifiers.forEach(identifer => {
parser.plugin(`evaluate typeof ${identifer}`, nullInHarmony);
parser.plugin(`typeof ${identifer}`, skipInHarmony);
parser.plugin(`evaluate ${identifer}`, nullInHarmony);
parser.plugin(`expression ${identifer}`, skipInHarmony);
parser.plugin(`call ${identifer}`, skipInHarmony);
});
function skipInHarmony() {
const module = this.state.module;
if(module && module.meta && module.meta.harmonyModule)
const skipInHarmony = () => {
const module = parser.state.module;
if (module && module.buildMeta && module.buildMeta.exportsType) {
return true;
}
}
};
function nullInHarmony() {
const module = this.state.module;
if(module && module.meta && module.meta.harmonyModule)
const nullInHarmony = () => {
const module = parser.state.module;
if (module && module.buildMeta && module.buildMeta.exportsType) {
return null;
}
};
const nonHarmonyIdentifiers = ["define", "exports"];
for (const identifer of nonHarmonyIdentifiers) {
parser.hooks.evaluateTypeof
.for(identifer)
.tap("HarmonyDetectionParserPlugin", nullInHarmony);
parser.hooks.typeof
.for(identifer)
.tap("HarmonyDetectionParserPlugin", skipInHarmony);
parser.hooks.evaluate
.for(identifer)
.tap("HarmonyDetectionParserPlugin", nullInHarmony);
parser.hooks.expression
.for(identifer)
.tap("HarmonyDetectionParserPlugin", skipInHarmony);
parser.hooks.call
.for(identifer)
.tap("HarmonyDetectionParserPlugin", skipInHarmony);
}
}
};
+135 -68
View File
@@ -5,83 +5,150 @@
"use strict";
const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency");
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency");
const HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency");
const HarmonyExportImportedSpecifierDependency = require("./HarmonyExportImportedSpecifierDependency");
const HarmonyImportDependency = require("./HarmonyImportDependency");
const HarmonyModulesHelpers = require("./HarmonyModulesHelpers");
const ConstDependency = require("./ConstDependency");
module.exports = class HarmonyExportDependencyParserPlugin {
constructor(moduleOptions) {
this.strictExportPresence = moduleOptions.strictExportPresence;
}
apply(parser) {
parser.plugin("export", statement => {
const dep = new HarmonyExportHeaderDependency(statement.declaration && statement.declaration.range, statement.range);
dep.loc = Object.create(statement.loc);
dep.loc.index = -1;
parser.state.current.addDependency(dep);
return true;
});
parser.plugin("export import", (statement, source) => {
const dep = new HarmonyImportDependency(source, HarmonyModulesHelpers.getNewModuleVar(parser.state, source), statement.range);
dep.loc = Object.create(statement.loc);
dep.loc.index = -1;
parser.state.current.addDependency(dep);
parser.state.lastHarmonyImport = dep;
return true;
});
parser.plugin("export expression", (statement, expr) => {
const dep = new HarmonyExportExpressionDependency(parser.state.module, expr.range, statement.range);
dep.loc = Object.create(statement.loc);
dep.loc.index = -1;
parser.state.current.addDependency(dep);
return true;
});
parser.plugin("export declaration", statement => {});
parser.plugin("export specifier", (statement, id, name, idx) => {
const rename = parser.scope.renames[`$${id}`];
let dep;
const harmonyNamedExports = parser.state.harmonyNamedExports = parser.state.harmonyNamedExports || new Set();
harmonyNamedExports.add(name);
if(rename === "imported var") {
const settings = parser.state.harmonySpecifier[`$${id}`];
dep = new HarmonyExportImportedSpecifierDependency(parser.state.module, settings[0], settings[1], settings[2], name, harmonyNamedExports, null);
} else {
const immutable = statement.declaration && isImmutableStatement(statement.declaration);
const hoisted = statement.declaration && isHoistedStatement(statement.declaration);
dep = new HarmonyExportSpecifierDependency(parser.state.module, id, name, !immutable || hoisted ? -2 : (statement.range[1] + 0.5), immutable);
parser.hooks.export.tap(
"HarmonyExportDependencyParserPlugin",
statement => {
const dep = new HarmonyExportHeaderDependency(
statement.declaration && statement.declaration.range,
statement.range
);
dep.loc = Object.create(statement.loc);
dep.loc.index = -1;
parser.state.current.addDependency(dep);
return true;
}
dep.loc = Object.create(statement.loc);
dep.loc.index = idx;
parser.state.current.addDependency(dep);
return true;
});
parser.plugin("export import specifier", (statement, source, id, name, idx) => {
const harmonyNamedExports = parser.state.harmonyNamedExports = parser.state.harmonyNamedExports || new Set();
let harmonyStarExports = null;
if(name) {
);
parser.hooks.exportImport.tap(
"HarmonyExportDependencyParserPlugin",
(statement, source) => {
parser.state.lastHarmonyImportOrder =
(parser.state.lastHarmonyImportOrder || 0) + 1;
const clearDep = new ConstDependency("", statement.range);
clearDep.loc = Object.create(statement.loc);
clearDep.loc.index = -1;
parser.state.current.addDependency(clearDep);
const sideEffectDep = new HarmonyImportSideEffectDependency(
source,
parser.state.module,
parser.state.lastHarmonyImportOrder,
parser.state.harmonyParserScope
);
sideEffectDep.loc = Object.create(statement.loc);
sideEffectDep.loc.index = -1;
parser.state.current.addDependency(sideEffectDep);
return true;
}
);
parser.hooks.exportExpression.tap(
"HarmonyExportDependencyParserPlugin",
(statement, expr) => {
const comments = parser.getComments([
statement.range[0],
expr.range[0]
]);
const dep = new HarmonyExportExpressionDependency(
parser.state.module,
expr.range,
statement.range,
comments
.map(c => {
switch (c.type) {
case "Block":
return `/*${c.value}*/`;
case "Line":
return `//${c.value}\n`;
}
return "";
})
.join("")
);
dep.loc = Object.create(statement.loc);
dep.loc.index = -1;
parser.state.current.addDependency(dep);
return true;
}
);
parser.hooks.exportDeclaration.tap(
"HarmonyExportDependencyParserPlugin",
statement => {}
);
parser.hooks.exportSpecifier.tap(
"HarmonyExportDependencyParserPlugin",
(statement, id, name, idx) => {
const rename = parser.scope.renames.get(id);
let dep;
const harmonyNamedExports = (parser.state.harmonyNamedExports =
parser.state.harmonyNamedExports || new Set());
harmonyNamedExports.add(name);
} else {
harmonyStarExports = parser.state.harmonyStarExports = parser.state.harmonyStarExports || [];
if (rename === "imported var") {
const settings = parser.state.harmonySpecifier.get(id);
dep = new HarmonyExportImportedSpecifierDependency(
settings.source,
parser.state.module,
settings.sourceOrder,
parser.state.harmonyParserScope,
settings.id,
name,
harmonyNamedExports,
null,
this.strictExportPresence
);
} else {
dep = new HarmonyExportSpecifierDependency(
parser.state.module,
id,
name
);
}
dep.loc = Object.create(statement.loc);
dep.loc.index = idx;
parser.state.current.addDependency(dep);
return true;
}
const dep = new HarmonyExportImportedSpecifierDependency(parser.state.module, parser.state.lastHarmonyImport, HarmonyModulesHelpers.getModuleVar(parser.state, source), id, name, harmonyNamedExports, harmonyStarExports && harmonyStarExports.slice());
if(harmonyStarExports) {
harmonyStarExports.push(dep);
);
parser.hooks.exportImportSpecifier.tap(
"HarmonyExportDependencyParserPlugin",
(statement, source, id, name, idx) => {
const harmonyNamedExports = (parser.state.harmonyNamedExports =
parser.state.harmonyNamedExports || new Set());
let harmonyStarExports = null;
if (name) {
harmonyNamedExports.add(name);
} else {
harmonyStarExports = parser.state.harmonyStarExports =
parser.state.harmonyStarExports || [];
}
const dep = new HarmonyExportImportedSpecifierDependency(
source,
parser.state.module,
parser.state.lastHarmonyImportOrder,
parser.state.harmonyParserScope,
id,
name,
harmonyNamedExports,
harmonyStarExports && harmonyStarExports.slice(),
this.strictExportPresence
);
if (harmonyStarExports) {
harmonyStarExports.push(dep);
}
dep.loc = Object.create(statement.loc);
dep.loc.index = idx;
parser.state.current.addDependency(dep);
return true;
}
dep.loc = Object.create(statement.loc);
dep.loc.index = idx;
parser.state.current.addDependency(dep);
return true;
});
);
}
};
function isImmutableStatement(statement) {
if(statement.type === "FunctionDeclaration") return true;
if(statement.type === "ClassDeclaration") return true;
if(statement.type === "VariableDeclaration" && statement.kind === "const") return true;
return false;
}
function isHoistedStatement(statement) {
if(statement.type === "FunctionDeclaration") return true;
return false;
}
+15 -7
View File
@@ -6,11 +6,12 @@
const NullDependency = require("./NullDependency");
class HarmonyExportExpressionDependency extends NullDependency {
constructor(originModule, range, rangeStatement) {
constructor(originModule, range, rangeStatement, prefix) {
super();
this.originModule = originModule;
this.range = range;
this.rangeStatement = rangeStatement;
this.prefix = prefix;
}
get type() {
@@ -19,7 +20,8 @@ class HarmonyExportExpressionDependency extends NullDependency {
getExports() {
return {
exports: ["default"]
exports: ["default"],
dependencies: undefined
};
}
}
@@ -29,8 +31,12 @@ HarmonyExportExpressionDependency.Template = class HarmonyExportDependencyTempla
const used = dep.originModule.isUsed("default");
const content = this.getContent(dep.originModule, used);
if(dep.range) {
source.replace(dep.rangeStatement[0], dep.range[0] - 1, content + "(");
if (dep.range) {
source.replace(
dep.rangeStatement[0],
dep.range[0] - 1,
content + "(" + dep.prefix
);
source.replace(dep.range[1], dep.rangeStatement[1] - 1, ");");
return;
}
@@ -39,9 +45,11 @@ HarmonyExportExpressionDependency.Template = class HarmonyExportDependencyTempla
}
getContent(module, used) {
const exportsName = module.exportsArgument || "exports";
if(used) {
return `/* harmony default export */ ${exportsName}[${JSON.stringify(used)}] = `;
const exportsName = module.exportsArgument;
if (used) {
return `/* harmony default export */ ${exportsName}[${JSON.stringify(
used
)}] = `;
}
return "/* unused harmony default export */ var _unused_webpack_default_export = ";
}
+3 -1
View File
@@ -20,7 +20,9 @@ class HarmonyExportHeaderDependency extends NullDependency {
HarmonyExportHeaderDependency.Template = class HarmonyExportDependencyTemplate {
apply(dep, source) {
const content = "";
const replaceUntil = dep.range ? dep.range[0] - 1 : dep.rangeStatement[1] - 1;
const replaceUntil = dep.range
? dep.range[0] - 1
: dep.rangeStatement[1] - 1;
source.replace(dep.rangeStatement[0], replaceUntil, content);
}
};
@@ -3,133 +3,314 @@
Author Tobias Koppers @sokra
*/
"use strict";
const NullDependency = require("./NullDependency");
class HarmonyExportImportedSpecifierDependency extends NullDependency {
constructor(originModule, importDependency, importedVar, id, name, activeExports, otherStarExports) {
super();
this.originModule = originModule;
this.importDependency = importDependency;
this.importedVar = importedVar;
const DependencyReference = require("./DependencyReference");
const HarmonyImportDependency = require("./HarmonyImportDependency");
const Template = require("../Template");
const HarmonyLinkingError = require("../HarmonyLinkingError");
/** @typedef {import("../Module")} Module */
/** @typedef {"missing"|"unused"|"empty-star"|"reexport-non-harmony-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-non-harmony-default-strict"|"reexport-fake-namespace-object"|"rexport-non-harmony-undefined"|"safe-reexport"|"checked-reexport"|"dynamic-reexport"} ExportModeType */
/** @type {Map<string, string>} */
const EMPTY_MAP = new Map();
class ExportMode {
/**
* @param {ExportModeType} type type of the mode
*/
constructor(type) {
/** @type {ExportModeType} */
this.type = type;
/** @type {string|null} */
this.name = null;
/** @type {Map<string, string>} */
this.map = EMPTY_MAP;
/** @type {Module|null} */
this.module = null;
/** @type {string|null} */
this.userRequest = null;
}
}
const EMPTY_STAR_MODE = new ExportMode("empty-star");
class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
constructor(
request,
originModule,
sourceOrder,
parserScope,
id,
name,
activeExports,
otherStarExports,
strictExportPresence
) {
super(request, originModule, sourceOrder, parserScope);
this.id = id;
this.name = name;
this.activeExports = activeExports;
this.otherStarExports = otherStarExports;
this.strictExportPresence = strictExportPresence;
}
get type() {
return "harmony export imported specifier";
}
getReference() {
getMode(ignoreUnused) {
const name = this.name;
const id = this.id;
const used = this.originModule.isUsed(name);
const importedModule = this.importDependency.module;
const importedModule = this._module;
if(!importedModule || !used || !this.originModule.usedExports) return null;
const hasUsedExports = Array.isArray(this.originModule.usedExports);
if(name) {
const nameIsNotInUsedExports = hasUsedExports && this.originModule.usedExports.indexOf(name) < 0;
if(nameIsNotInUsedExports) return null;
// export { name as name }
if(this.id) {
return {
module: importedModule,
importedNames: [this.id]
};
}
// export { * as name }
return {
module: importedModule,
importedNames: true
};
if (!importedModule) {
const mode = new ExportMode("missing");
mode.userRequest = this.userRequest;
return mode;
}
const hasProvidedExports = Array.isArray(importedModule.providedExports);
if (
!ignoreUnused &&
(name ? !used : this.originModule.usedExports === false)
) {
const mode = new ExportMode("unused");
mode.name = name || "*";
return mode;
}
const strictHarmonyModule = this.originModule.buildMeta.strictHarmonyModule;
if (name && id === "default" && importedModule.buildMeta) {
if (!importedModule.buildMeta.exportsType) {
const mode = new ExportMode(
strictHarmonyModule
? "reexport-non-harmony-default-strict"
: "reexport-non-harmony-default"
);
mode.name = name;
mode.module = importedModule;
return mode;
} else if (importedModule.buildMeta.exportsType === "named") {
const mode = new ExportMode("reexport-named-default");
mode.name = name;
mode.module = importedModule;
return mode;
}
}
const isNotAHarmonyModule =
importedModule.buildMeta && !importedModule.buildMeta.exportsType;
if (name) {
let mode;
if (id) {
// export { name as name }
if (isNotAHarmonyModule && strictHarmonyModule) {
mode = new ExportMode("rexport-non-harmony-undefined");
mode.name = name;
} else {
mode = new ExportMode("safe-reexport");
mode.map = new Map([[name, id]]);
}
} else {
// export { * as name }
if (isNotAHarmonyModule && strictHarmonyModule) {
mode = new ExportMode("reexport-fake-namespace-object");
mode.name = name;
} else {
mode = new ExportMode("reexport-namespace-object");
mode.name = name;
}
}
mode.module = importedModule;
return mode;
}
const hasUsedExports = Array.isArray(this.originModule.usedExports);
const hasProvidedExports = Array.isArray(
importedModule.buildMeta.providedExports
);
const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports();
// export *
if(hasUsedExports) {
if (hasUsedExports) {
// reexport * with known used exports
const importedNames = this.originModule.usedExports.filter(id => {
if(id === "default") return false;
if(this.activeExports.has(id)) return false;
if(activeFromOtherStarExports.has(id)) return false;
if(hasProvidedExports && importedModule.providedExports.indexOf(id) < 0) return false;
if (hasProvidedExports) {
const map = new Map(
this.originModule.usedExports
.filter(id => {
if (id === "default") return false;
if (this.activeExports.has(id)) return false;
if (activeFromOtherStarExports.has(id)) return false;
if (!importedModule.buildMeta.providedExports.includes(id))
return false;
return true;
})
.map(item => [item, item])
);
return true;
});
if (map.size === 0) {
return EMPTY_STAR_MODE;
}
return {
module: importedModule,
importedNames
};
const mode = new ExportMode("safe-reexport");
mode.module = importedModule;
mode.map = map;
return mode;
}
const map = new Map(
this.originModule.usedExports
.filter(id => {
if (id === "default") return false;
if (this.activeExports.has(id)) return false;
if (activeFromOtherStarExports.has(id)) return false;
return true;
})
.map(item => [item, item])
);
if (map.size === 0) {
return EMPTY_STAR_MODE;
}
const mode = new ExportMode("checked-reexport");
mode.module = importedModule;
mode.map = map;
return mode;
}
if(hasProvidedExports) {
return {
module: importedModule,
importedNames: importedModule.providedExports.filter(id => {
if(id === "default") return false;
if(this.activeExports.has(id)) return false;
if(activeFromOtherStarExports.has(id)) return false;
if (hasProvidedExports) {
const map = new Map(
importedModule.buildMeta.providedExports
.filter(id => {
if (id === "default") return false;
if (this.activeExports.has(id)) return false;
if (activeFromOtherStarExports.has(id)) return false;
return true;
})
};
return true;
})
.map(item => [item, item])
);
if (map.size === 0) {
return EMPTY_STAR_MODE;
}
const mode = new ExportMode("safe-reexport");
mode.module = importedModule;
mode.map = map;
return mode;
}
return {
module: importedModule,
importedNames: true,
};
const mode = new ExportMode("dynamic-reexport");
mode.module = importedModule;
return mode;
}
getReference() {
const mode = this.getMode(false);
switch (mode.type) {
case "missing":
case "unused":
case "empty-star":
return null;
case "reexport-non-harmony-default":
case "reexport-named-default":
return new DependencyReference(
mode.module,
["default"],
false,
this.sourceOrder
);
case "reexport-namespace-object":
case "reexport-non-harmony-default-strict":
case "reexport-fake-namespace-object":
case "rexport-non-harmony-undefined":
return new DependencyReference(
mode.module,
true,
false,
this.sourceOrder
);
case "safe-reexport":
case "checked-reexport":
return new DependencyReference(
mode.module,
Array.from(mode.map.values()),
false,
this.sourceOrder
);
case "dynamic-reexport":
return new DependencyReference(
mode.module,
true,
false,
this.sourceOrder
);
default:
throw new Error(`Unknown mode ${mode.type}`);
}
}
_discoverActiveExportsFromOtherStartExports() {
if(!this.otherStarExports)
return new Set();
if (!this.otherStarExports) return new Set();
const result = new Set();
// try to learn impossible exports from other star exports with provided exports
for(const otherStarExport of this.otherStarExports) {
const otherImportedModule = otherStarExport.importDependency.module;
if(otherImportedModule && Array.isArray(otherImportedModule.providedExports)) {
for(const exportName of otherImportedModule.providedExports)
for (const otherStarExport of this.otherStarExports) {
const otherImportedModule = otherStarExport._module;
if (
otherImportedModule &&
Array.isArray(otherImportedModule.buildMeta.providedExports)
) {
for (const exportName of otherImportedModule.buildMeta
.providedExports) {
result.add(exportName);
}
}
}
return result;
}
getExports() {
if(this.name) {
if (this.name) {
return {
exports: [this.name]
exports: [this.name],
dependencies: undefined
};
}
const importedModule = this.importDependency.module;
const importedModule = this.module;
if(!importedModule) {
if (!importedModule) {
// no imported module available
return {
exports: null
exports: null,
dependencies: undefined
};
}
if(Array.isArray(importedModule.providedExports)) {
if (Array.isArray(importedModule.buildMeta.providedExports)) {
return {
exports: importedModule.providedExports.filter(id => id !== "default"),
exports: importedModule.buildMeta.providedExports.filter(
id => id !== "default"
),
dependencies: [importedModule]
};
}
if(importedModule.providedExports) {
if (importedModule.buildMeta.providedExports) {
return {
exports: true
exports: true,
dependencies: undefined
};
}
@@ -139,147 +320,326 @@ class HarmonyExportImportedSpecifierDependency extends NullDependency {
};
}
getWarnings() {
if (
this.strictExportPresence ||
this.originModule.buildMeta.strictHarmonyModule
) {
return [];
}
return this._getErrors();
}
getErrors() {
if (
this.strictExportPresence ||
this.originModule.buildMeta.strictHarmonyModule
) {
return this._getErrors();
}
return [];
}
_getErrors() {
const importedModule = this._module;
if (!importedModule) {
return;
}
if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
// It's not an harmony module
if (
this.originModule.buildMeta.strictHarmonyModule &&
this.id !== "default"
) {
// In strict harmony modules we only support the default export
const exportName = this.id
? `the named export '${this.id}'`
: "the namespace object";
return [
new HarmonyLinkingError(
`Can't reexport ${exportName} from non EcmaScript module (only default export is available)`
)
];
}
return;
}
if (!this.id) {
return;
}
if (importedModule.isProvided(this.id) !== false) {
// It's provided or we are not sure
return;
}
// We are sure that it's not provided
const idIsNotNameMessage =
this.id !== this.name ? ` (reexported as '${this.name}')` : "";
const errorMessage = `"export '${
this.id
}'${idIsNotNameMessage} was not found in '${this.userRequest}'`;
return [new HarmonyLinkingError(errorMessage)];
}
updateHash(hash) {
super.updateHash(hash);
const hashValue = this.getHashValue(this.importDependency.module);
const hashValue = this.getHashValue(this._module);
hash.update(hashValue);
}
getHashValue(importedModule) {
if(!importedModule) {
if (!importedModule) {
return "";
}
const stringifiedUsedExport = JSON.stringify(importedModule.usedExports);
const stringifiedProvidedExport = JSON.stringify(importedModule.providedExports);
return importedModule.used + stringifiedUsedExport + stringifiedProvidedExport;
const stringifiedProvidedExport = JSON.stringify(
importedModule.buildMeta.providedExports
);
return (
importedModule.used + stringifiedUsedExport + stringifiedProvidedExport
);
}
}
module.exports = HarmonyExportImportedSpecifierDependency;
HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate extends HarmonyImportDependency.Template {
harmonyInit(dep, source, runtime, dependencyTemplates) {
super.harmonyInit(dep, source, runtime, dependencyTemplates);
const content = this.getContent(dep);
source.insert(-1, content);
}
getHarmonyInitOrder(dep) {
if (dep.name) {
const used = dep.originModule.isUsed(dep.name);
if (!used) return NaN;
} else {
const importedModule = dep._module;
const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports();
if (Array.isArray(dep.originModule.usedExports)) {
// we know which exports are used
const unused = dep.originModule.usedExports.every(id => {
if (id === "default") return true;
if (dep.activeExports.has(id)) return true;
if (importedModule.isProvided(id) === false) return true;
if (activeFromOtherStarExports.has(id)) return true;
return false;
});
if (unused) return NaN;
} else if (
dep.originModule.usedExports &&
importedModule &&
Array.isArray(importedModule.buildMeta.providedExports)
) {
// not sure which exports are used, but we know which are provided
const unused = importedModule.buildMeta.providedExports.every(id => {
if (id === "default") return true;
if (dep.activeExports.has(id)) return true;
if (activeFromOtherStarExports.has(id)) return true;
return false;
});
if (unused) return NaN;
}
}
return super.getHarmonyInitOrder(dep);
}
getContent(dep) {
const name = dep.importedVar;
const used = dep.originModule.isUsed(dep.name);
const importedModule = dep.importDependency.module;
const importsExportsUnknown = !importedModule || !Array.isArray(importedModule.providedExports);
const mode = dep.getMode(false);
const module = dep.originModule;
const importedModule = dep._module;
const importVar = dep.getImportVar();
const getReexportStatement = this.reexportStatementCreator(dep.originModule, importsExportsUnknown, name);
switch (mode.type) {
case "missing":
return `throw new Error(${JSON.stringify(
`Cannot find module '${mode.userRequest}'`
)});\n`;
// we want to rexport something, but the export isn't used
if(!used) {
return "/* unused harmony reexport " + dep.name + " */\n";
}
case "unused":
return `${Template.toNormalComment(
`unused harmony reexport ${mode.name}`
)}\n`;
// we want to reexport the default export from a non-hamory module
const isNotAHarmonyModule = !(importedModule && (!importedModule.meta || importedModule.meta.harmonyModule));
if(dep.name && dep.id === "default" && isNotAHarmonyModule) {
return "/* harmony reexport (default from non-hamory) */ " + getReexportStatement(JSON.stringify(used), null);
}
case "reexport-non-harmony-default":
return (
"/* harmony reexport (default from non-harmony) */ " +
this.getReexportStatement(
module,
module.isUsed(mode.name),
importVar,
null
)
);
// we want to reexport a key as new key
if(dep.name && dep.id) {
var idUsed = importedModule && importedModule.isUsed(dep.id);
return "/* harmony reexport (binding) */ " + getReexportStatement(JSON.stringify(used), JSON.stringify(idUsed));
}
case "reexport-named-default":
return (
"/* harmony reexport (default from named exports) */ " +
this.getReexportStatement(
module,
module.isUsed(mode.name),
importVar,
""
)
);
// we want to reexport the module object as named export
if(dep.name) {
return "/* harmony reexport (module object) */ " + getReexportStatement(JSON.stringify(used), "");
}
case "reexport-fake-namespace-object":
return (
"/* harmony reexport (fake namespace object from non-harmony) */ " +
this.getReexportFakeNamespaceObjectStatement(
module,
module.isUsed(mode.name),
importVar
)
);
const hasProvidedExports = importedModule && Array.isArray(importedModule.providedExports);
case "rexport-non-harmony-undefined":
return (
"/* harmony reexport (non default export from non-harmony) */ " +
this.getReexportStatement(
module,
module.isUsed(mode.name),
"undefined",
""
)
);
const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports();
case "reexport-non-harmony-default-strict":
return (
"/* harmony reexport (default from non-harmony) */ " +
this.getReexportStatement(
module,
module.isUsed(mode.name),
importVar,
""
)
);
// we know which exports are used
if(Array.isArray(dep.originModule.usedExports)) {
const items = dep.originModule.usedExports.map(id => {
if(id === "default") return;
if(dep.activeExports.has(id)) return;
if(importedModule.isProvided(id) === false) return;
if(activeFromOtherStarExports.has(id)) return;
var exportUsed = dep.originModule.isUsed(id);
var idUsed = importedModule && importedModule.isUsed(id);
return [exportUsed, idUsed];
}).filter(Boolean);
case "reexport-namespace-object":
return (
"/* harmony reexport (module object) */ " +
this.getReexportStatement(
module,
module.isUsed(mode.name),
importVar,
""
)
);
if(items.length === 0) {
return "/* unused harmony namespace reexport */\n";
case "empty-star":
return "/* empty/unused harmony star reexport */";
case "safe-reexport":
return Array.from(mode.map.entries())
.map(item => {
return (
"/* harmony reexport (safe) */ " +
this.getReexportStatement(
module,
module.isUsed(item[0]),
importVar,
importedModule.isUsed(item[1])
) +
"\n"
);
})
.join("");
case "checked-reexport":
return Array.from(mode.map.entries())
.map(item => {
return (
"/* harmony reexport (checked) */ " +
this.getConditionalReexportStatement(
module,
item[0],
importVar,
item[1]
) +
"\n"
);
})
.join("");
case "dynamic-reexport": {
const activeExports = new Set([
...dep.activeExports,
...dep._discoverActiveExportsFromOtherStartExports()
]);
let content =
"/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " +
importVar +
") ";
// Filter out exports which are defined by other exports
// and filter out default export because it cannot be reexported with *
if (activeExports.size > 0) {
content +=
"if(" +
JSON.stringify(Array.from(activeExports).concat("default")) +
".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
} else {
content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') ";
}
const exportsName = dep.originModule.exportsArgument;
return (
content +
`(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${importVar}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`
);
}
return items.map(function(item) {
return "/* harmony namespace reexport (by used) */ " + getReexportStatement(JSON.stringify(item[0]), JSON.stringify(item[1]));
}).join("");
default:
throw new Error(`Unknown mode ${mode.type}`);
}
// not sure which exports are used, but we know which are provided
if(dep.originModule.usedExports && importedModule && hasProvidedExports) {
const items = importedModule.providedExports.map(id => {
if(id === "default") return;
if(dep.activeExports.has(id)) return;
if(activeFromOtherStarExports.has(id)) return;
var exportUsed = dep.originModule.isUsed(id);
var idUsed = importedModule && importedModule.isUsed(id);
return [exportUsed, idUsed];
}).filter(Boolean);
if(items.length === 0) {
return "/* empty harmony namespace reexport */\n";
}
return items.map(function(item) {
return "/* harmony namespace reexport (by provided) */ " + getReexportStatement(JSON.stringify(item[0]), JSON.stringify(item[1]));
}).join("");
}
// not sure which exports are used and provided
if(dep.originModule.usedExports) {
const activeExports = Array.from(dep.activeExports).concat(Array.from(activeFromOtherStarExports));
let content = "/* harmony namespace reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " + name + ") ";
// Filter out exports which are defined by other exports
// and filter out default export because it cannot be reexported with *
if(activeExports.length > 0)
content += "if(" + JSON.stringify(activeExports.concat("default")) + ".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
else
content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') ";
const exportsName = dep.originModule.exportsArgument || "exports";
return content + `(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${name}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`;
}
return "/* unused harmony reexport namespace */\n";
}
reexportStatementCreator(module, importsExportsUnknown, name) {
const exportsName = module.exportsArgument || "exports";
const getReexportStatement = (key, valueKey) => {
const conditional = this.getConditional(importsExportsUnknown, valueKey, name);
const returnValue = this.getReturnValue(valueKey);
return `${conditional}__webpack_require__.d(${exportsName}, ${key}, function() { return ${name}${returnValue}; });\n`;
};
return getReexportStatement;
getReexportStatement(module, key, name, valueKey) {
const exportsName = module.exportsArgument;
const returnValue = this.getReturnValue(name, valueKey);
return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
key
)}, function() { return ${returnValue}; });\n`;
}
getConditional(importsExportsUnknown, valueKey, name) {
if(!importsExportsUnknown || !valueKey) {
return "";
}
return `if(__webpack_require__.o(${name}, ${valueKey})) `;
getReexportFakeNamespaceObjectStatement(module, key, name) {
const exportsName = module.exportsArgument;
return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
key
)}, function() { return __webpack_require__.t(${name}); });\n`;
}
getReturnValue(valueKey) {
if(valueKey === null) {
return "_default.a";
getConditionalReexportStatement(module, key, name, valueKey) {
if (valueKey === false) {
return "/* unused export */\n";
}
const exportsName = module.exportsArgument;
const returnValue = this.getReturnValue(name, valueKey);
return `if(__webpack_require__.o(${name}, ${JSON.stringify(
valueKey
)})) __webpack_require__.d(${exportsName}, ${JSON.stringify(
key
)}, function() { return ${returnValue}; });\n`;
}
getReturnValue(name, valueKey) {
if (valueKey === null) {
return `${name}_default.a`;
}
if (valueKey === "") {
return name;
}
if (valueKey === false) {
return "/* unused export */ undefined";
}
return valueKey && "[" + valueKey + "]";
return `${name}[${JSON.stringify(valueKey)}]`;
}
};
+16 -16
View File
@@ -6,13 +6,11 @@
const NullDependency = require("./NullDependency");
class HarmonyExportSpecifierDependency extends NullDependency {
constructor(originModule, id, name, position, immutable) {
constructor(originModule, id, name) {
super();
this.originModule = originModule;
this.id = id;
this.name = name;
this.position = position;
this.immutable = immutable;
}
get type() {
@@ -21,33 +19,35 @@ class HarmonyExportSpecifierDependency extends NullDependency {
getExports() {
return {
exports: [this.name]
exports: [this.name],
dependencies: undefined
};
}
}
HarmonyExportSpecifierDependency.Template = class HarmonyExportSpecifierDependencyTemplate {
apply(dep, source) {
const content = this.getPrefix(dep) + this.getContent(dep);
source.insert(dep.position, content);
apply(dep, source) {}
getHarmonyInitOrder(dep) {
return 0;
}
getPrefix(dep) {
return dep.position > 0 ? "\n" : "";
harmonyInit(dep, source, runtime) {
const content = this.getContent(dep);
source.insert(-1, content);
}
getContent(dep) {
const used = dep.originModule.isUsed(dep.name);
if(!used) {
return `/* unused harmony export ${(dep.name || "namespace")} */\n`;
if (!used) {
return `/* unused harmony export ${dep.name || "namespace"} */\n`;
}
const exportsName = dep.originModule.exportsArgument || "exports";
if(dep.immutable) {
return `/* harmony export (immutable) */ ${exportsName}[${JSON.stringify(used)}] = ${dep.id};\n`;
}
const exportsName = dep.originModule.exportsArgument;
return `/* harmony export (binding) */ __webpack_require__.d(${exportsName}, ${JSON.stringify(used)}, function() { return ${dep.id}; });\n`;
return `/* harmony export (binding) */ __webpack_require__.d(${exportsName}, ${JSON.stringify(
used
)}, function() { return ${dep.id}; });\n`;
}
};
+83 -46
View File
@@ -3,70 +3,107 @@
Author Tobias Koppers @sokra
*/
"use strict";
const DependencyReference = require("./DependencyReference");
const ModuleDependency = require("./ModuleDependency");
const Template = require("../Template");
class HarmonyImportDependency extends ModuleDependency {
constructor(request, importedVar, range) {
constructor(request, originModule, sourceOrder, parserScope) {
super(request);
this.range = range;
this.importedVar = importedVar;
this.redirectedModule = undefined;
this.originModule = originModule;
this.sourceOrder = sourceOrder;
this.parserScope = parserScope;
}
get type() {
return "harmony import";
get _module() {
return this.redirectedModule || this.module;
}
getReference() {
if(!this.module) return null;
if (!this._module) return null;
return new DependencyReference(
this._module,
false,
this.weak,
this.sourceOrder
);
}
return {
module: this.module,
importedNames: false
};
getImportVar() {
let importVarMap = this.parserScope.importVarMap;
if (!importVarMap) this.parserScope.importVarMap = importVarMap = new Map();
let importVar = importVarMap.get(this._module);
if (importVar) return importVar;
importVar = `${Template.toIdentifier(
`${this.userRequest}`
)}__WEBPACK_IMPORTED_MODULE_${importVarMap.size}__`;
importVarMap.set(this._module, importVar);
return importVar;
}
getImportStatement(update, runtime) {
return runtime.importStatement({
update,
module: this._module,
importVar: this.getImportVar(),
request: this.request,
originModule: this.originModule
});
}
updateHash(hash) {
super.updateHash(hash);
hash.update((this.module && (!this.module.meta || this.module.meta.harmonyModule)) + "");
const importedModule = this._module;
hash.update(
(importedModule &&
(!importedModule.buildMeta || importedModule.buildMeta.exportsType)) +
""
);
hash.update((importedModule && importedModule.id) + "");
}
disconnect() {
super.disconnect();
this.redirectedModule = undefined;
}
}
module.exports = HarmonyImportDependency;
const importEmittedMap = new WeakMap();
HarmonyImportDependency.Template = class HarmonyImportDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
const content = makeImportStatement(true, dep, outputOptions, requestShortener);
source.replace(dep.range[0], dep.range[1] - 1, "");
apply(dep, source, runtime) {
// no-op
}
getHarmonyInitOrder(dep) {
return dep.sourceOrder;
}
static isImportEmitted(dep, source) {
let sourceInfo = importEmittedMap.get(source);
if (!sourceInfo) return false;
const key = dep._module || dep.request;
return key && sourceInfo.emittedImports.get(key);
}
harmonyInit(dep, source, runtime, dependencyTemplates) {
let sourceInfo = importEmittedMap.get(source);
if (!sourceInfo) {
importEmittedMap.set(
source,
(sourceInfo = {
emittedImports: new Map()
})
);
}
const key = dep._module || dep.request;
if (key && sourceInfo.emittedImports.get(key)) return;
sourceInfo.emittedImports.set(key, true);
const content = dep.getImportStatement(false, runtime);
source.insert(-1, content);
}
};
function getOptionalComment(pathinfo, shortenedRequest) {
if(!pathinfo) {
return "";
}
return `/*! ${shortenedRequest} */ `;
}
function makeImportStatement(declare, dep, outputOptions, requestShortener) {
const comment = getOptionalComment(outputOptions.pathinfo, requestShortener.shorten(dep.request));
const declaration = declare ? "var " : "";
const newline = declare ? "\n" : " ";
if(!dep.module) {
const stringifiedError = JSON.stringify(`Cannot find module "${dep.request}"`);
return `throw new Error(${stringifiedError});${newline}`;
}
if(dep.importedVar) {
const isHarmonyModule = dep.module.meta && dep.module.meta.harmonyModule;
const content = `/* harmony import */ ${declaration}${dep.importedVar} = __webpack_require__(${comment}${JSON.stringify(dep.module.id)});${newline}`;
if(isHarmonyModule) {
return content;
}
return `${content}/* harmony import */ ${declaration}${dep.importedVar}_default = __webpack_require__.n(${dep.importedVar});${newline}`;
}
return "";
}
HarmonyImportDependency.makeImportStatement = makeImportStatement;
module.exports = HarmonyImportDependency;
+192 -94
View File
@@ -4,11 +4,12 @@
*/
"use strict";
const HarmonyImportDependency = require("./HarmonyImportDependency");
const { SyncBailHook } = require("tapable");
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency");
const HarmonyAcceptDependency = require("./HarmonyAcceptDependency");
const HarmonyModulesHelpers = require("./HarmonyModulesHelpers");
const ConstDependency = require("./ConstDependency");
module.exports = class HarmonyImportDependencyParserPlugin {
constructor(moduleOptions) {
@@ -17,108 +18,205 @@ module.exports = class HarmonyImportDependencyParserPlugin {
}
apply(parser) {
parser.plugin("import", (statement, source) => {
const dep = new HarmonyImportDependency(source, HarmonyModulesHelpers.getNewModuleVar(parser.state, source), statement.range);
dep.loc = statement.loc;
parser.state.current.addDependency(dep);
parser.state.lastHarmonyImport = dep;
return true;
});
parser.plugin("import specifier", (statement, source, id, name) => {
parser.scope.definitions.length--;
parser.scope.renames[`$${name}`] = "imported var";
if(!parser.state.harmonySpecifier) parser.state.harmonySpecifier = {};
parser.state.harmonySpecifier[`$${name}`] = [parser.state.lastHarmonyImport, HarmonyModulesHelpers.getModuleVar(parser.state, source), id];
return true;
});
parser.plugin("expression imported var", (expr) => {
const name = expr.name;
const settings = parser.state.harmonySpecifier[`$${name}`];
const dep = new HarmonyImportSpecifierDependency(settings[0], settings[1], settings[2], name, expr.range, this.strictExportPresence);
dep.shorthand = parser.scope.inShorthand;
dep.directImport = true;
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
});
parser.plugin("expression imported var.*", (expr) => {
const name = expr.object.name;
const settings = parser.state.harmonySpecifier[`$${name}`];
if(settings[2] !== null)
return false;
const dep = new HarmonyImportSpecifierDependency(settings[0], settings[1], expr.property.name || expr.property.value, name, expr.range, this.strictExportPresence);
dep.shorthand = parser.scope.inShorthand;
dep.directImport = false;
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
});
if(this.strictThisContextOnImports) {
// only in case when we strictly follow the spec we need a special case here
parser.plugin("call imported var.*", (expr) => {
if(expr.callee.type !== "MemberExpression") return;
if(expr.callee.object.type !== "Identifier") return;
const name = expr.callee.object.name;
const settings = parser.state.harmonySpecifier[`$${name}`];
if(settings[2] !== null)
return false;
const dep = new HarmonyImportSpecifierDependency(settings[0], settings[1], expr.callee.property.name || expr.callee.property.value, name, expr.callee.range, this.strictExportPresence);
parser.hooks.import.tap(
"HarmonyImportDependencyParserPlugin",
(statement, source) => {
parser.state.lastHarmonyImportOrder =
(parser.state.lastHarmonyImportOrder || 0) + 1;
const clearDep = new ConstDependency("", statement.range);
clearDep.loc = statement.loc;
parser.state.module.addDependency(clearDep);
const sideEffectDep = new HarmonyImportSideEffectDependency(
source,
parser.state.module,
parser.state.lastHarmonyImportOrder,
parser.state.harmonyParserScope
);
sideEffectDep.loc = statement.loc;
parser.state.module.addDependency(sideEffectDep);
return true;
}
);
parser.hooks.importSpecifier.tap(
"HarmonyImportDependencyParserPlugin",
(statement, source, id, name) => {
parser.scope.definitions.delete(name);
parser.scope.renames.set(name, "imported var");
if (!parser.state.harmonySpecifier) {
parser.state.harmonySpecifier = new Map();
}
parser.state.harmonySpecifier.set(name, {
source,
id,
sourceOrder: parser.state.lastHarmonyImportOrder
});
return true;
}
);
parser.hooks.expression
.for("imported var")
.tap("HarmonyImportDependencyParserPlugin", expr => {
const name = expr.name;
const settings = parser.state.harmonySpecifier.get(name);
const dep = new HarmonyImportSpecifierDependency(
settings.source,
parser.state.module,
settings.sourceOrder,
parser.state.harmonyParserScope,
settings.id,
name,
expr.range,
this.strictExportPresence
);
dep.shorthand = parser.scope.inShorthand;
dep.directImport = false;
dep.namespaceObjectAsContext = true;
dep.loc = expr.callee.loc;
parser.state.current.addDependency(dep);
if(expr.arguments)
parser.walkExpressions(expr.arguments);
dep.directImport = true;
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return true;
});
parser.hooks.expressionAnyMember
.for("imported var")
.tap("HarmonyImportDependencyParserPlugin", expr => {
const name = expr.object.name;
const settings = parser.state.harmonySpecifier.get(name);
if (settings.id !== null) return false;
const dep = new HarmonyImportSpecifierDependency(
settings.source,
parser.state.module,
settings.sourceOrder,
parser.state.harmonyParserScope,
expr.property.name || expr.property.value,
name,
expr.range,
this.strictExportPresence
);
dep.shorthand = parser.scope.inShorthand;
dep.directImport = false;
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return true;
});
if (this.strictThisContextOnImports) {
// only in case when we strictly follow the spec we need a special case here
parser.hooks.callAnyMember
.for("imported var")
.tap("HarmonyImportDependencyParserPlugin", expr => {
if (expr.callee.type !== "MemberExpression") return;
if (expr.callee.object.type !== "Identifier") return;
const name = expr.callee.object.name;
const settings = parser.state.harmonySpecifier.get(name);
if (settings.id !== null) return false;
const dep = new HarmonyImportSpecifierDependency(
settings.source,
parser.state.module,
settings.sourceOrder,
parser.state.harmonyParserScope,
expr.callee.property.name || expr.callee.property.value,
name,
expr.callee.range,
this.strictExportPresence
);
dep.shorthand = parser.scope.inShorthand;
dep.directImport = false;
dep.namespaceObjectAsContext = true;
dep.loc = expr.callee.loc;
parser.state.module.addDependency(dep);
if (expr.arguments) parser.walkExpressions(expr.arguments);
return true;
});
}
parser.plugin("call imported var", (expr) => {
const args = expr.arguments;
const fullExpr = expr;
expr = expr.callee;
if(expr.type !== "Identifier") return;
const name = expr.name;
const settings = parser.state.harmonySpecifier[`$${name}`];
const dep = new HarmonyImportSpecifierDependency(settings[0], settings[1], settings[2], name, expr.range, this.strictExportPresence);
dep.directImport = true;
dep.callArgs = args;
dep.call = fullExpr;
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
if(args)
parser.walkExpressions(args);
return true;
});
parser.plugin("hot accept callback", (expr, requests) => {
const dependencies = requests
.filter(request => HarmonyModulesHelpers.checkModuleVar(parser.state, request))
.map(request => {
const dep = new HarmonyAcceptImportDependency(request, HarmonyModulesHelpers.getModuleVar(parser.state, request), expr.range);
parser.hooks.call
.for("imported var")
.tap("HarmonyImportDependencyParserPlugin", expr => {
const args = expr.arguments;
const fullExpr = expr;
expr = expr.callee;
if (expr.type !== "Identifier") return;
const name = expr.name;
const settings = parser.state.harmonySpecifier.get(name);
const dep = new HarmonyImportSpecifierDependency(
settings.source,
parser.state.module,
settings.sourceOrder,
parser.state.harmonyParserScope,
settings.id,
name,
expr.range,
this.strictExportPresence
);
dep.directImport = true;
dep.callArgs = args;
dep.call = fullExpr;
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
if (args) parser.walkExpressions(args);
return true;
});
// TODO webpack 5: refactor this, no custom hooks
if (!parser.hooks.hotAcceptCallback) {
parser.hooks.hotAcceptCallback = new SyncBailHook([
"expression",
"requests"
]);
}
if (!parser.hooks.hotAcceptWithoutCallback) {
parser.hooks.hotAcceptWithoutCallback = new SyncBailHook([
"expression",
"requests"
]);
}
parser.hooks.hotAcceptCallback.tap(
"HarmonyImportDependencyParserPlugin",
(expr, requests) => {
const harmonyParserScope = parser.state.harmonyParserScope;
if (!harmonyParserScope) {
// This is not a harmony module, skip it
return;
}
const dependencies = requests.map(request => {
const dep = new HarmonyAcceptImportDependency(
request,
parser.state.module,
harmonyParserScope
);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
parser.state.module.addDependency(dep);
return dep;
});
if(dependencies.length > 0) {
const dep = new HarmonyAcceptDependency(expr.range, dependencies, true);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
}
});
parser.plugin("hot accept without callback", (expr, requests) => {
const dependencies = requests
.filter(request => HarmonyModulesHelpers.checkModuleVar(parser.state, request))
.map(request => {
const dep = new HarmonyAcceptImportDependency(request, HarmonyModulesHelpers.getModuleVar(parser.state, request), expr.range);
if (dependencies.length > 0) {
const dep = new HarmonyAcceptDependency(
expr.range,
dependencies,
true
);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
parser.state.module.addDependency(dep);
}
}
);
parser.hooks.hotAcceptWithoutCallback.tap(
"HarmonyImportDependencyParserPlugin",
(expr, requests) => {
const dependencies = requests.map(request => {
const dep = new HarmonyAcceptImportDependency(
request,
parser.state.module,
parser.state.harmonyParserScope
);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return dep;
});
if(dependencies.length > 0) {
const dep = new HarmonyAcceptDependency(expr.range, dependencies, false);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
if (dependencies.length > 0) {
const dep = new HarmonyAcceptDependency(
expr.range,
dependencies,
false
);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
}
}
});
);
}
};
+109 -71
View File
@@ -3,14 +3,25 @@
Author Tobias Koppers @sokra
*/
"use strict";
const NullDependency = require("./NullDependency");
class HarmonyImportSpecifierDependency extends NullDependency {
constructor(importDependency, importedVar, id, name, range, strictExportPresence) {
super();
this.importDependency = importDependency;
this.importedVar = importedVar;
this.id = id;
const DependencyReference = require("./DependencyReference");
const HarmonyImportDependency = require("./HarmonyImportDependency");
const HarmonyLinkingError = require("../HarmonyLinkingError");
class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
constructor(
request,
originModule,
sourceOrder,
parserScope,
id,
name,
range,
strictExportPresence
) {
super(request, originModule, sourceOrder, parserScope);
this.id = id === null ? null : `${id}`;
this.redirectedId = undefined;
this.name = name;
this.range = range;
this.strictExportPresence = strictExportPresence;
@@ -18,111 +29,138 @@ class HarmonyImportSpecifierDependency extends NullDependency {
this.callArgs = undefined;
this.call = undefined;
this.directImport = undefined;
this.shorthand = undefined;
}
get type() {
return "harmony import specifier";
}
get _id() {
return this.redirectedId || this.id;
}
getReference() {
if(!this.importDependency.module) return null;
return {
module: this.importDependency.module,
importedNames: this.id && !this.namespaceObjectAsContext ? [this.id] : true
};
if (!this._module) return null;
return new DependencyReference(
this._module,
this._id && !this.namespaceObjectAsContext ? [this._id] : true,
false,
this.sourceOrder
);
}
getWarnings() {
if(this.strictExportPresence) {
if (
this.strictExportPresence ||
this.originModule.buildMeta.strictHarmonyModule
) {
return [];
}
return this._getErrors();
}
getErrors() {
if(this.strictExportPresence) {
if (
this.strictExportPresence ||
this.originModule.buildMeta.strictHarmonyModule
) {
return this._getErrors();
}
return [];
}
_getErrors() {
const importedModule = this.importDependency.module;
if(!importedModule || !importedModule.meta || !importedModule.meta.harmonyModule) {
const importedModule = this._module;
if (!importedModule) {
return;
}
if(!this.id) {
if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
// It's not an harmony module
if (
this.originModule.buildMeta.strictHarmonyModule &&
this._id !== "default"
) {
// In strict harmony modules we only support the default export
const exportName = this._id
? `the named export '${this._id}'`
: "the namespace object";
return [
new HarmonyLinkingError(
`Can't import ${exportName} from non EcmaScript module (only default export is available)`
)
];
}
return;
}
if(importedModule.isProvided(this.id) !== false) {
if (!this._id) {
return;
}
const idIsNotNameMessage = this.id !== this.name ? ` (imported as '${this.name}')` : "";
const errorMessage = `"export '${this.id}'${idIsNotNameMessage} was not found in '${this.importDependency.userRequest}'`;
const err = new Error(errorMessage);
err.hideStack = true;
return [err];
if (importedModule.isProvided(this._id) !== false) {
// It's provided or we are not sure
return;
}
// We are sure that it's not provided
const idIsNotNameMessage =
this._id !== this.name ? ` (imported as '${this.name}')` : "";
const errorMessage = `"export '${
this._id
}'${idIsNotNameMessage} was not found in '${this.userRequest}'`;
return [new HarmonyLinkingError(errorMessage)];
}
// implement this method to allow the occurrence order plugin to count correctly
getNumberOfIdOccurrences() {
return 0;
}
updateHash(hash) {
super.updateHash(hash);
const importedModule = this.importDependency.module;
hash.update((importedModule && importedModule.id) + "");
hash.update((importedModule && this.id) + "");
hash.update((importedModule && this.importedVar) + "");
hash.update((importedModule && this.id && importedModule.isUsed(this.id)) + "");
hash.update((importedModule && (!importedModule.meta || importedModule.meta.harmonyModule)) + "");
hash.update((importedModule && (importedModule.used + JSON.stringify(importedModule.usedExports))) + "");
const importedModule = this._module;
hash.update((importedModule && this._id) + "");
hash.update(
(importedModule && this._id && importedModule.isUsed(this._id)) + ""
);
hash.update(
(importedModule &&
(!importedModule.buildMeta || importedModule.buildMeta.exportsType)) +
""
);
hash.update(
(importedModule &&
importedModule.used + JSON.stringify(importedModule.usedExports)) + ""
);
}
disconnect() {
super.disconnect();
this.redirectedId = undefined;
}
}
HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependencyTemplate {
apply(dep, source) {
const content = this.getContent(dep);
HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependencyTemplate extends HarmonyImportDependency.Template {
apply(dep, source, runtime) {
super.apply(dep, source, runtime);
const content = this.getContent(dep, runtime);
source.replace(dep.range[0], dep.range[1] - 1, content);
}
getContent(dep) {
const importedModule = dep.importDependency.module;
const defaultImport = dep.directImport && dep.id === "default" && !(importedModule && (!importedModule.meta || importedModule.meta.harmonyModule));
const shortHandPrefix = this.getShortHandPrefix(dep);
const importedVar = dep.importedVar;
const importedVarSuffix = this.getImportVarSuffix(dep, defaultImport, importedModule);
if(dep.call && defaultImport) {
return `${shortHandPrefix}${importedVar}_default()`;
}
if(dep.call && dep.id) {
return `${shortHandPrefix}Object(${importedVar}${importedVarSuffix})`;
}
return `${shortHandPrefix}${importedVar}${importedVarSuffix}`;
}
getImportVarSuffix(dep, defaultImport, importedModule) {
if(defaultImport) {
return "_default.a";
}
if(dep.id) {
const used = importedModule ? importedModule.isUsed(dep.id) : dep.id;
const optionalComment = dep.id !== used ? " /* " + dep.id + " */" : "";
return `[${JSON.stringify(used)}${optionalComment}]`;
}
return "";
}
getShortHandPrefix(dep) {
if(!dep.shorthand) {
return "";
}
return dep.name + ": ";
getContent(dep, runtime) {
const exportExpr = runtime.exportFromImport({
module: dep._module,
request: dep.request,
exportName: dep._id,
originModule: dep.originModule,
asiSafe: dep.shorthand,
isCall: dep.call,
callContext: !dep.directImport,
importVar: dep.getImportVar()
});
return dep.shorthand ? `${dep.name}: ${exportExpr}` : exportExpr;
}
};
-32
View File
@@ -1,32 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
class HarmonyModulesHelpers {
static getModuleVar(state, request) {
if(!state.harmonyModules) state.harmonyModules = [];
let idx = state.harmonyModules.indexOf(request);
if(idx < 0) {
idx = state.harmonyModules.length;
state.harmonyModules.push(request);
}
return `__WEBPACK_IMPORTED_MODULE_${idx}_${request.replace(/[^A-Za-z0-9_]/g, "_").replace(/__+/g, "_")}__`;
}
static getNewModuleVar(state, request) {
if(state.harmonyModules && state.harmonyModules.indexOf(request) >= 0)
return null;
return this.getModuleVar(state, request);
}
static checkModuleVar(state, request) {
if(!state.harmonyModules || state.harmonyModules.indexOf(request) < 0)
return null;
return this.getModuleVar(state, request);
}
}
module.exports = HarmonyModulesHelpers;
+114 -43
View File
@@ -3,9 +3,10 @@
Author Tobias Koppers @sokra
*/
"use strict";
const HarmonyImportDependency = require("./HarmonyImportDependency");
const HarmonyCompatibilityDependency = require("./HarmonyCompatibilityDependency");
const HarmonyInitDependency = require("./HarmonyInitDependency");
const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
const HarmonyCompatiblilityDependency = require("./HarmonyCompatibilityDependency");
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency");
const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency");
const HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency");
@@ -18,6 +19,7 @@ const NullFactory = require("../NullFactory");
const HarmonyDetectionParserPlugin = require("./HarmonyDetectionParserPlugin");
const HarmonyImportDependencyParserPlugin = require("./HarmonyImportDependencyParserPlugin");
const HarmonyExportDependencyParserPlugin = require("./HarmonyExportDependencyParserPlugin");
const HarmonyTopLevelThisParserPlugin = require("./HarmonyTopLevelThisParserPlugin");
class HarmonyModulesPlugin {
constructor(options) {
@@ -25,48 +27,117 @@ class HarmonyModulesPlugin {
}
apply(compiler) {
compiler.plugin("compilation", (compilation, params) => {
const normalModuleFactory = params.normalModuleFactory;
compilation.dependencyFactories.set(HarmonyImportDependency, normalModuleFactory);
compilation.dependencyTemplates.set(HarmonyImportDependency, new HarmonyImportDependency.Template());
compilation.dependencyFactories.set(HarmonyImportSpecifierDependency, new NullFactory());
compilation.dependencyTemplates.set(HarmonyImportSpecifierDependency, new HarmonyImportSpecifierDependency.Template());
compilation.dependencyFactories.set(HarmonyCompatiblilityDependency, new NullFactory());
compilation.dependencyTemplates.set(HarmonyCompatiblilityDependency, new HarmonyCompatiblilityDependency.Template());
compilation.dependencyFactories.set(HarmonyExportHeaderDependency, new NullFactory());
compilation.dependencyTemplates.set(HarmonyExportHeaderDependency, new HarmonyExportHeaderDependency.Template());
compilation.dependencyFactories.set(HarmonyExportExpressionDependency, new NullFactory());
compilation.dependencyTemplates.set(HarmonyExportExpressionDependency, new HarmonyExportExpressionDependency.Template());
compilation.dependencyFactories.set(HarmonyExportSpecifierDependency, new NullFactory());
compilation.dependencyTemplates.set(HarmonyExportSpecifierDependency, new HarmonyExportSpecifierDependency.Template());
compilation.dependencyFactories.set(HarmonyExportImportedSpecifierDependency, new NullFactory());
compilation.dependencyTemplates.set(HarmonyExportImportedSpecifierDependency, new HarmonyExportImportedSpecifierDependency.Template());
compilation.dependencyFactories.set(HarmonyAcceptDependency, new NullFactory());
compilation.dependencyTemplates.set(HarmonyAcceptDependency, new HarmonyAcceptDependency.Template());
compilation.dependencyFactories.set(HarmonyAcceptImportDependency, normalModuleFactory);
compilation.dependencyTemplates.set(HarmonyAcceptImportDependency, new HarmonyAcceptImportDependency.Template());
params.normalModuleFactory.plugin("parser", (parser, parserOptions) => {
if(typeof parserOptions.harmony !== "undefined" && !parserOptions.harmony)
return;
parser.apply(
new HarmonyDetectionParserPlugin(),
new HarmonyImportDependencyParserPlugin(this.options),
new HarmonyExportDependencyParserPlugin()
compiler.hooks.compilation.tap(
"HarmonyModulesPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
HarmonyCompatibilityDependency,
new NullFactory()
);
});
});
compilation.dependencyTemplates.set(
HarmonyCompatibilityDependency,
new HarmonyCompatibilityDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyInitDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
HarmonyInitDependency,
new HarmonyInitDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyImportSideEffectDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HarmonyImportSideEffectDependency,
new HarmonyImportSideEffectDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyImportSpecifierDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HarmonyImportSpecifierDependency,
new HarmonyImportSpecifierDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyExportHeaderDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
HarmonyExportHeaderDependency,
new HarmonyExportHeaderDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyExportExpressionDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
HarmonyExportExpressionDependency,
new HarmonyExportExpressionDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyExportSpecifierDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
HarmonyExportSpecifierDependency,
new HarmonyExportSpecifierDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyExportImportedSpecifierDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HarmonyExportImportedSpecifierDependency,
new HarmonyExportImportedSpecifierDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyAcceptDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
HarmonyAcceptDependency,
new HarmonyAcceptDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyAcceptImportDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HarmonyAcceptImportDependency,
new HarmonyAcceptImportDependency.Template()
);
const handler = (parser, parserOptions) => {
if (parserOptions.harmony !== undefined && !parserOptions.harmony)
return;
new HarmonyDetectionParserPlugin().apply(parser);
new HarmonyImportDependencyParserPlugin(this.options).apply(parser);
new HarmonyExportDependencyParserPlugin(this.options).apply(parser);
new HarmonyTopLevelThisParserPlugin().apply(parser);
};
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("HarmonyModulesPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("HarmonyModulesPlugin", handler);
}
);
}
}
module.exports = HarmonyModulesPlugin;
+3 -5
View File
@@ -7,17 +7,15 @@ const ContextDependency = require("./ContextDependency");
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
class ImportContextDependency extends ContextDependency {
constructor(request, recursive, regExp, range, valueRange, chunkName) {
super(request, recursive, regExp);
constructor(options, range, valueRange) {
super(options);
this.range = range;
this.valueRange = valueRange;
this.chunkName = chunkName;
}
get type() {
return "import() context";
return `import() context ${this.options.mode}`;
}
}
ImportContextDependency.Template = ContextDependencyTemplateAsRequireCall;
+4 -3
View File
@@ -7,10 +7,11 @@ const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
const ImportDependency = require("./ImportDependency");
module.exports = class ImportDependenciesBlock extends AsyncDependenciesBlock {
constructor(request, range, chunkName, module, loc) {
super(chunkName, module, loc);
// TODO webpack 5 reorganize arguments
constructor(request, range, groupOptions, module, loc, originModule) {
super(groupOptions, module, loc, request);
this.range = range;
const dep = new ImportDependency(request, this);
const dep = new ImportDependency(request, originModule, this);
dep.loc = loc;
this.addDependency(dep);
}
+11 -31
View File
@@ -4,12 +4,11 @@
*/
"use strict";
const ModuleDependency = require("./ModuleDependency");
const DepBlockHelpers = require("./DepBlockHelpers");
const webpackMissingPromiseModule = require("./WebpackMissingModule").promise;
class ImportDependency extends ModuleDependency {
constructor(request, block) {
constructor(request, originModule, block) {
super(request);
this.originModule = originModule;
this.block = block;
}
@@ -19,35 +18,16 @@ class ImportDependency extends ModuleDependency {
}
ImportDependency.Template = class ImportDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
const depBlock = dep.block;
const promise = DepBlockHelpers.getDepBlockPromise(depBlock, outputOptions, requestShortener, "import()");
const comment = this.getOptionalComment(outputOptions.pathinfo, requestShortener.shorten(dep.request));
apply(dep, source, runtime) {
const content = runtime.moduleNamespacePromise({
block: dep.block,
module: dep.module,
request: dep.request,
strict: dep.originModule.buildMeta.strictHarmonyModule,
message: "import()"
});
const content = this.getContent(promise, dep, comment);
source.replace(depBlock.range[0], depBlock.range[1] - 1, content);
}
getOptionalComment(pathinfo, shortenedRequest) {
if(!pathinfo) {
return "";
}
return `/*! ${shortenedRequest} */ `;
}
getContent(promise, dep, comment) {
if(promise && dep.module) {
const stringifiedId = JSON.stringify(dep.module.id);
return `${promise}.then(__webpack_require__.bind(null, ${comment}${stringifiedId}))`;
}
if(dep.module) {
const stringifiedId = JSON.stringify(dep.module.id);
return `new Promise(function(resolve) { resolve(__webpack_require__(${comment}${stringifiedId})); })`;
}
return webpackMissingPromiseModule(dep.request);
source.replace(dep.block.range[0], dep.block.range[1] - 1, content);
}
};
-22
View File
@@ -1,22 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const ImportContextDependency = require("./ImportContextDependency");
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
class ImportEagerContextDependency extends ImportContextDependency {
constructor(request, recursive, regExp, range, valueRange, chunkName) {
super(request, recursive, regExp, range, valueRange, chunkName);
this.async = "eager";
}
get type() {
return "import() context eager";
}
}
ImportEagerContextDependency.Template = ContextDependencyTemplateAsRequireCall;
module.exports = ImportEagerContextDependency;
+10 -24
View File
@@ -4,43 +4,29 @@
*/
"use strict";
const ModuleDependency = require("./ModuleDependency");
const webpackMissingPromiseModule = require("./WebpackMissingModule").promise;
class ImportEagerDependency extends ModuleDependency {
constructor(request, range) {
constructor(request, originModule, range) {
super(request);
this.originModule = originModule;
this.range = range;
}
get type() {
return "import()";
return "import() eager";
}
}
ImportEagerDependency.Template = class ImportEagerDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
const comment = this.getOptionalComment(outputOptions.pathinfo, requestShortener.shorten(dep.request));
const content = this.getContent(dep, comment);
apply(dep, source, runtime) {
const content = runtime.moduleNamespacePromise({
module: dep.module,
request: dep.request,
strict: dep.originModule.buildMeta.strictHarmonyModule,
message: "import() eager"
});
source.replace(dep.range[0], dep.range[1] - 1, content);
}
getOptionalComment(pathinfo, shortenedRequest) {
if(!pathinfo) {
return "";
}
return `/*! ${shortenedRequest} */ `;
}
getContent(dep, comment) {
if(dep.module) {
const stringifiedId = JSON.stringify(dep.module.id);
return `new Promise(function(resolve) { resolve(__webpack_require__(${comment}${stringifiedId})); })`;
}
return webpackMissingPromiseModule(dep.request);
}
};
module.exports = ImportEagerDependency;
-22
View File
@@ -1,22 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const ImportContextDependency = require("./ImportContextDependency");
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
class ImportLazyContextDependency extends ImportContextDependency {
constructor(request, recursive, regExp, range, valueRange, chunkName) {
super(request, recursive, regExp, range, valueRange, chunkName);
this.async = "lazy";
}
get type() {
return "import() context lazy";
}
}
ImportLazyContextDependency.Template = ContextDependencyTemplateAsRequireCall;
module.exports = ImportLazyContextDependency;
@@ -1,22 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const ImportContextDependency = require("./ImportContextDependency");
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
class ImportLazyOnceContextDependency extends ImportContextDependency {
constructor(request, recursive, regExp, range, valueRange, chunkName) {
super(request, recursive, regExp, range, valueRange, chunkName);
this.async = "lazy-once";
}
get type() {
return "import() context lazy-once";
}
}
ImportLazyOnceContextDependency.Template = ContextDependencyTemplateAsRequireCall;
module.exports = ImportLazyOnceContextDependency;
+216 -41
View File
@@ -4,15 +4,13 @@
*/
"use strict";
const ImportEagerContextDependency = require("./ImportEagerContextDependency");
const ImportContextDependency = require("./ImportContextDependency");
const ImportWeakDependency = require("./ImportWeakDependency");
const ImportWeakContextDependency = require("./ImportWeakContextDependency");
const ImportLazyOnceContextDependency = require("./ImportLazyOnceContextDependency");
const ImportLazyContextDependency = require("./ImportLazyContextDependency");
const ImportDependenciesBlock = require("./ImportDependenciesBlock");
const ImportEagerDependency = require("./ImportEagerDependency");
const ContextDependencyHelpers = require("./ContextDependencyHelpers");
const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
const CommentCompilationWarning = require("../CommentCompilationWarning");
class ImportParserPlugin {
constructor(options) {
@@ -20,64 +18,240 @@ class ImportParserPlugin {
}
apply(parser) {
const options = this.options;
parser.plugin(["call System.import", "import-call"], (expr) => {
if(expr.arguments.length !== 1)
throw new Error("Incorrect number of arguments provided to 'import(module: string) -> Promise'.");
parser.hooks.importCall.tap("ImportParserPlugin", expr => {
if (expr.arguments.length !== 1) {
throw new Error(
"Incorrect number of arguments provided to 'import(module: string) -> Promise'."
);
}
const param = parser.evaluateExpression(expr.arguments[0]);
let chunkName = null;
let mode = "lazy";
let include = null;
let exclude = null;
const groupOptions = {};
const importOptions = parser.getCommentOptions(expr.range);
if(importOptions) {
if(typeof importOptions.webpackChunkName !== "undefined") {
if(typeof importOptions.webpackChunkName !== "string")
parser.state.module.warnings.push(new UnsupportedFeatureWarning(parser.state.module, `\`webpackChunkName\` expected a string, but received: ${importOptions.webpackChunkName}.`));
else
chunkName = importOptions.webpackChunkName;
}
if(typeof importOptions.webpackMode !== "undefined") {
if(typeof importOptions.webpackMode !== "string")
parser.state.module.warnings.push(new UnsupportedFeatureWarning(parser.state.module, `\`webpackMode\` expected a string, but received: ${importOptions.webpackMode}.`));
else
mode = importOptions.webpackMode;
const {
options: importOptions,
errors: commentErrors
} = parser.parseCommentOptions(expr.range);
if (commentErrors) {
for (const e of commentErrors) {
const { comment } = e;
parser.state.module.warnings.push(
new CommentCompilationWarning(
`Compilation error while processing magic comment(-s): /*${
comment.value
}*/: ${e.message}`,
parser.state.module,
comment.loc
)
);
}
}
if(param.isString()) {
if(mode !== "lazy" && mode !== "eager" && mode !== "weak") {
parser.state.module.warnings.push(new UnsupportedFeatureWarning(parser.state.module, `\`webpackMode\` expected 'lazy', 'eager' or 'weak', but received: ${mode}.`));
if (importOptions) {
if (importOptions.webpackIgnore !== undefined) {
if (typeof importOptions.webpackIgnore !== "boolean") {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackIgnore\` expected a boolean, but received: ${
importOptions.webpackIgnore
}.`,
expr.loc
)
);
} else {
// Do not instrument `import()` if `webpackIgnore` is `true`
if (importOptions.webpackIgnore) {
return false;
}
}
}
if (importOptions.webpackChunkName !== undefined) {
if (typeof importOptions.webpackChunkName !== "string") {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackChunkName\` expected a string, but received: ${
importOptions.webpackChunkName
}.`,
expr.loc
)
);
} else {
chunkName = importOptions.webpackChunkName;
}
}
if (importOptions.webpackMode !== undefined) {
if (typeof importOptions.webpackMode !== "string") {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackMode\` expected a string, but received: ${
importOptions.webpackMode
}.`,
expr.loc
)
);
} else {
mode = importOptions.webpackMode;
}
}
if (importOptions.webpackPrefetch !== undefined) {
if (importOptions.webpackPrefetch === true) {
groupOptions.prefetchOrder = 0;
} else if (typeof importOptions.webpackPrefetch === "number") {
groupOptions.prefetchOrder = importOptions.webpackPrefetch;
} else {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackPrefetch\` expected true or a number, but received: ${
importOptions.webpackPrefetch
}.`,
expr.loc
)
);
}
}
if (importOptions.webpackPreload !== undefined) {
if (importOptions.webpackPreload === true) {
groupOptions.preloadOrder = 0;
} else if (typeof importOptions.webpackPreload === "number") {
groupOptions.preloadOrder = importOptions.webpackPreload;
} else {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackPreload\` expected true or a number, but received: ${
importOptions.webpackPreload
}.`,
expr.loc
)
);
}
}
if (importOptions.webpackInclude !== undefined) {
if (
!importOptions.webpackInclude ||
importOptions.webpackInclude.constructor.name !== "RegExp"
) {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackInclude\` expected a regular expression, but received: ${
importOptions.webpackInclude
}.`,
expr.loc
)
);
} else {
include = new RegExp(importOptions.webpackInclude);
}
}
if (importOptions.webpackExclude !== undefined) {
if (
!importOptions.webpackExclude ||
importOptions.webpackExclude.constructor.name !== "RegExp"
) {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackExclude\` expected a regular expression, but received: ${
importOptions.webpackExclude
}.`,
expr.loc
)
);
} else {
exclude = new RegExp(importOptions.webpackExclude);
}
}
}
if (param.isString()) {
if (mode !== "lazy" && mode !== "eager" && mode !== "weak") {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackMode\` expected 'lazy', 'eager' or 'weak', but received: ${mode}.`,
expr.loc
)
);
}
if(mode === "eager") {
const dep = new ImportEagerDependency(param.string, expr.range);
if (mode === "eager") {
const dep = new ImportEagerDependency(
param.string,
parser.state.module,
expr.range
);
parser.state.current.addDependency(dep);
} else if(mode === "weak") {
const dep = new ImportWeakDependency(param.string, expr.range);
} else if (mode === "weak") {
const dep = new ImportWeakDependency(
param.string,
parser.state.module,
expr.range
);
parser.state.current.addDependency(dep);
} else {
const depBlock = new ImportDependenciesBlock(param.string, expr.range, chunkName, parser.state.module, expr.loc);
const depBlock = new ImportDependenciesBlock(
param.string,
expr.range,
Object.assign(groupOptions, {
name: chunkName
}),
parser.state.module,
expr.loc,
parser.state.module
);
parser.state.current.addBlock(depBlock);
}
return true;
} else {
if(mode !== "lazy" && mode !== "lazy-once" && mode !== "eager" && mode !== "weak") {
parser.state.module.warnings.push(new UnsupportedFeatureWarning(parser.state.module, `\`webpackMode\` expected 'lazy', 'lazy-once', 'eager' or 'weak', but received: ${mode}.`));
if (
mode !== "lazy" &&
mode !== "lazy-once" &&
mode !== "eager" &&
mode !== "weak"
) {
parser.state.module.warnings.push(
new UnsupportedFeatureWarning(
parser.state.module,
`\`webpackMode\` expected 'lazy', 'lazy-once', 'eager' or 'weak', but received: ${mode}.`,
expr.loc
)
);
mode = "lazy";
}
let Dep = ImportLazyContextDependency;
if(mode === "eager") {
Dep = ImportEagerContextDependency;
} else if(mode === "weak") {
Dep = ImportWeakContextDependency;
} else if(mode === "lazy-once") {
Dep = ImportLazyOnceContextDependency;
if (mode === "weak") {
mode = "async-weak";
}
const dep = ContextDependencyHelpers.create(Dep, expr.range, param, expr, options, chunkName);
if(!dep) return;
const dep = ContextDependencyHelpers.create(
ImportContextDependency,
expr.range,
param,
expr,
this.options,
{
chunkName,
groupOptions,
include,
exclude,
mode,
namespaceObject: parser.state.module.buildMeta.strictHarmonyModule
? "strict"
: true
},
parser
);
if (!dep) return;
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
@@ -86,4 +260,5 @@ class ImportParserPlugin {
});
}
}
module.exports = ImportParserPlugin;
+57 -38
View File
@@ -7,10 +7,7 @@
const ImportDependency = require("./ImportDependency");
const ImportEagerDependency = require("./ImportEagerDependency");
const ImportWeakDependency = require("./ImportWeakDependency");
const ImportEagerContextDependency = require("./ImportEagerContextDependency");
const ImportWeakContextDependency = require("./ImportWeakContextDependency");
const ImportLazyOnceContextDependency = require("./ImportLazyOnceContextDependency");
const ImportLazyContextDependency = require("./ImportLazyContextDependency");
const ImportContextDependency = require("./ImportContextDependency");
const ImportParserPlugin = require("./ImportParserPlugin");
class ImportPlugin {
@@ -20,41 +17,63 @@ class ImportPlugin {
apply(compiler) {
const options = this.options;
compiler.plugin("compilation", (compilation, params) => {
const normalModuleFactory = params.normalModuleFactory;
const contextModuleFactory = params.contextModuleFactory;
compilation.dependencyFactories.set(ImportDependency, normalModuleFactory);
compilation.dependencyTemplates.set(ImportDependency, new ImportDependency.Template());
compilation.dependencyFactories.set(ImportEagerDependency, normalModuleFactory);
compilation.dependencyTemplates.set(ImportEagerDependency, new ImportEagerDependency.Template());
compilation.dependencyFactories.set(ImportWeakDependency, normalModuleFactory);
compilation.dependencyTemplates.set(ImportWeakDependency, new ImportWeakDependency.Template());
compilation.dependencyFactories.set(ImportEagerContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(ImportEagerContextDependency, new ImportEagerContextDependency.Template());
compilation.dependencyFactories.set(ImportWeakContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(ImportWeakContextDependency, new ImportWeakContextDependency.Template());
compilation.dependencyFactories.set(ImportLazyOnceContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(ImportLazyOnceContextDependency, new ImportLazyOnceContextDependency.Template());
compilation.dependencyFactories.set(ImportLazyContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(ImportLazyContextDependency, new ImportLazyContextDependency.Template());
normalModuleFactory.plugin("parser", (parser, parserOptions) => {
if(typeof parserOptions.import !== "undefined" && !parserOptions.import)
return;
parser.apply(
new ImportParserPlugin(options)
compiler.hooks.compilation.tap(
"ImportPlugin",
(compilation, { contextModuleFactory, normalModuleFactory }) => {
compilation.dependencyFactories.set(
ImportDependency,
normalModuleFactory
);
});
});
compilation.dependencyTemplates.set(
ImportDependency,
new ImportDependency.Template()
);
compilation.dependencyFactories.set(
ImportEagerDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
ImportEagerDependency,
new ImportEagerDependency.Template()
);
compilation.dependencyFactories.set(
ImportWeakDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
ImportWeakDependency,
new ImportWeakDependency.Template()
);
compilation.dependencyFactories.set(
ImportContextDependency,
contextModuleFactory
);
compilation.dependencyTemplates.set(
ImportContextDependency,
new ImportContextDependency.Template()
);
const handler = (parser, parserOptions) => {
if (parserOptions.import !== undefined && !parserOptions.import)
return;
new ImportParserPlugin(options).apply(parser);
};
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("ImportPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("ImportPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("ImportPlugin", handler);
}
);
}
}
module.exports = ImportPlugin;
-22
View File
@@ -1,22 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const ImportContextDependency = require("./ImportContextDependency");
const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall");
class ImportWeakContextDependency extends ImportContextDependency {
constructor(request, recursive, regExp, range, valueRange, chunkName) {
super(request, recursive, regExp, range, valueRange, chunkName);
this.async = "async-weak";
}
get type() {
return "import() context weak";
}
}
ImportWeakContextDependency.Template = ContextDependencyTemplateAsRequireCall;
module.exports = ImportWeakContextDependency;
+10 -23
View File
@@ -4,11 +4,11 @@
*/
"use strict";
const ModuleDependency = require("./ModuleDependency");
const webpackMissingPromiseModule = require("./WebpackMissingModule").promise;
class ImportWeakDependency extends ModuleDependency {
constructor(request, range) {
constructor(request, originModule, range) {
super(request);
this.originModule = originModule;
this.range = range;
this.weak = true;
}
@@ -19,29 +19,16 @@ class ImportWeakDependency extends ModuleDependency {
}
ImportWeakDependency.Template = class ImportDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
const comment = this.getOptionalComment(outputOptions.pathinfo, requestShortener.shorten(dep.request));
const content = this.getContent(dep, comment);
apply(dep, source, runtime) {
const content = runtime.moduleNamespacePromise({
module: dep.module,
request: dep.request,
strict: dep.originModule.buildMeta.strictHarmonyModule,
message: "import() weak",
weak: true
});
source.replace(dep.range[0], dep.range[1] - 1, content);
}
getOptionalComment(pathinfo, shortenedRequest) {
if(!pathinfo) {
return "";
}
return `/*! ${shortenedRequest} */ `;
}
getContent(dep, comment) {
if(dep.module) {
const stringifiedId = JSON.stringify(dep.module.id);
return `Promise.resolve(${comment}${stringifiedId}).then(function(id) { if(!__webpack_require__.m[id]) throw new Error("Module '" + id + "' is not available (weak dependency)"); return __webpack_require__(id); })`;
}
return webpackMissingPromiseModule(dep.request);
}
};
module.exports = ImportWeakDependency;
+3
View File
@@ -6,6 +6,9 @@
const ModuleDependency = require("./ModuleDependency");
class LoaderDependency extends ModuleDependency {
/**
* @param {string} request request string
*/
constructor(request) {
super(request);
}
+101 -44
View File
@@ -5,55 +5,112 @@
"use strict";
const LoaderDependency = require("./LoaderDependency");
const NormalModule = require("../NormalModule");
/** @typedef {import("../Module")} Module */
/**
* @callback LoadModuleCallback
* @param {Error=} err error object
* @param {string=} source source code
* @param {object=} map source map
* @param {Module=} module loaded module if successful
*/
class LoaderPlugin {
apply(compiler) {
compiler.plugin("compilation", (compilation, params) => {
const normalModuleFactory = params.normalModuleFactory;
compiler.hooks.compilation.tap(
"LoaderPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
LoaderDependency,
normalModuleFactory
);
}
);
compilation.dependencyFactories.set(LoaderDependency, normalModuleFactory);
});
compiler.plugin("compilation", (compilation) => {
compilation.plugin("normal-module-loader", (loaderContext, module) => {
loaderContext.loadModule = function loadModule(request, callback) {
const dep = new LoaderDependency(request);
dep.loc = request;
compilation.addModuleDependencies(module, [
[dep]
], true, "lm", false, (err) => {
if(err) return callback(err);
if(!dep.module) return callback(new Error("Cannot load the module"));
if(dep.module.building) dep.module.building.push(next);
else next();
function next(err) {
if(err) return callback(err);
if(dep.module.error) return callback(dep.module.error);
if(!dep.module._source) throw new Error("The module created for a LoaderDependency must have a property _source");
let source, map;
const moduleSource = dep.module._source;
if(moduleSource.sourceAndMap) {
const sourceAndMap = moduleSource.sourceAndMap();
map = sourceAndMap.map;
source = sourceAndMap.source;
} else {
map = moduleSource.map();
source = moduleSource.source();
}
if(dep.module.fileDependencies) {
dep.module.fileDependencies.forEach((dep) => loaderContext.addDependency(dep));
}
if(dep.module.contextDependencies) {
dep.module.contextDependencies.forEach((dep) => loaderContext.addContextDependency(dep));
}
return callback(null, source, map, dep.module);
compiler.hooks.compilation.tap("LoaderPlugin", compilation => {
compilation.hooks.normalModuleLoader.tap(
"LoaderPlugin",
(loaderContext, module) => {
/**
* @param {string} request the request string to load the module from
* @param {LoadModuleCallback} callback callback returning the loaded module or error
* @returns {void}
*/
loaderContext.loadModule = (request, callback) => {
const dep = new LoaderDependency(request);
dep.loc = {
name: request
};
const factory = compilation.dependencyFactories.get(
dep.constructor
);
if (factory === undefined) {
return callback(
new Error(
`No module factory available for dependency type: ${
dep.constructor.name
}`
)
);
}
});
};
});
compilation.semaphore.release();
compilation.addModuleDependencies(
module,
[
{
factory,
dependencies: [dep]
}
],
true,
"lm",
true,
err => {
compilation.semaphore.acquire(() => {
if (err) {
return callback(err);
}
if (!dep.module) {
return callback(new Error("Cannot load the module"));
}
// TODO consider removing this in webpack 5
if (dep.module instanceof NormalModule && dep.module.error) {
return callback(dep.module.error);
}
if (!dep.module._source) {
throw new Error(
"The module created for a LoaderDependency must have a property _source"
);
}
let source, map;
const moduleSource = dep.module._source;
if (moduleSource.sourceAndMap) {
const sourceAndMap = moduleSource.sourceAndMap();
map = sourceAndMap.map;
source = sourceAndMap.source;
} else {
map = moduleSource.map();
source = moduleSource.source();
}
if (dep.module.buildInfo.fileDependencies) {
for (const d of dep.module.buildInfo.fileDependencies) {
loaderContext.addDependency(d);
}
}
if (dep.module.buildInfo.contextDependencies) {
for (const d of dep.module.buildInfo.contextDependencies) {
loaderContext.addContextDependency(d);
}
}
return callback(null, source, map, dep.module);
});
}
);
};
}
);
});
}
}
+7 -3
View File
@@ -6,18 +6,22 @@
const NullDependency = require("./NullDependency");
class LocalModuleDependency extends NullDependency {
constructor(localModule, range) {
constructor(localModule, range, callNew) {
super();
localModule.flagUsed();
this.localModule = localModule;
this.range = range;
this.callNew = callNew;
}
}
LocalModuleDependency.Template = class LocalModuleDependencyTemplate {
apply(dep, source) {
if(!dep.range) return;
source.replace(dep.range[0], dep.range[1] - 1, dep.localModule.variableName());
if (!dep.range) return;
const moduleInstance = dep.callNew
? `new (function () { return ${dep.localModule.variableName()}; })()`
: dep.localModule.variableName();
source.replace(dep.range[0], dep.range[1] - 1, moduleInstance);
}
};
+17 -11
View File
@@ -8,37 +8,43 @@ const LocalModule = require("./LocalModule");
const LocalModulesHelpers = exports;
const lookup = (parent, mod) => {
if(mod.charAt(0) !== ".") return mod;
if (mod.charAt(0) !== ".") return mod;
var path = parent.split("/"),
segs = mod.split("/");
var path = parent.split("/");
var segs = mod.split("/");
path.pop();
for(let i = 0; i < segs.length; i++) {
for (let i = 0; i < segs.length; i++) {
const seg = segs[i];
if(seg === "..") path.pop();
else if(seg !== ".") path.push(seg);
if (seg === "..") {
path.pop();
} else if (seg !== ".") {
path.push(seg);
}
}
return path.join("/");
};
LocalModulesHelpers.addLocalModule = (state, name) => {
if(!state.localModules) state.localModules = [];
if (!state.localModules) {
state.localModules = [];
}
const m = new LocalModule(state.module, name, state.localModules.length);
state.localModules.push(m);
return m;
};
LocalModulesHelpers.getLocalModule = (state, name, namedModule) => {
if(!state.localModules) return null;
if(namedModule) {
if (!state.localModules) return null;
if (namedModule) {
// resolve dependency name relative to the defining named module
name = lookup(namedModule, name);
}
for(let i = 0; i < state.localModules.length; i++) {
if(state.localModules[i].name === name)
for (let i = 0; i < state.localModules.length; i++) {
if (state.localModules[i].name === name) {
return state.localModules[i];
}
}
return null;
};
+5 -5
View File
@@ -6,17 +6,17 @@
const Dependency = require("../Dependency");
class ModuleDependency extends Dependency {
/**
* @param {string} request request path which needs resolving
*/
constructor(request) {
super();
this.request = request;
this.userRequest = request;
}
isEqualResource(other) {
if(!(other instanceof ModuleDependency))
return false;
return this.request === other.request;
getResourceIdentifier() {
return `module${this.request}`;
}
}
+6 -10
View File
@@ -5,16 +5,12 @@
"use strict";
class ModuleDependencyTemplateAsId {
apply(dep, source, outputOptions, requestShortener) {
if(!dep.range) return;
const comment = outputOptions.pathinfo ?
`/*! ${requestShortener.shorten(dep.request)} */ ` : "";
let content;
if(dep.module)
content = comment + JSON.stringify(dep.module.id);
else
content = require("./WebpackMissingModule").module(dep.request);
apply(dep, source, runtime) {
if (!dep.range) return;
const content = runtime.moduleId({
module: dep.module,
request: dep.request
});
source.replace(dep.range[0], dep.range[1] - 1, content);
}
}
@@ -5,16 +5,12 @@
"use strict";
class ModuleDependencyTemplateAsRequireId {
apply(dep, source, outputOptions, requestShortener) {
if(!dep.range) return;
const comment = outputOptions.pathinfo ?
`/*! ${requestShortener.shorten(dep.request)} */ ` : "";
let content;
if(dep.module)
content = `__webpack_require__(${comment}${JSON.stringify(dep.module.id)})`;
else
content = require("./WebpackMissingModule").module(dep.request);
apply(dep, source, runtime) {
if (!dep.range) return;
const content = runtime.moduleExports({
module: dep.module,
request: dep.request
});
source.replace(dep.range[0], dep.range[1] - 1, content);
}
}
+5
View File
@@ -3,9 +3,14 @@
Author Tobias Koppers @sokra
*/
"use strict";
/** @typedef {import("./SingleEntryDependency")} SingleEntryDependency */
const Dependency = require("../Dependency");
class MultiEntryDependency extends Dependency {
/**
* @param {SingleEntryDependency[]} dependencies an array of SingleEntryDependencies
* @param {string} name entry name
*/
constructor(dependencies, name) {
super();
this.dependencies = dependencies;
-4
View File
@@ -10,10 +10,6 @@ class NullDependency extends Dependency {
return "null";
}
isEqualResource() {
return false;
}
updateHash() {}
}
+2 -6
View File
@@ -7,13 +7,9 @@ const ContextDependency = require("./ContextDependency");
const ModuleDependencyTemplateAsRequireId = require("./ModuleDependencyTemplateAsRequireId");
class RequireContextDependency extends ContextDependency {
constructor(request, recursive, regExp, asyncMode, range) {
super(request, recursive, regExp);
constructor(options, range) {
super(options);
this.range = range;
if(asyncMode) {
this.async = asyncMode;
}
}
get type() {
@@ -8,43 +8,49 @@ const RequireContextDependency = require("./RequireContextDependency");
module.exports = class RequireContextDependencyParserPlugin {
apply(parser) {
parser.plugin("call require.context", expr => {
let regExp = /^\.\/.*$/;
let recursive = true;
let asyncMode;
switch(expr.arguments.length) {
case 4:
{
const asyncModeExpr = parser.evaluateExpression(expr.arguments[3]);
if(!asyncModeExpr.isString()) return;
asyncMode = asyncModeExpr.string;
parser.hooks.call
.for("require.context")
.tap("RequireContextDependencyParserPlugin", expr => {
let regExp = /^\.\/.*$/;
let recursive = true;
let mode = "sync";
switch (expr.arguments.length) {
case 4: {
const modeExpr = parser.evaluateExpression(expr.arguments[3]);
if (!modeExpr.isString()) return;
mode = modeExpr.string;
}
// falls through
case 3:
{
case 3: {
const regExpExpr = parser.evaluateExpression(expr.arguments[2]);
if(!regExpExpr.isRegExp()) return;
if (!regExpExpr.isRegExp()) return;
regExp = regExpExpr.regExp;
}
// falls through
case 2:
{
case 2: {
const recursiveExpr = parser.evaluateExpression(expr.arguments[1]);
if(!recursiveExpr.isBoolean()) return;
if (!recursiveExpr.isBoolean()) return;
recursive = recursiveExpr.bool;
}
// falls through
case 1:
{
case 1: {
const requestExpr = parser.evaluateExpression(expr.arguments[0]);
if(!requestExpr.isString()) return;
const dep = new RequireContextDependency(requestExpr.string, recursive, regExp, asyncMode, expr.range);
if (!requestExpr.isString()) return;
const dep = new RequireContextDependency(
{
request: requestExpr.string,
recursive,
regExp,
mode
},
expr.range
);
dep.loc = expr.loc;
dep.optional = parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
}
});
}
});
}
};
+113 -66
View File
@@ -11,86 +11,133 @@ const RequireContextDependencyParserPlugin = require("./RequireContextDependency
class RequireContextPlugin {
constructor(modulesDirectories, extensions, mainFiles) {
if(!Array.isArray(modulesDirectories))
if (!Array.isArray(modulesDirectories)) {
throw new Error("modulesDirectories must be an array");
if(!Array.isArray(extensions))
}
if (!Array.isArray(extensions)) {
throw new Error("extensions must be an array");
}
this.modulesDirectories = modulesDirectories;
this.extensions = extensions;
this.mainFiles = mainFiles;
}
apply(compiler) {
compiler.plugin("compilation", (compilation, params) => {
const contextModuleFactory = params.contextModuleFactory;
const normalModuleFactory = params.normalModuleFactory;
compiler.hooks.compilation.tap(
"RequireContextPlugin",
(compilation, { contextModuleFactory, normalModuleFactory }) => {
compilation.dependencyFactories.set(
RequireContextDependency,
contextModuleFactory
);
compilation.dependencyTemplates.set(
RequireContextDependency,
new RequireContextDependency.Template()
);
compilation.dependencyFactories.set(RequireContextDependency, contextModuleFactory);
compilation.dependencyTemplates.set(RequireContextDependency, new RequireContextDependency.Template());
compilation.dependencyFactories.set(
ContextElementDependency,
normalModuleFactory
);
compilation.dependencyFactories.set(ContextElementDependency, normalModuleFactory);
const handler = (parser, parserOptions) => {
if (
parserOptions.requireContext !== undefined &&
!parserOptions.requireContext
)
return;
params.normalModuleFactory.plugin("parser", (parser, parserOptions) => {
new RequireContextDependencyParserPlugin().apply(parser);
};
if(typeof parserOptions.requireContext !== "undefined" && !parserOptions.requireContext)
return;
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("RequireContextPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("RequireContextPlugin", handler);
parser.apply(new RequireContextDependencyParserPlugin());
});
params.contextModuleFactory.plugin("alternatives", (items, callback) => {
if(items.length === 0) return callback(null, items);
callback(null, items.map((obj) => {
return this.extensions.filter((ext) => {
const l = obj.request.length;
return l > ext.length && obj.request.substr(l - ext.length, l) === ext;
}).map((ext) => {
const l = obj.request.length;
return {
context: obj.context,
request: obj.request.substr(0, l - ext.length)
};
}).concat(obj);
}).reduce((a, b) => a.concat(b), []));
});
params.contextModuleFactory.plugin("alternatives", (items, callback) => {
if(items.length === 0) return callback(null, items);
callback(null, items.map((obj) => {
return this.mainFiles.filter((mainFile) => {
const l = obj.request.length;
return l > mainFile.length + 1 && obj.request.substr(l - mainFile.length - 1, l) === "/" + mainFile;
}).map((mainFile) => {
const l = obj.request.length;
return [{
context: obj.context,
request: obj.request.substr(0, l - mainFile.length)
}, {
context: obj.context,
request: obj.request.substr(0, l - mainFile.length - 1)
}];
}).reduce((a, b) => a.concat(b), []).concat(obj);
}).reduce((a, b) => a.concat(b), []));
});
params.contextModuleFactory.plugin("alternatives", (items, callback) => {
if(items.length === 0) return callback(null, items);
callback(null, items.map((obj) => {
for(let i = 0; i < this.modulesDirectories.length; i++) {
const dir = this.modulesDirectories[i];
const idx = obj.request.indexOf("./" + dir + "/");
if(idx === 0) {
obj.request = obj.request.slice(dir.length + 3);
break;
}
contextModuleFactory.hooks.alternatives.tap(
"RequireContextPlugin",
items => {
if (items.length === 0) return items;
return items
.map(obj => {
return this.extensions
.filter(ext => {
const l = obj.request.length;
return (
l > ext.length &&
obj.request.substr(l - ext.length, l) === ext
);
})
.map(ext => {
const l = obj.request.length;
return {
context: obj.context,
request: obj.request.substr(0, l - ext.length)
};
})
.concat(obj);
})
.reduce((a, b) => a.concat(b), []);
}
return obj;
}));
});
});
);
contextModuleFactory.hooks.alternatives.tap(
"RequireContextPlugin",
items => {
if (items.length === 0) return items;
return items
.map(obj => {
return this.mainFiles
.filter(mainFile => {
const l = obj.request.length;
return (
l > mainFile.length + 1 &&
obj.request.substr(l - mainFile.length - 1, l) ===
"/" + mainFile
);
})
.map(mainFile => {
const l = obj.request.length;
return [
{
context: obj.context,
request: obj.request.substr(0, l - mainFile.length)
},
{
context: obj.context,
request: obj.request.substr(0, l - mainFile.length - 1)
}
];
})
.reduce((a, b) => a.concat(b), [])
.concat(obj);
})
.reduce((a, b) => a.concat(b), []);
}
);
contextModuleFactory.hooks.alternatives.tap(
"RequireContextPlugin",
items => {
if (items.length === 0) return items;
return items.map(obj => {
for (let i = 0; i < this.modulesDirectories.length; i++) {
const dir = this.modulesDirectories[i];
const idx = obj.request.indexOf("./" + dir + "/");
if (idx === 0) {
obj.request = obj.request.slice(dir.length + 3);
break;
}
}
return obj;
});
}
);
}
);
}
}
module.exports = RequireContextPlugin;
+15 -4
View File
@@ -7,11 +7,22 @@ const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
const RequireEnsureDependency = require("./RequireEnsureDependency");
module.exports = class RequireEnsureDependenciesBlock extends AsyncDependenciesBlock {
constructor(expr, successExpression, errorExpression, chunkName, chunkNameRange, module, loc) {
super(chunkName, module, loc);
constructor(
expr,
successExpression,
errorExpression,
chunkName,
chunkNameRange,
module,
loc
) {
super(chunkName, module, loc, null);
this.expr = expr;
const successBodyRange = successExpression && successExpression.body && successExpression.body.range;
if(successBodyRange) {
const successBodyRange =
successExpression &&
successExpression.body &&
successExpression.body.range;
if (successBodyRange) {
this.range = [successBodyRange[0] + 1, successBodyRange[1] - 1];
}
this.chunkNameRange = chunkNameRange;
@@ -10,93 +10,107 @@ const getFunctionExpression = require("./getFunctionExpression");
module.exports = class RequireEnsureDependenciesBlockParserPlugin {
apply(parser) {
parser.plugin("call require.ensure", expr => {
let chunkName = null;
let chunkNameRange = null;
let errorExpressionArg = null;
let errorExpression = null;
switch(expr.arguments.length) {
case 4:
{
parser.hooks.call
.for("require.ensure")
.tap("RequireEnsureDependenciesBlockParserPlugin", expr => {
let chunkName = null;
let chunkNameRange = null;
let errorExpressionArg = null;
let errorExpression = null;
switch (expr.arguments.length) {
case 4: {
const chunkNameExpr = parser.evaluateExpression(expr.arguments[3]);
if(!chunkNameExpr.isString()) return;
if (!chunkNameExpr.isString()) return;
chunkNameRange = chunkNameExpr.range;
chunkName = chunkNameExpr.string;
}
// falls through
case 3:
{
case 3: {
errorExpressionArg = expr.arguments[2];
errorExpression = getFunctionExpression(errorExpressionArg);
if(!errorExpression && !chunkName) {
const chunkNameExpr = parser.evaluateExpression(expr.arguments[2]);
if(!chunkNameExpr.isString()) return;
if (!errorExpression && !chunkName) {
const chunkNameExpr = parser.evaluateExpression(
expr.arguments[2]
);
if (!chunkNameExpr.isString()) return;
chunkNameRange = chunkNameExpr.range;
chunkName = chunkNameExpr.string;
}
}
// falls through
case 2:
{
const dependenciesExpr = parser.evaluateExpression(expr.arguments[0]);
const dependenciesItems = dependenciesExpr.isArray() ? dependenciesExpr.items : [dependenciesExpr];
case 2: {
const dependenciesExpr = parser.evaluateExpression(
expr.arguments[0]
);
const dependenciesItems = dependenciesExpr.isArray()
? dependenciesExpr.items
: [dependenciesExpr];
const successExpressionArg = expr.arguments[1];
const successExpression = getFunctionExpression(successExpressionArg);
const successExpression = getFunctionExpression(
successExpressionArg
);
if(successExpression) {
if (successExpression) {
parser.walkExpressions(successExpression.expressions);
}
if(errorExpression) {
if (errorExpression) {
parser.walkExpressions(errorExpression.expressions);
}
const dep = new RequireEnsureDependenciesBlock(expr,
const dep = new RequireEnsureDependenciesBlock(
expr,
successExpression ? successExpression.fn : successExpressionArg,
errorExpression ? errorExpression.fn : errorExpressionArg,
chunkName, chunkNameRange, parser.state.module, expr.loc);
chunkName,
chunkNameRange,
parser.state.module,
expr.loc
);
const old = parser.state.current;
parser.state.current = dep;
try {
let failed = false;
parser.inScope([], () => {
dependenciesItems.forEach(ee => {
if(ee.isString()) {
const edep = new RequireEnsureItemDependency(ee.string, ee.range);
for (const ee of dependenciesItems) {
if (ee.isString()) {
const edep = new RequireEnsureItemDependency(ee.string);
edep.loc = dep.loc;
dep.addDependency(edep);
} else {
failed = true;
}
});
}
});
if(failed) {
if (failed) {
return;
}
if(successExpression) {
if(successExpression.fn.body.type === "BlockStatement")
if (successExpression) {
if (successExpression.fn.body.type === "BlockStatement") {
parser.walkStatement(successExpression.fn.body);
else
} else {
parser.walkExpression(successExpression.fn.body);
}
}
old.addBlock(dep);
} finally {
parser.state.current = old;
}
if(!successExpression) {
if (!successExpression) {
parser.walkExpression(successExpressionArg);
}
if(errorExpression) {
if(errorExpression.fn.body.type === "BlockStatement")
if (errorExpression) {
if (errorExpression.fn.body.type === "BlockStatement") {
parser.walkStatement(errorExpression.fn.body);
else
} else {
parser.walkExpression(errorExpression.fn.body);
} else if(errorExpressionArg) {
}
} else if (errorExpressionArg) {
parser.walkExpression(errorExpressionArg);
}
return true;
}
}
});
}
});
}
};
+32 -12
View File
@@ -4,7 +4,6 @@
*/
"use strict";
const NullDependency = require("./NullDependency");
const DepBlockHelpers = require("./DepBlockHelpers");
class RequireEnsureDependency extends NullDependency {
constructor(block) {
@@ -18,19 +17,40 @@ class RequireEnsureDependency extends NullDependency {
}
RequireEnsureDependency.Template = class RequireEnsureDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
apply(dep, source, runtime) {
const depBlock = dep.block;
const wrapper = DepBlockHelpers.getLoadDepBlockWrapper(depBlock, outputOptions, requestShortener, "require.ensure");
const errorCallbackExists = depBlock.expr.arguments.length === 4 || (!depBlock.chunkName && depBlock.expr.arguments.length === 3);
const startBlock = wrapper[0] + "(";
const middleBlock = `).bind(null, __webpack_require__)${wrapper[1]}`;
const endBlock = `${middleBlock}__webpack_require__.oe${wrapper[2]}`;
source.replace(depBlock.expr.range[0], depBlock.expr.arguments[1].range[0] - 1, startBlock);
if(errorCallbackExists) {
source.replace(depBlock.expr.arguments[1].range[1], depBlock.expr.arguments[2].range[0] - 1, middleBlock);
source.replace(depBlock.expr.arguments[2].range[1], depBlock.expr.range[1] - 1, wrapper[2]);
const promise = runtime.blockPromise({
block: depBlock,
message: "require.ensure"
});
const errorCallbackExists =
depBlock.expr.arguments.length === 4 ||
(!depBlock.chunkName && depBlock.expr.arguments.length === 3);
const startBlock = `${promise}.then((`;
const middleBlock = ").bind(null, __webpack_require__)).catch(";
const endBlock = `).bind(null, __webpack_require__)).catch(${runtime.onError()})`;
source.replace(
depBlock.expr.range[0],
depBlock.expr.arguments[1].range[0] - 1,
startBlock
);
if (errorCallbackExists) {
source.replace(
depBlock.expr.arguments[1].range[1],
depBlock.expr.arguments[2].range[0] - 1,
middleBlock
);
source.replace(
depBlock.expr.arguments[2].range[1],
depBlock.expr.range[1] - 1,
")"
);
} else {
source.replace(depBlock.expr.arguments[1].range[1], depBlock.expr.range[1] - 1, endBlock);
source.replace(
depBlock.expr.arguments[1].range[1],
depBlock.expr.range[1] - 1,
endBlock
);
}
}
};
+50 -16
View File
@@ -14,27 +14,61 @@ const RequireEnsureDependenciesBlockParserPlugin = require("./RequireEnsureDepen
const ParserHelpers = require("../ParserHelpers");
class RequireEnsurePlugin {
apply(compiler) {
compiler.plugin("compilation", (compilation, params) => {
const normalModuleFactory = params.normalModuleFactory;
compiler.hooks.compilation.tap(
"RequireEnsurePlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
RequireEnsureItemDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
RequireEnsureItemDependency,
new RequireEnsureItemDependency.Template()
);
compilation.dependencyFactories.set(RequireEnsureItemDependency, normalModuleFactory);
compilation.dependencyTemplates.set(RequireEnsureItemDependency, new RequireEnsureItemDependency.Template());
compilation.dependencyFactories.set(
RequireEnsureDependency,
new NullFactory()
);
compilation.dependencyTemplates.set(
RequireEnsureDependency,
new RequireEnsureDependency.Template()
);
compilation.dependencyFactories.set(RequireEnsureDependency, new NullFactory());
compilation.dependencyTemplates.set(RequireEnsureDependency, new RequireEnsureDependency.Template());
const handler = (parser, parserOptions) => {
if (
parserOptions.requireEnsure !== undefined &&
!parserOptions.requireEnsure
)
return;
params.normalModuleFactory.plugin("parser", (parser, parserOptions) => {
new RequireEnsureDependenciesBlockParserPlugin().apply(parser);
parser.hooks.evaluateTypeof
.for("require.ensure")
.tap(
"RequireEnsurePlugin",
ParserHelpers.evaluateToString("function")
);
parser.hooks.typeof
.for("require.ensure")
.tap(
"RequireEnsurePlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("function")
)
);
};
if(typeof parserOptions.requireEnsure !== "undefined" && !parserOptions.requireEnsure)
return;
parser.apply(new RequireEnsureDependenciesBlockParserPlugin());
parser.plugin("evaluate typeof require.ensure", ParserHelpers.evaluateToString("function"));
parser.plugin("typeof require.ensure", ParserHelpers.toConstantDependency(JSON.stringify("function")));
});
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("RequireEnsurePlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("RequireEnsurePlugin", handler);
}
);
}
}
module.exports = RequireEnsurePlugin;
+1 -1
View File
@@ -8,7 +8,7 @@ const NullDependency = require("./NullDependency");
class RequireHeaderDependency extends NullDependency {
constructor(range) {
super();
if(!Array.isArray(range)) throw new Error("range must be valid");
if (!Array.isArray(range)) throw new Error("range must be valid");
this.range = range;
}
}
+12 -14
View File
@@ -3,7 +3,10 @@
Author Tobias Koppers @sokra
*/
"use strict";
const DependencyReference = require("./DependencyReference");
const ModuleDependency = require("./ModuleDependency");
const Template = require("../Template");
class RequireIncludeDependency extends ModuleDependency {
constructor(request, range) {
@@ -12,11 +15,9 @@ class RequireIncludeDependency extends ModuleDependency {
}
getReference() {
if(!this.module) return null;
return {
module: this.module,
importedNames: [] // This doesn't use any export
};
if (!this.module) return null;
// This doesn't use any export
return new DependencyReference(this.module, [], false);
}
get type() {
@@ -25,17 +26,14 @@ class RequireIncludeDependency extends ModuleDependency {
}
RequireIncludeDependency.Template = class RequireIncludeDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
const comment = this.getOptionalComment(outputOptions.pathinfo && dep.module, requestShortener.shorten(dep.request));
apply(dep, source, runtime) {
const comment = runtime.outputOptions.pathinfo
? Template.toComment(
`require.include ${runtime.requestShortener.shorten(dep.request)}`
)
: "";
source.replace(dep.range[0], dep.range[1] - 1, `undefined${comment}`);
}
getOptionalComment(shouldHaveComment, shortenedRequest) {
if(shouldHaveComment) {
return "";
}
return `/*! require.include ${shortenedRequest} */`;
}
};
module.exports = RequireIncludeDependency;
@@ -8,14 +8,16 @@ const RequireIncludeDependency = require("./RequireIncludeDependency");
module.exports = class RequireIncludeDependencyParserPlugin {
apply(parser) {
parser.plugin("call require.include", expr => {
if(expr.arguments.length !== 1) return;
const param = parser.evaluateExpression(expr.arguments[0]);
if(!param.isString()) return;
const dep = new RequireIncludeDependency(param.string, expr.range);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
});
parser.hooks.call
.for("require.include")
.tap("RequireIncludeDependencyParserPlugin", expr => {
if (expr.arguments.length !== 1) return;
const param = parser.evaluateExpression(expr.arguments[0]);
if (!param.isString()) return;
const dep = new RequireIncludeDependency(param.string, expr.range);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
});
}
};
+42 -14
View File
@@ -10,24 +10,52 @@ const RequireIncludeDependencyParserPlugin = require("./RequireIncludeDependency
const ParserHelpers = require("../ParserHelpers");
class RequireIncludePlugin {
apply(compiler) {
compiler.plugin("compilation", (compilation, params) => {
const normalModuleFactory = params.normalModuleFactory;
compiler.hooks.compilation.tap(
"RequireIncludePlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
RequireIncludeDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
RequireIncludeDependency,
new RequireIncludeDependency.Template()
);
compilation.dependencyFactories.set(RequireIncludeDependency, normalModuleFactory);
compilation.dependencyTemplates.set(RequireIncludeDependency, new RequireIncludeDependency.Template());
const handler = (parser, parserOptions) => {
if (
parserOptions.requireInclude !== undefined &&
!parserOptions.requireInclude
)
return;
params.normalModuleFactory.plugin("parser", (parser, parserOptions) => {
new RequireIncludeDependencyParserPlugin().apply(parser);
parser.hooks.evaluateTypeof
.for("require.include")
.tap(
"RequireIncludePlugin",
ParserHelpers.evaluateToString("function")
);
parser.hooks.typeof
.for("require.include")
.tap(
"RequireIncludePlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("function")
)
);
};
if(typeof parserOptions.requireInclude !== "undefined" && !parserOptions.requireInclude)
return;
parser.apply(new RequireIncludeDependencyParserPlugin());
parser.plugin("evaluate typeof require.include", ParserHelpers.evaluateToString("function"));
parser.plugin("typeof require.include", ParserHelpers.toConstantDependency(JSON.stringify("function")));
});
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("RequireIncludePlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("RequireIncludePlugin", handler);
}
);
}
}
module.exports = RequireIncludePlugin;
+2 -3
View File
@@ -7,8 +7,8 @@ const ContextDependency = require("./ContextDependency");
const ContextDependencyTemplateAsId = require("./ContextDependencyTemplateAsId");
class RequireResolveContextDependency extends ContextDependency {
constructor(request, recursive, regExp, range, valueRange) {
super(request, recursive, regExp);
constructor(options, range, valueRange) {
super(options);
this.range = range;
this.valueRange = valueRange;
}
@@ -16,7 +16,6 @@ class RequireResolveContextDependency extends ContextDependency {
get type() {
return "amd require context";
}
}
RequireResolveContextDependency.Template = ContextDependencyTemplateAsId;
@@ -16,39 +16,34 @@ class RequireResolveDependencyParserPlugin {
apply(parser) {
const options = this.options;
parser.plugin("call require.resolve", (expr) => {
return parser.applyPluginsBailResult("call require.resolve(Weak)", expr, false);
});
parser.plugin("call require.resolveWeak", (expr) => {
return parser.applyPluginsBailResult("call require.resolve(Weak)", expr, true);
});
parser.plugin("call require.resolve(Weak)", (expr, weak) => {
if(expr.arguments.length !== 1) return;
const process = (expr, weak) => {
if (expr.arguments.length !== 1) return;
const param = parser.evaluateExpression(expr.arguments[0]);
if(param.isConditional()) {
param.options.forEach((option) => {
const result = parser.applyPluginsBailResult("call require.resolve(Weak):item", expr, option, weak);
if(result === undefined) {
parser.applyPluginsBailResult("call require.resolve(Weak):context", expr, option, weak);
if (param.isConditional()) {
for (const option of param.options) {
const result = processItem(expr, option, weak);
if (result === undefined) {
processContext(expr, option, weak);
}
});
}
const dep = new RequireResolveHeaderDependency(expr.callee.range);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
} else {
const result = parser.applyPluginsBailResult("call require.resolve(Weak):item", expr, param, weak);
if(result === undefined) {
parser.applyPluginsBailResult("call require.resolve(Weak):context", expr, param, weak);
const result = processItem(expr, param, weak);
if (result === undefined) {
processContext(expr, param, weak);
}
const dep = new RequireResolveHeaderDependency(expr.callee.range);
dep.loc = expr.loc;
parser.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call require.resolve(Weak):item", (expr, param, weak) => {
if(param.isString()) {
};
const processItem = (expr, param, weak) => {
if (param.isString()) {
const dep = new RequireResolveDependency(param.string, param.range);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
@@ -56,16 +51,36 @@ class RequireResolveDependencyParserPlugin {
parser.state.current.addDependency(dep);
return true;
}
});
parser.plugin("call require.resolve(Weak):context", (expr, param, weak) => {
const dep = ContextDependencyHelpers.create(RequireResolveContextDependency, param.range, param, expr, options);
if(!dep) return;
};
const processContext = (expr, param, weak) => {
const dep = ContextDependencyHelpers.create(
RequireResolveContextDependency,
param.range,
param,
expr,
options,
{
mode: weak ? "weak" : "sync"
},
parser
);
if (!dep) return;
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
dep.async = weak ? "weak" : false;
parser.state.current.addDependency(dep);
return true;
});
};
parser.hooks.call
.for("require.resolve")
.tap("RequireResolveDependencyParserPlugin", expr => {
return process(expr, false);
});
parser.hooks.call
.for("require.resolveWeak")
.tap("RequireResolveDependencyParserPlugin", expr => {
return process(expr, true);
});
}
}
module.exports = RequireResolveDependencyParserPlugin;
+1 -1
View File
@@ -8,7 +8,7 @@ const NullDependency = require("./NullDependency");
class RequireResolveHeaderDependency extends NullDependency {
constructor(range) {
super();
if(!Array.isArray(range)) throw new Error("range must be valid");
if (!Array.isArray(range)) throw new Error("range must be valid");
this.range = range;
}
}
+3
View File
@@ -6,6 +6,9 @@
const ModuleDependency = require("./ModuleDependency");
class SingleEntryDependency extends ModuleDependency {
/**
* @param {string} request request path for entry
*/
constructor(request) {
super(request);
}
+102 -24
View File
@@ -3,7 +3,9 @@
Author Tobias Koppers @sokra
*/
"use strict";
const ParserHelpers = require("../ParserHelpers");
const WebpackError = require("../WebpackError");
class SystemPlugin {
constructor(options) {
@@ -11,34 +13,110 @@ class SystemPlugin {
}
apply(compiler) {
compiler.plugin("compilation", (compilation, params) => {
params.normalModuleFactory.plugin("parser", (parser, parserOptions) => {
compiler.hooks.compilation.tap(
"SystemPlugin",
(compilation, { normalModuleFactory }) => {
const handler = (parser, parserOptions) => {
if (parserOptions.system !== undefined && !parserOptions.system)
return;
if(typeof parserOptions.system !== "undefined" && !parserOptions.system)
return;
const shouldWarn = parserOptions.system === undefined;
function setNotSupported(name) {
parser.plugin("evaluate typeof " + name, ParserHelpers.evaluateToString("undefined"));
parser.plugin("expression " + name,
ParserHelpers.expressionIsUnsupported(name + " is not supported by webpack.")
);
}
const setNotSupported = name => {
parser.hooks.evaluateTypeof
.for(name)
.tap("SystemPlugin", ParserHelpers.evaluateToString("undefined"));
parser.hooks.expression
.for(name)
.tap(
"SystemPlugin",
ParserHelpers.expressionIsUnsupported(
parser,
name + " is not supported by webpack."
)
);
};
parser.plugin("typeof System.import", ParserHelpers.toConstantDependency(JSON.stringify("function")));
parser.plugin("evaluate typeof System.import", ParserHelpers.evaluateToString("function"));
parser.plugin("typeof System", ParserHelpers.toConstantDependency(JSON.stringify("object")));
parser.plugin("evaluate typeof System", ParserHelpers.evaluateToString("object"));
parser.hooks.typeof
.for("System.import")
.tap(
"SystemPlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("function")
)
);
parser.hooks.evaluateTypeof
.for("System.import")
.tap("SystemPlugin", ParserHelpers.evaluateToString("function"));
parser.hooks.typeof
.for("System")
.tap(
"SystemPlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("object")
)
);
parser.hooks.evaluateTypeof
.for("System")
.tap("SystemPlugin", ParserHelpers.evaluateToString("object"));
setNotSupported("System.set");
setNotSupported("System.get");
setNotSupported("System.register");
parser.plugin("expression System", function() {
const systemPolyfillRequire = ParserHelpers.requireFileAsExpression(
this.state.module.context, require.resolve("../../buildin/system.js"));
return ParserHelpers.addParsedVariableToModule(this, "System", systemPolyfillRequire);
});
});
});
setNotSupported("System.set");
setNotSupported("System.get");
setNotSupported("System.register");
parser.hooks.expression.for("System").tap("SystemPlugin", () => {
const systemPolyfillRequire = ParserHelpers.requireFileAsExpression(
parser.state.module.context,
require.resolve("../../buildin/system")
);
return ParserHelpers.addParsedVariableToModule(
parser,
"System",
systemPolyfillRequire
);
});
parser.hooks.call.for("System.import").tap("SystemPlugin", expr => {
if (shouldWarn) {
parser.state.module.warnings.push(
new SystemImportDeprecationWarning(
parser.state.module,
expr.loc
)
);
}
return parser.hooks.importCall.call(expr);
});
};
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("SystemPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("SystemPlugin", handler);
}
);
}
}
class SystemImportDeprecationWarning extends WebpackError {
constructor(module, loc) {
super(
"System.import() is deprecated and will be removed soon. Use import() instead.\n" +
"For more info visit https://webpack.js.org/guides/code-splitting/"
);
this.name = "SystemImportDeprecationWarning";
this.module = module;
this.loc = loc;
Error.captureStackTrace(this, this.constructor);
}
}
module.exports = SystemPlugin;
+6 -2
View File
@@ -15,8 +15,12 @@ class UnsupportedDependency extends NullDependency {
}
UnsupportedDependency.Template = class UnsupportedDependencyTemplate {
apply(dep, source, outputOptions, requestShortener) {
source.replace(dep.range[0], dep.range[1], webpackMissingModule(dep.request));
apply(dep, source, runtime) {
source.replace(
dep.range[0],
dep.range[1],
webpackMissingModule(dep.request)
);
}
};
+9 -7
View File
@@ -3,16 +3,18 @@
Author Tobias Koppers @sokra
*/
"use strict";
const toErrorCode = err => `var e = new Error(${JSON.stringify(err)}); e.code = 'MODULE_NOT_FOUND';`;
const toErrorCode = err =>
`var e = new Error(${JSON.stringify(err)}); e.code = 'MODULE_NOT_FOUND';`;
exports.module = request => `!(function webpackMissingModule() { ${exports.moduleCode(request)} }())`;
exports.module = request =>
`!(function webpackMissingModule() { ${exports.moduleCode(request)} }())`;
exports.promise = (request) => {
const errorCode = toErrorCode(`Cannot find module "${request}"`);
return `Promise.reject(function webpackMissingModule() { ${errorCode}; return e; }())`;
exports.promise = request => {
const errorCode = toErrorCode(`Cannot find module '${request}'`);
return `Promise.reject(function webpackMissingModule() { ${errorCode} return e; }())`;
};
exports.moduleCode = (request) => {
const errorCode = toErrorCode(`Cannot find module "${request}"`);
exports.moduleCode = request => {
const errorCode = toErrorCode(`Cannot find module '${request}'`);
return `${errorCode} throw e;`;
};
+15 -7
View File
@@ -2,9 +2,12 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
module.exports = function(expr) {
module.exports = expr => {
// <FunctionExpression>
if(expr.type === "FunctionExpression" || expr.type === "ArrowFunctionExpression") {
if (
expr.type === "FunctionExpression" ||
expr.type === "ArrowFunctionExpression"
) {
return {
fn: expr,
expressions: [],
@@ -13,19 +16,23 @@ module.exports = function(expr) {
}
// <FunctionExpression>.bind(<Expression>)
if(expr.type === "CallExpression" &&
if (
expr.type === "CallExpression" &&
expr.callee.type === "MemberExpression" &&
expr.callee.object.type === "FunctionExpression" &&
expr.callee.property.type === "Identifier" &&
expr.callee.property.name === "bind" &&
expr.arguments.length === 1) {
expr.arguments.length === 1
) {
return {
fn: expr.callee.object,
expressions: [expr.arguments[0]]
expressions: [expr.arguments[0]],
needThis: undefined
};
}
// (function(_this) {return <FunctionExpression>})(this) (Coffeescript)
if(expr.type === "CallExpression" &&
if (
expr.type === "CallExpression" &&
expr.callee.type === "FunctionExpression" &&
expr.callee.body.type === "BlockStatement" &&
expr.arguments.length === 1 &&
@@ -34,7 +41,8 @@ module.exports = function(expr) {
expr.callee.body.body.length === 1 &&
expr.callee.body.body[0].type === "ReturnStatement" &&
expr.callee.body.body[0].argument &&
expr.callee.body.body[0].argument.type === "FunctionExpression") {
expr.callee.body.body[0].argument.type === "FunctionExpression"
) {
return {
fn: expr.callee.body.body[0].argument,
expressions: [],