Merge branch 'master' into jest
# Conflicts: # lib/Chunk.js # lib/HotModuleReplacement.runtime.js # lib/Module.js # lib/MultiCompiler.js # lib/Parser.js # lib/Stats.js # test/BenchmarkTestCases.benchmark.js # test/CachePlugin.unittest.js # test/CaseSensitiveModulesWarning.unittest.js # test/Chunk.unittest.js # test/Compiler-caching.test.js # test/Compiler.test.js # test/ConfigTestCases.test.js # test/ContextModuleFactory.unittest.js # test/DependenciesBlockVariable.unittest.js # test/Errors.test.js # test/Examples.test.js # test/HotModuleReplacementPlugin.test.js # test/HotTestCases.test.js # test/Integration.test.js # test/LocalModulesHelpers.unittest.js # test/ModuleDependencyError.unittest.js # test/ModuleReason.unittest.js # test/MultiStats.unittest.js # test/NodeTemplatePlugin.test.js # test/NodeWatchFileSystem.unittest.js # test/NormalModule.unittest.js # test/NullDependency.unittest.js # test/Parser.unittest.js # test/ProfilingPlugin.unittest.js # test/RawModule.unittest.js # test/RuleSet.unittest.js # test/Schemas.lint.js # test/SideEffectsFlagPlugin.unittest.js # test/SizeFormatHelpers.unittest.js # test/SourceMapDevToolModuleOptionsPlugin.unittest.js # test/Stats.test.js # test/Stats.unittest.js # test/StatsTestCases.test.js # test/Template.unittest.js # test/TestCases.test.js # test/Validation.test.js # test/WatchDetection.test.js # test/WatchTestCases.test.js # test/WatcherEvents.test.js # test/WebEnvironmentPlugin.unittest.js # test/WebpackMissingModule.unittest.js # test/compareLocations.unittest.js # test/identifier.unittest.js
This commit is contained in:
commit
650cf52e56
|
@ -162,6 +162,7 @@ class Chunk {
|
|||
if (this._modules.size < otherChunk._modules.size) return 1;
|
||||
const a = this._modules[Symbol.iterator]();
|
||||
const b = otherChunk._modules[Symbol.iterator]();
|
||||
// eslint-disable-next-line
|
||||
while (true) {
|
||||
// eslint-disable-line
|
||||
const aItem = a.next();
|
||||
|
|
|
@ -12,6 +12,7 @@ module.exports = function() {
|
|||
var hotCurrentParents = []; // eslint-disable-line no-unused-vars
|
||||
var hotCurrentParentsTemp = []; // eslint-disable-line no-unused-vars
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotCreateRequire(moduleId) {
|
||||
// eslint-disable-line no-unused-vars
|
||||
var me = installedModules[moduleId];
|
||||
|
@ -80,6 +81,7 @@ module.exports = function() {
|
|||
return fn;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotCreateModule(moduleId) {
|
||||
// eslint-disable-line no-unused-vars
|
||||
var hot = {
|
||||
|
@ -206,6 +208,7 @@ module.exports = function() {
|
|||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotAddUpdateChunk(chunkId, moreModules) {
|
||||
// eslint-disable-line no-unused-vars
|
||||
if (!hotAvailableFilesMap[chunkId] || !hotRequestedFilesMap[chunkId])
|
||||
|
|
|
@ -163,8 +163,8 @@ class Module extends DependenciesBlock {
|
|||
otherModule._chunks.sortWith(sortByDebugId);
|
||||
const a = this._chunks[Symbol.iterator]();
|
||||
const b = otherModule._chunks[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
// eslint-disable-line
|
||||
const aItem = a.next();
|
||||
const bItem = b.next();
|
||||
if (aItem.done) return true;
|
||||
|
|
|
@ -34,8 +34,8 @@ module.exports = class MultiCompiler extends Tapable {
|
|||
for (const compiler of this.compilers) {
|
||||
let compilerDone = false;
|
||||
const compilerIndex = index++;
|
||||
// eslint-disable-next-line no-loop-func
|
||||
compiler.hooks.done.tap("MultiCompiler", stats => {
|
||||
// eslint-disable-line no-loop-func
|
||||
if (!compilerDone) {
|
||||
compilerDone = true;
|
||||
doneCompilers++;
|
||||
|
@ -45,8 +45,8 @@ module.exports = class MultiCompiler extends Tapable {
|
|||
this.hooks.done.call(new MultiStats(compilerStats));
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line no-loop-func
|
||||
compiler.hooks.invalid.tap("MultiCompiler", () => {
|
||||
// eslint-disable-line no-loop-func
|
||||
if (compilerDone) {
|
||||
compilerDone = false;
|
||||
doneCompilers--;
|
||||
|
|
|
@ -2055,7 +2055,9 @@ class Parser extends Tapable {
|
|||
try {
|
||||
ast = acorn.parse(code, parserOptions);
|
||||
threw = false;
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (threw) {
|
||||
|
|
|
@ -97,7 +97,7 @@ class Stats {
|
|||
if (typeof item === "string") {
|
||||
const regExp = new RegExp(
|
||||
`[\\\\/]${item.replace(
|
||||
/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
|
||||
/[-[\]{}()*+?.\\^$|]/g,
|
||||
"\\$&"
|
||||
)}([\\\\/]|$|!|\\?)`
|
||||
); // eslint-disable-line no-useless-escape
|
||||
|
|
|
@ -6,7 +6,7 @@ let inspector = undefined;
|
|||
|
||||
try {
|
||||
inspector = require("inspector"); // eslint-disable-line node/no-missing-require
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.log("Unable to CPU profile in < node 8.0");
|
||||
}
|
||||
|
||||
|
@ -21,14 +21,14 @@ class Profiler {
|
|||
}
|
||||
|
||||
startProfiling() {
|
||||
if(this.inspector === undefined) {
|
||||
if (this.inspector === undefined) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
try {
|
||||
this.session = new inspector.Session();
|
||||
this.session.connect();
|
||||
} catch(_) {
|
||||
} catch (_) {
|
||||
this.session = undefined;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -38,15 +38,15 @@ class Profiler {
|
|||
interval: 100
|
||||
}),
|
||||
this.sendCommand("Profiler.enable"),
|
||||
this.sendCommand("Profiler.start"),
|
||||
this.sendCommand("Profiler.start")
|
||||
]);
|
||||
}
|
||||
|
||||
sendCommand(method, params) {
|
||||
if(this.hasSession()) {
|
||||
if (this.hasSession()) {
|
||||
return new Promise((res, rej) => {
|
||||
return this.session.post(method, params, (err, params) => {
|
||||
if(err !== null) {
|
||||
if (err !== null) {
|
||||
rej(err);
|
||||
} else {
|
||||
res(params);
|
||||
|
@ -59,7 +59,7 @@ class Profiler {
|
|||
}
|
||||
|
||||
destroy() {
|
||||
if(this.hasSession()) {
|
||||
if (this.hasSession()) {
|
||||
this.session.disconnect();
|
||||
}
|
||||
|
||||
|
@ -94,11 +94,13 @@ function createTrace(outputPath) {
|
|||
data: {
|
||||
sessionId: "-1",
|
||||
page: "0xfff",
|
||||
frames: [{
|
||||
frame: "0xfff",
|
||||
url: "webpack",
|
||||
name: ""
|
||||
}]
|
||||
frames: [
|
||||
{
|
||||
frame: "0xfff",
|
||||
url: "webpack",
|
||||
name: ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -110,7 +112,7 @@ function createTrace(outputPath) {
|
|||
args: {
|
||||
data: {
|
||||
sessionId: "-1"
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -136,83 +138,97 @@ class ProfilingPlugin {
|
|||
|
||||
// Compiler Hooks
|
||||
Object.keys(compiler.hooks).forEach(hookName => {
|
||||
compiler.hooks[hookName].intercept(makeInterceptorFor("Compiler", tracer)(hookName));
|
||||
compiler.hooks[hookName].intercept(
|
||||
makeInterceptorFor("Compiler", tracer)(hookName)
|
||||
);
|
||||
});
|
||||
|
||||
Object.keys(compiler.resolverFactory.hooks).forEach(hookName => {
|
||||
compiler.resolverFactory.hooks[hookName].intercept(makeInterceptorFor("Resolver", tracer)(hookName));
|
||||
compiler.resolverFactory.hooks[hookName].intercept(
|
||||
makeInterceptorFor("Resolver", tracer)(hookName)
|
||||
);
|
||||
});
|
||||
|
||||
compiler.hooks.compilation.tap(pluginName, (compilation, {
|
||||
normalModuleFactory,
|
||||
contextModuleFactory
|
||||
}) => {
|
||||
interceptAllHooksFor(compilation, tracer, "Compilation");
|
||||
interceptAllHooksFor(normalModuleFactory, tracer, "Normal Module Factory");
|
||||
interceptAllHooksFor(contextModuleFactory, tracer, "Context Module Factory");
|
||||
interceptAllParserHooks(normalModuleFactory, tracer);
|
||||
interceptTemplateInstancesFrom(compilation, tracer);
|
||||
});
|
||||
compiler.hooks.compilation.tap(
|
||||
pluginName,
|
||||
(compilation, { normalModuleFactory, contextModuleFactory }) => {
|
||||
interceptAllHooksFor(compilation, tracer, "Compilation");
|
||||
interceptAllHooksFor(
|
||||
normalModuleFactory,
|
||||
tracer,
|
||||
"Normal Module Factory"
|
||||
);
|
||||
interceptAllHooksFor(
|
||||
contextModuleFactory,
|
||||
tracer,
|
||||
"Context Module Factory"
|
||||
);
|
||||
interceptAllParserHooks(normalModuleFactory, tracer);
|
||||
interceptTemplateInstancesFrom(compilation, tracer);
|
||||
}
|
||||
);
|
||||
|
||||
// We need to write out the CPU profile when we are all done.
|
||||
compiler.hooks.done.tap({
|
||||
name: pluginName,
|
||||
stage: Infinity
|
||||
}, () => {
|
||||
tracer.profiler.stopProfiling().then((parsedResults) => {
|
||||
compiler.hooks.done.tap(
|
||||
{
|
||||
name: pluginName,
|
||||
stage: Infinity
|
||||
},
|
||||
() => {
|
||||
tracer.profiler.stopProfiling().then(parsedResults => {
|
||||
if (parsedResults === undefined) {
|
||||
tracer.profiler.destroy();
|
||||
tracer.trace.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
const cpuStartTime = parsedResults.profile.startTime;
|
||||
const cpuEndTime = parsedResults.profile.endTime;
|
||||
|
||||
tracer.trace.completeEvent({
|
||||
name: "TaskQueueManager::ProcessTaskFromWorkQueue",
|
||||
id: ++tracer.counter,
|
||||
cat: ["toplevel"],
|
||||
ts: cpuStartTime,
|
||||
args: {
|
||||
src_file: "../../ipc/ipc_moji_bootstrap.cc",
|
||||
src_func: "Accept"
|
||||
}
|
||||
});
|
||||
|
||||
tracer.trace.completeEvent({
|
||||
name: "EvaluateScript",
|
||||
id: ++tracer.counter,
|
||||
cat: ["devtools.timeline"],
|
||||
ts: cpuStartTime,
|
||||
dur: cpuEndTime - cpuStartTime,
|
||||
args: {
|
||||
data: {
|
||||
url: "webpack",
|
||||
lineNumber: 1,
|
||||
columnNumber: 1,
|
||||
frame: "0xFFF"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tracer.trace.instantEvent({
|
||||
name: "CpuProfile",
|
||||
id: ++tracer.counter,
|
||||
cat: ["disabled-by-default-devtools.timeline"],
|
||||
ts: cpuEndTime,
|
||||
args: {
|
||||
data: {
|
||||
cpuProfile: parsedResults.profile
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(parsedResults === undefined) {
|
||||
tracer.profiler.destroy();
|
||||
tracer.trace.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
const cpuStartTime = parsedResults.profile.startTime;
|
||||
const cpuEndTime = parsedResults.profile.endTime;
|
||||
|
||||
tracer.trace.completeEvent({
|
||||
name: "TaskQueueManager::ProcessTaskFromWorkQueue",
|
||||
id: ++tracer.counter,
|
||||
cat: ["toplevel"],
|
||||
ts: cpuStartTime,
|
||||
args: {
|
||||
src_file: "../../ipc/ipc_moji_bootstrap.cc",
|
||||
src_func: "Accept"
|
||||
}
|
||||
});
|
||||
|
||||
tracer.trace.completeEvent({
|
||||
name: "EvaluateScript",
|
||||
id: ++tracer.counter,
|
||||
cat: ["devtools.timeline"],
|
||||
ts: cpuStartTime,
|
||||
dur: cpuEndTime - cpuStartTime,
|
||||
args: {
|
||||
data: {
|
||||
url: "webpack",
|
||||
lineNumber: 1,
|
||||
columnNumber: 1,
|
||||
frame: "0xFFF"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tracer.trace.instantEvent({
|
||||
name: "CpuProfile",
|
||||
id: ++tracer.counter,
|
||||
cat: ["disabled-by-default-devtools.timeline"],
|
||||
ts: cpuEndTime,
|
||||
args: {
|
||||
data: {
|
||||
cpuProfile: parsedResults.profile
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tracer.profiler.destroy();
|
||||
tracer.trace.flush();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,12 +240,10 @@ const interceptTemplateInstancesFrom = (compilation, tracer) => {
|
|||
moduleTemplates
|
||||
} = compilation;
|
||||
|
||||
const {
|
||||
javascript,
|
||||
webassembly
|
||||
} = moduleTemplates;
|
||||
const { javascript, webassembly } = moduleTemplates;
|
||||
|
||||
[{
|
||||
[
|
||||
{
|
||||
instance: mainTemplate,
|
||||
name: "MainTemplate"
|
||||
},
|
||||
|
@ -251,15 +265,19 @@ const interceptTemplateInstancesFrom = (compilation, tracer) => {
|
|||
}
|
||||
].forEach(templateObject => {
|
||||
Object.keys(templateObject.instance.hooks).forEach(hookName => {
|
||||
templateObject.instance.hooks[hookName].intercept(makeInterceptorFor(templateObject.name, tracer)(hookName));
|
||||
templateObject.instance.hooks[hookName].intercept(
|
||||
makeInterceptorFor(templateObject.name, tracer)(hookName)
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const interceptAllHooksFor = (instance, tracer, logLabel) => {
|
||||
if(Reflect.has(instance, "hooks")) {
|
||||
if (Reflect.has(instance, "hooks")) {
|
||||
Object.keys(instance.hooks).forEach(hookName => {
|
||||
instance.hooks[hookName].intercept(makeInterceptorFor(logLabel, tracer)(hookName));
|
||||
instance.hooks[hookName].intercept(
|
||||
makeInterceptorFor(logLabel, tracer)(hookName)
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -274,28 +292,27 @@ const interceptAllParserHooks = (moduleFactory, tracer) => {
|
|||
];
|
||||
|
||||
moduleTypes.forEach(moduleType => {
|
||||
moduleFactory.hooks.parser.for(moduleType).tap("ProfilingPlugin", (parser, parserOpts) => {
|
||||
interceptAllHooksFor(parser, tracer, "Parser");
|
||||
});
|
||||
moduleFactory.hooks.parser
|
||||
.for(moduleType)
|
||||
.tap("ProfilingPlugin", (parser, parserOpts) => {
|
||||
interceptAllHooksFor(parser, tracer, "Parser");
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const makeInterceptorFor = (instance, tracer) => (hookName) => ({
|
||||
register: ({
|
||||
name,
|
||||
type,
|
||||
fn
|
||||
}) => {
|
||||
const makeInterceptorFor = (instance, tracer) => hookName => ({
|
||||
register: ({ name, type, fn }) => {
|
||||
const newFn = makeNewProfiledTapFn(hookName, tracer, {
|
||||
name,
|
||||
type,
|
||||
fn
|
||||
});
|
||||
return({ // eslint-disable-line
|
||||
return {
|
||||
// eslint-disable-line
|
||||
name,
|
||||
type,
|
||||
fn: newFn
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -305,16 +322,13 @@ const makeInterceptorFor = (instance, tracer) => (hookName) => ({
|
|||
* @param {{name: string, type: string, fn: Function}} opts Options for the profiled fn.
|
||||
* @returns {*} Chainable hooked function.
|
||||
*/
|
||||
const makeNewProfiledTapFn = (hookName, tracer, {
|
||||
name,
|
||||
type,
|
||||
fn
|
||||
}) => {
|
||||
const makeNewProfiledTapFn = (hookName, tracer, { name, type, fn }) => {
|
||||
const defaultCategory = ["blink.user_timing"];
|
||||
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case "promise":
|
||||
return(...args) => { // eslint-disable-line
|
||||
return (...args) => {
|
||||
// eslint-disable-line
|
||||
const id = ++tracer.counter;
|
||||
tracer.trace.begin({
|
||||
name,
|
||||
|
@ -331,7 +345,8 @@ const makeNewProfiledTapFn = (hookName, tracer, {
|
|||
});
|
||||
};
|
||||
case "async":
|
||||
return(...args) => { // eslint-disable-line
|
||||
return (...args) => {
|
||||
// eslint-disable-line
|
||||
const id = ++tracer.counter;
|
||||
tracer.trace.begin({
|
||||
name,
|
||||
|
@ -349,11 +364,12 @@ const makeNewProfiledTapFn = (hookName, tracer, {
|
|||
});
|
||||
};
|
||||
case "sync":
|
||||
return(...args) => { // eslint-disable-line
|
||||
return (...args) => {
|
||||
// eslint-disable-line
|
||||
const id = ++tracer.counter;
|
||||
// Do not instrument outself due to the CPU
|
||||
// profile needing to be the last event in the trace.
|
||||
if(name === pluginName) {
|
||||
if (name === pluginName) {
|
||||
return fn(...args);
|
||||
}
|
||||
|
||||
|
@ -365,7 +381,7 @@ const makeNewProfiledTapFn = (hookName, tracer, {
|
|||
let r;
|
||||
try {
|
||||
r = fn(...args);
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
tracer.trace.end({
|
||||
name,
|
||||
id,
|
||||
|
|
|
@ -28,10 +28,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 +42,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 +54,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 +63,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 +82,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 +99,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");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,24 +14,24 @@ const ContextDependencyHelpers = require("./ContextDependencyHelpers");
|
|||
const LocalModulesHelpers = require("./LocalModulesHelpers");
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
if (isUnboundFunctionExpression(expr)) return true;
|
||||
if (isBoundFunctionExpression(expr)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -40,36 +40,57 @@ class AMDDefineDependencyParserPlugin {
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
newDefineDependency(range, arrayRange, functionRange, objectRange, namedModule) {
|
||||
return new AMDDefineDependency(range, arrayRange, functionRange, objectRange, namedModule);
|
||||
newDefineDependency(
|
||||
range,
|
||||
arrayRange,
|
||||
functionRange,
|
||||
objectRange,
|
||||
namedModule
|
||||
) {
|
||||
return new AMDDefineDependency(
|
||||
range,
|
||||
arrayRange,
|
||||
functionRange,
|
||||
objectRange,
|
||||
namedModule
|
||||
);
|
||||
}
|
||||
|
||||
apply(parser) {
|
||||
const options = this.options;
|
||||
|
||||
const processArray = (expr, param, identifiers, namedModule) => {
|
||||
if(param.isArray()) {
|
||||
if (param.isArray()) {
|
||||
param.items.forEach((param, idx) => {
|
||||
if(param.isString() && ["require", "module", "exports"].includes(param.string))
|
||||
if (
|
||||
param.isString() &&
|
||||
["require", "module", "exports"].includes(param.string)
|
||||
)
|
||||
identifiers[idx] = param.string;
|
||||
const result = processItem(expr, param, namedModule);
|
||||
if(result === undefined) {
|
||||
if (result === undefined) {
|
||||
processContext(expr, param);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if(param.isConstArray()) {
|
||||
} else if (param.isConstArray()) {
|
||||
const deps = [];
|
||||
param.array.forEach((request, idx) => {
|
||||
let dep;
|
||||
let localModule;
|
||||
if(request === "require") {
|
||||
if (request === "require") {
|
||||
identifiers[idx] = request;
|
||||
dep = "__webpack_require__";
|
||||
} else if(["exports", "module"].includes(request)) {
|
||||
} else if (["exports", "module"].includes(request)) {
|
||||
identifiers[idx] = request;
|
||||
dep = request;
|
||||
} else if(localModule = LocalModulesHelpers.getLocalModule(parser.state, request)) { // eslint-disable-line no-cond-assign
|
||||
} 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);
|
||||
|
@ -89,21 +110,28 @@ class AMDDefineDependencyParserPlugin {
|
|||
}
|
||||
};
|
||||
const processItem = (expr, param, namedModule) => {
|
||||
if(param.isConditional()) {
|
||||
param.options.forEach((param) => {
|
||||
if (param.isConditional()) {
|
||||
param.options.forEach(param => {
|
||||
const result = processItem(expr, param);
|
||||
if(result === undefined) {
|
||||
if (result === undefined) {
|
||||
processContext(expr, param);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if(param.isString()) {
|
||||
} else if (param.isString()) {
|
||||
let dep, localModule;
|
||||
if(param.string === "require") {
|
||||
if (param.string === "require") {
|
||||
dep = new ConstDependency("__webpack_require__", param.range);
|
||||
} else if(["require", "exports", "module"].includes(param.string)) {
|
||||
} 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)) { // eslint-disable-line no-cond-assign
|
||||
} else if (
|
||||
(localModule = LocalModulesHelpers.getLocalModule(
|
||||
parser.state,
|
||||
param.string,
|
||||
namedModule
|
||||
))
|
||||
) {
|
||||
// eslint-disable-line no-cond-assign
|
||||
dep = new LocalModuleDependency(localModule, param.range);
|
||||
} else {
|
||||
dep = new AMDRequireItemDependency(param.string, param.range);
|
||||
|
@ -115,154 +143,169 @@ class AMDDefineDependencyParserPlugin {
|
|||
}
|
||||
};
|
||||
const processContext = (expr, param) => {
|
||||
const dep = ContextDependencyHelpers.create(AMDRequireContextDependency, param.range, param, expr, options);
|
||||
if(!dep) return;
|
||||
const dep = ContextDependencyHelpers.create(
|
||||
AMDRequireContextDependency,
|
||||
param.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("define").tap("AMDDefineDependencyParserPlugin", (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") {
|
||||
parser.hooks.call
|
||||
.for("define")
|
||||
.tap("AMDDefineDependencyParserPlugin", 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;
|
||||
// define("...", ...)
|
||||
if(isCallable(expr.arguments[1])) {
|
||||
// define("...", f() {...})
|
||||
fn = expr.arguments[1];
|
||||
} else if(expr.arguments[1].type === "ObjectExpression") {
|
||||
// define("...", {...})
|
||||
obj = expr.arguments[1];
|
||||
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)
|
||||
// define("...", [...], expr)
|
||||
// unclear if function or object
|
||||
obj = fn = expr.arguments[1];
|
||||
obj = fn = expr.arguments[2];
|
||||
}
|
||||
} 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;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
let fnRenames = parser.scope.renames.createChild();
|
||||
let identifiers;
|
||||
if(array) {
|
||||
identifiers = {};
|
||||
const param = parser.evaluateExpression(array);
|
||||
const result = processArray(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;
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
let fnRenames = parser.scope.renames.createChild();
|
||||
let identifiers;
|
||||
if (array) {
|
||||
identifiers = {};
|
||||
const param = parser.evaluateExpression(array);
|
||||
const result = processArray(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 {
|
||||
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;
|
||||
});
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
module.exports = AMDDefineDependencyParserPlugin;
|
||||
|
|
|
@ -31,90 +31,219 @@ class AMDPlugin {
|
|||
apply(compiler) {
|
||||
const options = this.options;
|
||||
const amdOptions = this.amdOptions;
|
||||
compiler.hooks.compilation.tap("AMDPlugin", (compilation, {
|
||||
contextModuleFactory,
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(AMDRequireDependency, new NullFactory());
|
||||
compilation.dependencyTemplates.set(AMDRequireDependency, new AMDRequireDependency.Template());
|
||||
compiler.hooks.compilation.tap(
|
||||
"AMDPlugin",
|
||||
(compilation, { contextModuleFactory, normalModuleFactory }) => {
|
||||
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(typeof parserOptions.amd !== "undefined" && !parserOptions.amd)
|
||||
return;
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (typeof parserOptions.amd !== "undefined" && !parserOptions.amd)
|
||||
return;
|
||||
|
||||
const setExpressionToModule = (outerExpr, module) => {
|
||||
parser.hooks.expression.for(outerExpr).tap("AMDPlugin", (expr) => {
|
||||
const dep = new AMDRequireItemDependency(module, expr.range);
|
||||
dep.userRequest = outerExpr;
|
||||
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;
|
||||
});
|
||||
};
|
||||
|
||||
new AMDRequireDependenciesBlockParserPlugin(options).apply(parser);
|
||||
new AMDDefineDependencyParserPlugin(options).apply(parser);
|
||||
|
||||
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"));
|
||||
};
|
||||
|
||||
new AMDRequireDependenciesBlockParserPlugin(options).apply(parser);
|
||||
new AMDDefineDependencyParserPlugin(options).apply(parser);
|
||||
|
||||
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 false;
|
||||
});
|
||||
parser.hooks.typeof.for("require").tap("AMDPlugin", ParserHelpers.toConstantDependency(parser, JSON.stringify("function")));
|
||||
parser.hooks.evaluateTypeof.for("require").tap("AMDPlugin", ParserHelpers.evaluateToString("function"));
|
||||
};
|
||||
|
||||
normalModuleFactory.hooks.parser.for("javascript/auto").tap("AMDPlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("AMDPlugin", handler);
|
||||
});
|
||||
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);
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,18 +24,18 @@ AMDRequireArrayDependency.Template = class AMDRequireArrayDependencyTemplate {
|
|||
}
|
||||
|
||||
getContent(dep, runtime) {
|
||||
const requires = dep.depsArray.map((dependency) => {
|
||||
const requires = dep.depsArray.map(dependency => {
|
||||
return this.contentForDependency(dependency, runtime);
|
||||
});
|
||||
return `[${requires.join(", ")}]`;
|
||||
}
|
||||
|
||||
contentForDependency(dep, runtime) {
|
||||
if(typeof dep === "string") {
|
||||
if (typeof dep === "string") {
|
||||
return dep;
|
||||
}
|
||||
|
||||
if(dep.localModule) {
|
||||
if (dep.localModule) {
|
||||
return dep.localModule.variableName();
|
||||
} else {
|
||||
return runtime.moduleExports({
|
||||
|
|
|
@ -7,7 +7,15 @@ const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
|
|||
const AMDRequireDependency = require("./AMDRequireDependency");
|
||||
|
||||
module.exports = class AMDRequireDependenciesBlock extends AsyncDependenciesBlock {
|
||||
constructor(expr, arrayRange, functionRange, errorCallbackRange, module, loc, request) {
|
||||
constructor(
|
||||
expr,
|
||||
arrayRange,
|
||||
functionRange,
|
||||
errorCallbackRange,
|
||||
module,
|
||||
loc,
|
||||
request
|
||||
) {
|
||||
super(null, module, loc, request);
|
||||
this.expr = expr;
|
||||
this.outerRange = expr.range;
|
||||
|
@ -15,13 +23,13 @@ module.exports = class AMDRequireDependenciesBlock extends AsyncDependenciesBloc
|
|||
this.functionRange = functionRange;
|
||||
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;
|
||||
|
|
|
@ -24,17 +24,19 @@ 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"].includes(i.name);
|
||||
}), () => {
|
||||
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 {
|
||||
|
@ -47,43 +49,51 @@ class AMDRequireDependenciesBlockParserPlugin {
|
|||
const options = this.options;
|
||||
|
||||
const processArrayForRequestString = param => {
|
||||
if(param.isArray()) {
|
||||
const result = param.items.map(item => processItemForRequestString(item));
|
||||
if(result.every(Boolean))
|
||||
return result.join(" ");
|
||||
} else if(param.isConstArray()) {
|
||||
if (param.isArray()) {
|
||||
const result = param.items.map(item =>
|
||||
processItemForRequestString(item)
|
||||
);
|
||||
if (result.every(Boolean)) return result.join(" ");
|
||||
} else if (param.isConstArray()) {
|
||||
return param.array.join(" ");
|
||||
}
|
||||
};
|
||||
|
||||
const processItemForRequestString = param => {
|
||||
if(param.isConditional()) {
|
||||
const result = param.options.map(item => processItemForRequestString(item));
|
||||
if(result.every(Boolean))
|
||||
return result.join("|");
|
||||
} else if(param.isString()) {
|
||||
if (param.isConditional()) {
|
||||
const result = param.options.map(item =>
|
||||
processItemForRequestString(item)
|
||||
);
|
||||
if (result.every(Boolean)) return result.join("|");
|
||||
} else if (param.isString()) {
|
||||
return param.string;
|
||||
}
|
||||
};
|
||||
|
||||
const processArray = (expr, param) => {
|
||||
if(param.isArray()) {
|
||||
for(const p of param.items) {
|
||||
if (param.isArray()) {
|
||||
for (const p of param.items) {
|
||||
const result = processItem(expr, p);
|
||||
if(result === undefined) {
|
||||
if (result === undefined) {
|
||||
processContext(expr, p);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if(param.isConstArray()) {
|
||||
} else if (param.isConstArray()) {
|
||||
const deps = [];
|
||||
for(const request of param.array) {
|
||||
for (const request of param.array) {
|
||||
let dep, localModule;
|
||||
if(request === "require") {
|
||||
if (request === "require") {
|
||||
dep = "__webpack_require__";
|
||||
} else if(["exports", "module"].includes(request)) {
|
||||
} else if (["exports", "module"].includes(request)) {
|
||||
dep = request;
|
||||
} else if(localModule = LocalModulesHelpers.getLocalModule(parser.state, request)) { // eslint-disable-line no-cond-assign
|
||||
} 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);
|
||||
|
@ -103,23 +113,35 @@ class AMDRequireDependenciesBlockParserPlugin {
|
|||
}
|
||||
};
|
||||
const processItem = (expr, param) => {
|
||||
if(param.isConditional()) {
|
||||
for(const p of param.options) {
|
||||
if (param.isConditional()) {
|
||||
for (const p of param.options) {
|
||||
const result = processItem(expr, p);
|
||||
if(result === undefined) {
|
||||
if (result === undefined) {
|
||||
processContext(expr, p);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if(param.isString()) {
|
||||
} else if (param.isString()) {
|
||||
let dep, localModule;
|
||||
if(param.string === "require") {
|
||||
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)) { // eslint-disable-line no-cond-assign
|
||||
} 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
|
||||
))
|
||||
) {
|
||||
// eslint-disable-line no-cond-assign
|
||||
dep = new LocalModuleDependency(localModule, param.range);
|
||||
} else {
|
||||
dep = new AMDRequireItemDependency(param.string, param.range);
|
||||
|
@ -131,70 +153,89 @@ class AMDRequireDependenciesBlockParserPlugin {
|
|||
}
|
||||
};
|
||||
const processContext = (expr, param) => {
|
||||
const dep = ContextDependencyHelpers.create(AMDRequireContextDependency, param.range, param, expr, options);
|
||||
if(!dep) return;
|
||||
const dep = ContextDependencyHelpers.create(
|
||||
AMDRequireContextDependency,
|
||||
param.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("AMDRequireDependenciesBlockParserPlugin", (expr) => {
|
||||
let param;
|
||||
let dep;
|
||||
let result;
|
||||
parser.hooks.call
|
||||
.for("require")
|
||||
.tap("AMDRequireDependenciesBlockParserPlugin", expr => {
|
||||
let param;
|
||||
let dep;
|
||||
let result;
|
||||
|
||||
const old = parser.state.current;
|
||||
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,
|
||||
processArrayForRequestString(param)
|
||||
);
|
||||
parser.state.current = dep;
|
||||
}
|
||||
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,
|
||||
processArrayForRequestString(param)
|
||||
);
|
||||
parser.state.current = dep;
|
||||
}
|
||||
|
||||
if(expr.arguments.length === 1) {
|
||||
parser.inScope([], () => {
|
||||
result = processArray(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 {
|
||||
if (expr.arguments.length === 1) {
|
||||
parser.inScope([], () => {
|
||||
result = processArray(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);
|
||||
if (!result) return;
|
||||
parser.state.current.addBlock(dep);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (expr.arguments.length === 2 || expr.arguments.length === 3) {
|
||||
try {
|
||||
parser.inScope([], () => {
|
||||
result = processArray(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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
module.exports = AMDRequireDependenciesBlockParserPlugin;
|
||||
|
|
|
@ -21,47 +21,113 @@ AMDRequireDependency.Template = class AMDRequireDependencyTemplate {
|
|||
});
|
||||
|
||||
// has array range but no function range
|
||||
if(depBlock.arrayRange && !depBlock.functionRange) {
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
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) {
|
||||
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)" : ""})`;
|
||||
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) {
|
||||
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);
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -25,66 +25,137 @@ class CommonJsPlugin {
|
|||
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
compiler.hooks.compilation.tap("CommonJsPlugin", (compilation, {
|
||||
contextModuleFactory,
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(CommonJsRequireDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(CommonJsRequireDependency, new CommonJsRequireDependency.Template());
|
||||
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(
|
||||
CommonJsRequireContextDependency,
|
||||
contextModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
CommonJsRequireContextDependency,
|
||||
new CommonJsRequireContextDependency.Template()
|
||||
);
|
||||
|
||||
compilation.dependencyFactories.set(RequireResolveDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(RequireResolveDependency, new RequireResolveDependency.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(
|
||||
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(
|
||||
RequireResolveHeaderDependency,
|
||||
new NullFactory()
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
RequireResolveHeaderDependency,
|
||||
new RequireResolveHeaderDependency.Template()
|
||||
);
|
||||
|
||||
compilation.dependencyFactories.set(RequireHeaderDependency, new NullFactory());
|
||||
compilation.dependencyTemplates.set(RequireHeaderDependency, new RequireHeaderDependency.Template());
|
||||
compilation.dependencyFactories.set(
|
||||
RequireHeaderDependency,
|
||||
new NullFactory()
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
RequireHeaderDependency,
|
||||
new RequireHeaderDependency.Template()
|
||||
);
|
||||
|
||||
const handler = (parser, parserOptions) => {
|
||||
if(typeof parserOptions.commonjs !== "undefined" && !parserOptions.commonjs)
|
||||
return;
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (
|
||||
typeof 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));
|
||||
}
|
||||
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"));
|
||||
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);
|
||||
};
|
||||
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);
|
||||
});
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("CommonJsPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/dynamic")
|
||||
.tap("CommonJsPlugin", handler);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = CommonJsPlugin;
|
||||
|
|
|
@ -16,7 +16,6 @@ class CommonJsRequireContextDependency extends ContextDependency {
|
|||
get type() {
|
||||
return "cjs require context";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CommonJsRequireContextDependency.Template = ContextDependencyTemplateAsRequireCall;
|
||||
|
|
|
@ -21,7 +21,7 @@ class CommonJsRequireDependencyParserPlugin {
|
|||
const options = this.options;
|
||||
|
||||
const processItem = (expr, param) => {
|
||||
if(param.isString()) {
|
||||
if (param.isString()) {
|
||||
const dep = new CommonJsRequireDependency(param.string, param.range);
|
||||
dep.loc = expr.loc;
|
||||
dep.optional = !!parser.scope.inTry;
|
||||
|
@ -30,67 +30,96 @@ class CommonJsRequireDependencyParserPlugin {
|
|||
}
|
||||
};
|
||||
const processContext = (expr, param) => {
|
||||
const dep = ContextDependencyHelpers.create(CommonJsRequireContextDependency, expr.range, param, expr, options);
|
||||
if(!dep) return;
|
||||
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.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;
|
||||
});
|
||||
parser.hooks.call.for("require").tap("CommonJsRequireDependencyParserPlugin", (expr) => {
|
||||
if(expr.arguments.length !== 1) return;
|
||||
let localModule;
|
||||
const param = parser.evaluateExpression(expr.arguments[0]);
|
||||
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);
|
||||
for(const p of param.options) {
|
||||
const result = processItem(expr, p);
|
||||
if(result === undefined) {
|
||||
isExpression = true;
|
||||
}
|
||||
}
|
||||
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);
|
||||
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;
|
||||
} else {
|
||||
const result = processItem(expr, param);
|
||||
if(result === undefined) {
|
||||
processContext(expr, param);
|
||||
} else {
|
||||
});
|
||||
parser.hooks.call
|
||||
.for("require")
|
||||
.tap("CommonJsRequireDependencyParserPlugin", expr => {
|
||||
if (expr.arguments.length !== 1) return;
|
||||
let localModule;
|
||||
const param = parser.evaluateExpression(expr.arguments[0]);
|
||||
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);
|
||||
for (const p of param.options) {
|
||||
const result = processItem(expr, p);
|
||||
if (result === undefined) {
|
||||
isExpression = true;
|
||||
}
|
||||
}
|
||||
if (isExpression) {
|
||||
parser.state.current.dependencies.length = prevLength;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (
|
||||
param.isString() &&
|
||||
(localModule = LocalModulesHelpers.getLocalModule(
|
||||
parser.state,
|
||||
param.string
|
||||
))
|
||||
) {
|
||||
const dep = new LocalModuleDependency(localModule, expr.range);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.current.addDependency(dep);
|
||||
return true;
|
||||
} else {
|
||||
const result = processItem(expr, param);
|
||||
if (result === undefined) {
|
||||
processContext(expr, param);
|
||||
} else {
|
||||
const dep = new RequireHeaderDependency(expr.callee.range);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.current.addDependency(dep);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
module.exports = CommonJsRequireDependencyParserPlugin;
|
||||
|
|
|
@ -21,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;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
const Dependency = require("../Dependency");
|
||||
const CriticalDependencyWarning = require("./CriticalDependencyWarning");
|
||||
|
||||
const regExpToString = r => r ? r + "" : "";
|
||||
const regExpToString = r => (r ? r + "" : "");
|
||||
|
||||
class ContextDependency extends Dependency {
|
||||
// options: { request, recursive, regExp, include, exclude, mode, chunkName }
|
||||
|
@ -15,25 +15,33 @@ class ContextDependency extends Dependency {
|
|||
this.options = options;
|
||||
this.userRequest = this.options.request;
|
||||
this.hadGlobalOrStickyRegExp = false;
|
||||
if(this.options.regExp.global || this.options.regExp.sticky) {
|
||||
if (this.options.regExp.global || this.options.regExp.sticky) {
|
||||
this.options.regExp = null;
|
||||
this.hadGlobalOrStickyRegExp = true;
|
||||
}
|
||||
}
|
||||
|
||||
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}`;
|
||||
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}`
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -42,10 +50,14 @@ class ContextDependency extends Dependency {
|
|||
Object.defineProperty(ContextDependency.prototype, "async", {
|
||||
configurable: false,
|
||||
get() {
|
||||
throw new Error("ContextDependency.async was removed. Use ContextDependency.options.mode instead.");
|
||||
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");
|
||||
throw new Error(
|
||||
"ContextDependency.async was removed. Pass options.mode to constructor instead"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -15,7 +15,14 @@ const quotemeta = str => {
|
|||
return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
|
||||
};
|
||||
|
||||
ContextDependencyHelpers.create = (Dep, range, param, expr, options, contextOptions) => {
|
||||
ContextDependencyHelpers.create = (
|
||||
Dep,
|
||||
range,
|
||||
param,
|
||||
expr,
|
||||
options,
|
||||
contextOptions
|
||||
) => {
|
||||
let dep;
|
||||
let prefix;
|
||||
let postfix;
|
||||
|
@ -24,63 +31,112 @@ ContextDependencyHelpers.create = (Dep, range, param, expr, options, contextOpti
|
|||
let idx;
|
||||
let context;
|
||||
let regExp;
|
||||
if(param.isTemplateString()) {
|
||||
if (param.isTemplateString()) {
|
||||
prefix = param.quasis[0].string;
|
||||
postfix = param.quasis.length > 1 ? param.quasis[param.quasis.length - 1].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) {
|
||||
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(Object.assign({
|
||||
request: context,
|
||||
recursive: options.wrappedContextRecursive,
|
||||
regExp,
|
||||
mode: "sync"
|
||||
}, contextOptions), range, valueRange);
|
||||
regExp = new RegExp(
|
||||
`^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(
|
||||
postfix
|
||||
)}$`
|
||||
);
|
||||
dep = new Dep(
|
||||
Object.assign(
|
||||
{
|
||||
request: context,
|
||||
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";
|
||||
dep.replaces = [
|
||||
{
|
||||
range: prefixRange,
|
||||
value: prefix
|
||||
}
|
||||
];
|
||||
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())) {
|
||||
} 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]];
|
||||
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) {
|
||||
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(Object.assign({
|
||||
request: context,
|
||||
recursive: options.wrappedContextRecursive,
|
||||
regExp,
|
||||
mode: "sync"
|
||||
}, contextOptions), range, valueRange);
|
||||
regExp = new RegExp(
|
||||
`^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(
|
||||
postfix
|
||||
)}$`
|
||||
);
|
||||
dep = new Dep(
|
||||
Object.assign(
|
||||
{
|
||||
request: context,
|
||||
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";
|
||||
dep.critical =
|
||||
options.wrappedContextCritical &&
|
||||
"a part of the request of a dependency is an expression";
|
||||
return dep;
|
||||
} else {
|
||||
dep = new Dep(Object.assign({
|
||||
request: options.exprContextRequest,
|
||||
recursive: options.exprContextRecursive,
|
||||
regExp: options.exprContextRegExp,
|
||||
mode: "sync"
|
||||
}, contextOptions), range, param.range);
|
||||
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";
|
||||
return dep;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,25 +5,34 @@
|
|||
"use strict";
|
||||
|
||||
class ContextDependencyTemplateAsId {
|
||||
|
||||
apply(dep, source, runtime) {
|
||||
const moduleExports = runtime.moduleExports({
|
||||
module: dep.module,
|
||||
request: dep.request
|
||||
});
|
||||
|
||||
if(dep.module) {
|
||||
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, `${moduleExports}.resolve(${typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : ""}`);
|
||||
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, `${moduleExports}.resolve`);
|
||||
source.replace(
|
||||
dep.range[0],
|
||||
dep.range[1] - 1,
|
||||
`${moduleExports}.resolve`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
source.replace(dep.range[0], dep.range[1] - 1, moduleExports);
|
||||
|
|
|
@ -5,23 +5,28 @@
|
|||
"use strict";
|
||||
|
||||
class ContextDependencyTemplateAsRequireCall {
|
||||
|
||||
apply(dep, source, runtime) {
|
||||
const moduleExports = runtime.moduleExports({
|
||||
module: dep.module,
|
||||
request: dep.request
|
||||
});
|
||||
|
||||
if(dep.module) {
|
||||
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, `${moduleExports}(${typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : ""}`);
|
||||
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, moduleExports);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ const ModuleDependency = require("./ModuleDependency");
|
|||
class ContextElementDependency extends ModuleDependency {
|
||||
constructor(request, userRequest) {
|
||||
super(request);
|
||||
if(userRequest) {
|
||||
if (userRequest) {
|
||||
this.userRequest = userRequest;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,17 @@ class HarmonyAcceptDependency extends NullDependency {
|
|||
HarmonyAcceptDependency.Template = class HarmonyAcceptDependencyTemplate {
|
||||
apply(dep, source, runtime) {
|
||||
const content = dep.dependencies
|
||||
.filter(dependency => HarmonyImportDependency.Template.isImportEmitted(dependency, source))
|
||||
.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}(`);
|
||||
if (dep.hasCallback) {
|
||||
source.insert(
|
||||
dep.range[0],
|
||||
`function(__WEBPACK_OUTDATED_DEPENDENCIES__) { ${content}(`
|
||||
);
|
||||
source.insert(dep.range[1], ")(__WEBPACK_OUTDATED_DEPENDENCIES__); }");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ class HarmonyCompatibilityDependency extends NullDependency {
|
|||
HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate {
|
||||
apply(dep, source, runtime) {
|
||||
const usedExports = dep.originModule.usedExports;
|
||||
if(usedExports !== false && !Array.isArray(usedExports)) {
|
||||
if (usedExports !== false && !Array.isArray(usedExports)) {
|
||||
const content = runtime.defineEsModuleFlagStatement({
|
||||
exportsArgument: dep.originModule.exportsArgument
|
||||
});
|
||||
|
|
|
@ -9,12 +9,14 @@ const HarmonyInitDependency = require("./HarmonyInitDependency");
|
|||
|
||||
module.exports = class HarmonyDetectionParserPlugin {
|
||||
apply(parser) {
|
||||
parser.hooks.program.tap("HarmonyDetectionParserPlugin", (ast) => {
|
||||
parser.hooks.program.tap("HarmonyDetectionParserPlugin", ast => {
|
||||
const isStrictHarmony = parser.state.module.type === "javascript/esm";
|
||||
const isHarmony = isStrictHarmony || ast.body.some(statement => {
|
||||
return /^(Import|Export).*Declaration$/.test(statement.type);
|
||||
});
|
||||
if(isHarmony) {
|
||||
const isHarmony =
|
||||
isStrictHarmony ||
|
||||
ast.body.some(statement => {
|
||||
return /^(Import|Export).*Declaration$/.test(statement.type);
|
||||
});
|
||||
if (isHarmony) {
|
||||
const module = parser.state.module;
|
||||
const compatDep = new HarmonyCompatibilityDependency(module);
|
||||
compatDep.loc = {
|
||||
|
@ -47,7 +49,7 @@ module.exports = class HarmonyDetectionParserPlugin {
|
|||
module.buildMeta.exportsType = "namespace";
|
||||
module.buildInfo.strict = true;
|
||||
module.buildInfo.exportsArgument = "__webpack_exports__";
|
||||
if(isStrictHarmony) {
|
||||
if (isStrictHarmony) {
|
||||
module.buildMeta.strictHarmonyModule = true;
|
||||
module.buildInfo.moduleArgument = "__webpack_module__";
|
||||
}
|
||||
|
@ -56,23 +58,33 @@ module.exports = class HarmonyDetectionParserPlugin {
|
|||
|
||||
const skipInHarmony = () => {
|
||||
const module = parser.state.module;
|
||||
if(module && module.buildMeta && module.buildMeta.exportsType)
|
||||
if (module && module.buildMeta && module.buildMeta.exportsType)
|
||||
return true;
|
||||
};
|
||||
|
||||
const nullInHarmony = () => {
|
||||
const module = parser.state.module;
|
||||
if(module && module.buildMeta && module.buildMeta.exportsType)
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,65 +17,123 @@ module.exports = class HarmonyExportDependencyParserPlugin {
|
|||
}
|
||||
|
||||
apply(parser) {
|
||||
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;
|
||||
});
|
||||
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 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.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);
|
||||
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);
|
||||
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.hooks.exportImportSpecifier.tap("HarmonyExportDependencyParserPlugin", (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 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.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(source, parser.state.module, parser.state.lastHarmonyImportOrder, parser.state.harmonyParserScope, id, name, harmonyNamedExports, harmonyStarExports && harmonyStarExports.slice(), this.strictExportPresence);
|
||||
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;
|
||||
});
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -29,7 +29,7 @@ HarmonyExportExpressionDependency.Template = class HarmonyExportDependencyTempla
|
|||
const used = dep.originModule.isUsed("default");
|
||||
const content = this.getContent(dep.originModule, used);
|
||||
|
||||
if(dep.range) {
|
||||
if (dep.range) {
|
||||
source.replace(dep.rangeStatement[0], dep.range[0] - 1, content + "(");
|
||||
source.replace(dep.range[1], dep.rangeStatement[1] - 1, ");");
|
||||
return;
|
||||
|
@ -40,8 +40,10 @@ HarmonyExportExpressionDependency.Template = class HarmonyExportDependencyTempla
|
|||
|
||||
getContent(module, used) {
|
||||
const exportsName = module.exportsArgument;
|
||||
if(used) {
|
||||
return `/* harmony default export */ ${exportsName}[${JSON.stringify(used)}] = `;
|
||||
if (used) {
|
||||
return `/* harmony default export */ ${exportsName}[${JSON.stringify(
|
||||
used
|
||||
)}] = `;
|
||||
}
|
||||
return "/* unused harmony default export */ var _unused_webpack_default_export = ";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,7 +7,17 @@ const HarmonyImportDependency = require("./HarmonyImportDependency");
|
|||
const Template = require("../Template");
|
||||
|
||||
class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
||||
constructor(request, originModule, sourceOrder, parserScope, id, name, activeExports, otherStarExports, strictExportPresence) {
|
||||
constructor(
|
||||
request,
|
||||
originModule,
|
||||
sourceOrder,
|
||||
parserScope,
|
||||
id,
|
||||
name,
|
||||
activeExports,
|
||||
otherStarExports,
|
||||
strictExportPresence
|
||||
) {
|
||||
super(request, originModule, sourceOrder, parserScope);
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
|
@ -26,24 +36,28 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
const used = this.originModule.isUsed(name);
|
||||
const importedModule = this.module;
|
||||
|
||||
if(!importedModule) {
|
||||
if (!importedModule) {
|
||||
return {
|
||||
type: "missing",
|
||||
userRequest: this.userRequest
|
||||
};
|
||||
}
|
||||
|
||||
if(!ignoreUnused && (name ? !used : this.originModule.usedExports === false)) {
|
||||
if (
|
||||
!ignoreUnused &&
|
||||
(name ? !used : this.originModule.usedExports === false)
|
||||
) {
|
||||
return {
|
||||
type: "unused",
|
||||
name: name || "*"
|
||||
};
|
||||
}
|
||||
|
||||
const isNotAHarmonyModule = importedModule.buildMeta && !importedModule.buildMeta.exportsType;
|
||||
const isNotAHarmonyModule =
|
||||
importedModule.buildMeta && !importedModule.buildMeta.exportsType;
|
||||
const strictHarmonyModule = this.originModule.buildMeta.strictHarmonyModule;
|
||||
if(name && id === "default" && isNotAHarmonyModule) {
|
||||
if(strictHarmonyModule) {
|
||||
if (name && id === "default" && isNotAHarmonyModule) {
|
||||
if (strictHarmonyModule) {
|
||||
return {
|
||||
type: "reexport-non-harmony-default-strict",
|
||||
module: importedModule,
|
||||
|
@ -58,10 +72,10 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
}
|
||||
}
|
||||
|
||||
if(name) {
|
||||
if (name) {
|
||||
// export { name as name }
|
||||
if(id) {
|
||||
if(isNotAHarmonyModule && strictHarmonyModule) {
|
||||
if (id) {
|
||||
if (isNotAHarmonyModule && strictHarmonyModule) {
|
||||
return {
|
||||
type: "rexport-non-harmony-undefined",
|
||||
module: importedModule,
|
||||
|
@ -71,15 +85,13 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
return {
|
||||
type: "safe-reexport",
|
||||
module: importedModule,
|
||||
map: new Map([
|
||||
[name, id]
|
||||
])
|
||||
map: new Map([[name, id]])
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// export { * as name }
|
||||
if(isNotAHarmonyModule && strictHarmonyModule) {
|
||||
if (isNotAHarmonyModule && strictHarmonyModule) {
|
||||
return {
|
||||
type: "reexport-fake-namespace-object",
|
||||
module: importedModule,
|
||||
|
@ -95,22 +107,29 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
}
|
||||
|
||||
const hasUsedExports = Array.isArray(this.originModule.usedExports);
|
||||
const hasProvidedExports = Array.isArray(importedModule.buildMeta.providedExports);
|
||||
const hasProvidedExports = Array.isArray(
|
||||
importedModule.buildMeta.providedExports
|
||||
);
|
||||
const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports();
|
||||
|
||||
// export *
|
||||
if(hasUsedExports) {
|
||||
if (hasUsedExports) {
|
||||
// reexport * with known used exports
|
||||
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]));
|
||||
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])
|
||||
);
|
||||
|
||||
if(map.size === 0) {
|
||||
if (map.size === 0) {
|
||||
return {
|
||||
type: "empty-star"
|
||||
};
|
||||
|
@ -123,15 +142,19 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
};
|
||||
}
|
||||
|
||||
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;
|
||||
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]));
|
||||
return true;
|
||||
})
|
||||
.map(item => [item, item])
|
||||
);
|
||||
|
||||
if(map.size === 0) {
|
||||
if (map.size === 0) {
|
||||
return {
|
||||
type: "empty-star"
|
||||
};
|
||||
|
@ -144,19 +167,20 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
};
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
})
|
||||
.map(item => [item, item])
|
||||
return true;
|
||||
})
|
||||
.map(item => [item, item])
|
||||
);
|
||||
|
||||
if(map.size === 0) {
|
||||
if (map.size === 0) {
|
||||
return {
|
||||
type: "empty-star"
|
||||
};
|
||||
|
@ -178,7 +202,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
getReference() {
|
||||
const mode = this.getMode();
|
||||
|
||||
switch(mode.type) {
|
||||
switch (mode.type) {
|
||||
case "missing":
|
||||
case "unused":
|
||||
case "empty-star":
|
||||
|
@ -218,14 +242,16 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
}
|
||||
|
||||
_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) {
|
||||
for (const otherStarExport of this.otherStarExports) {
|
||||
const otherImportedModule = otherStarExport.module;
|
||||
if(otherImportedModule && Array.isArray(otherImportedModule.buildMeta.providedExports)) {
|
||||
for(const exportName of otherImportedModule.buildMeta.providedExports)
|
||||
if (
|
||||
otherImportedModule &&
|
||||
Array.isArray(otherImportedModule.buildMeta.providedExports)
|
||||
) {
|
||||
for (const exportName of otherImportedModule.buildMeta.providedExports)
|
||||
result.add(exportName);
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +259,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
}
|
||||
|
||||
getExports() {
|
||||
if(this.name) {
|
||||
if (this.name) {
|
||||
return {
|
||||
exports: [this.name]
|
||||
};
|
||||
|
@ -241,21 +267,23 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
|
||||
const importedModule = this.module;
|
||||
|
||||
if(!importedModule) {
|
||||
if (!importedModule) {
|
||||
// no imported module available
|
||||
return {
|
||||
exports: null
|
||||
};
|
||||
}
|
||||
|
||||
if(Array.isArray(importedModule.buildMeta.providedExports)) {
|
||||
if (Array.isArray(importedModule.buildMeta.providedExports)) {
|
||||
return {
|
||||
exports: importedModule.buildMeta.providedExports.filter(id => id !== "default"),
|
||||
exports: importedModule.buildMeta.providedExports.filter(
|
||||
id => id !== "default"
|
||||
),
|
||||
dependencies: [importedModule]
|
||||
};
|
||||
}
|
||||
|
||||
if(importedModule.buildMeta.providedExports) {
|
||||
if (importedModule.buildMeta.providedExports) {
|
||||
return {
|
||||
exports: true
|
||||
};
|
||||
|
@ -268,14 +296,20 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
}
|
||||
|
||||
getWarnings() {
|
||||
if(this.strictExportPresence || this.originModule.buildMeta.strictHarmonyModule) {
|
||||
if (
|
||||
this.strictExportPresence ||
|
||||
this.originModule.buildMeta.strictHarmonyModule
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
return this._getErrors();
|
||||
}
|
||||
|
||||
getErrors() {
|
||||
if(this.strictExportPresence || this.originModule.buildMeta.strictHarmonyModule) {
|
||||
if (
|
||||
this.strictExportPresence ||
|
||||
this.originModule.buildMeta.strictHarmonyModule
|
||||
) {
|
||||
return this._getErrors();
|
||||
}
|
||||
return [];
|
||||
|
@ -283,34 +317,46 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
|
||||
_getErrors() {
|
||||
const importedModule = this.module;
|
||||
if(!importedModule) {
|
||||
if (!importedModule) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
|
||||
if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
|
||||
// It's not an harmony module
|
||||
if(this.originModule.buildMeta.strictHarmonyModule && this.id !== "default") {
|
||||
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";
|
||||
const err = new Error(`Can't reexport ${exportName} from non EcmaScript module (only default export is available)`);
|
||||
const exportName = this.id
|
||||
? `the named export '${this.id}'`
|
||||
: "the namespace object";
|
||||
const err = new Error(
|
||||
`Can't reexport ${
|
||||
exportName
|
||||
} from non EcmaScript module (only default export is available)`
|
||||
);
|
||||
err.hideStack = true;
|
||||
return [err];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.id) {
|
||||
if (!this.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(importedModule.isProvided(this.id) !== false) {
|
||||
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}'`;
|
||||
const idIsNotNameMessage =
|
||||
this.id !== this.name ? ` (reexported as '${this.name}')` : "";
|
||||
const errorMessage = `"export '${this.id}'${
|
||||
idIsNotNameMessage
|
||||
} was not found in '${this.userRequest}'`;
|
||||
const err = new Error(errorMessage);
|
||||
err.hideStack = true;
|
||||
return [err];
|
||||
|
@ -323,13 +369,17 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
}
|
||||
|
||||
getHashValue(importedModule) {
|
||||
if(!importedModule) {
|
||||
if (!importedModule) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const stringifiedUsedExport = JSON.stringify(importedModule.usedExports);
|
||||
const stringifiedProvidedExport = JSON.stringify(importedModule.buildMeta.providedExports);
|
||||
return importedModule.used + stringifiedUsedExport + stringifiedProvidedExport;
|
||||
const stringifiedProvidedExport = JSON.stringify(
|
||||
importedModule.buildMeta.providedExports
|
||||
);
|
||||
return (
|
||||
importedModule.used + stringifiedUsedExport + stringifiedProvidedExport
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,36 +393,39 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
}
|
||||
|
||||
getHarmonyInitOrder(dep) {
|
||||
if(dep.name) {
|
||||
if (dep.name) {
|
||||
const used = dep.originModule.isUsed(dep.name);
|
||||
if(!used) return NaN;
|
||||
if (!used) return NaN;
|
||||
} else {
|
||||
const importedModule = dep.module;
|
||||
|
||||
const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports();
|
||||
|
||||
if(Array.isArray(dep.originModule.usedExports)) {
|
||||
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;
|
||||
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)) {
|
||||
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;
|
||||
if (id === "default") return true;
|
||||
if (dep.activeExports.has(id)) return true;
|
||||
if (activeFromOtherStarExports.has(id)) return true;
|
||||
return false;
|
||||
});
|
||||
if(unused) return NaN;
|
||||
if (unused) return NaN;
|
||||
}
|
||||
}
|
||||
return super.getHarmonyInitOrder(dep);
|
||||
|
@ -384,55 +437,134 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
const importedModule = dep.module;
|
||||
const importVar = dep.getImportVar();
|
||||
|
||||
switch(mode.type) {
|
||||
switch (mode.type) {
|
||||
case "missing":
|
||||
return `throw new Error(${JSON.stringify(`Cannot find module '${mode.userRequest}'`)});\n`;
|
||||
return `throw new Error(${JSON.stringify(
|
||||
`Cannot find module '${mode.userRequest}'`
|
||||
)});\n`;
|
||||
|
||||
case "unused":
|
||||
return `${Template.toNormalComment(`unused harmony reexport ${mode.name}`)}\n`;
|
||||
return `${Template.toNormalComment(
|
||||
`unused harmony reexport ${mode.name}`
|
||||
)}\n`;
|
||||
|
||||
case "reexport-non-harmony-default":
|
||||
return "/* harmony reexport (default from non-hamory) */ " + this.getReexportStatement(module, module.isUsed(mode.name), importVar, null);
|
||||
return (
|
||||
"/* harmony reexport (default from non-hamory) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.isUsed(mode.name),
|
||||
importVar,
|
||||
null
|
||||
)
|
||||
);
|
||||
|
||||
case "reexport-fake-namespace-object":
|
||||
return "/* harmony reexport (fake namespace object from non-hamory) */ " + this.getReexportFakeNamespaceObjectStatement(module, module.isUsed(mode.name), importVar);
|
||||
return (
|
||||
"/* harmony reexport (fake namespace object from non-hamory) */ " +
|
||||
this.getReexportFakeNamespaceObjectStatement(
|
||||
module,
|
||||
module.isUsed(mode.name),
|
||||
importVar
|
||||
)
|
||||
);
|
||||
|
||||
case "rexport-non-harmony-undefined":
|
||||
return "/* harmony reexport (non default export from non-hamory) */ " + this.getReexportStatement(module, module.isUsed(mode.name), "undefined", "");
|
||||
return (
|
||||
"/* harmony reexport (non default export from non-hamory) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.isUsed(mode.name),
|
||||
"undefined",
|
||||
""
|
||||
)
|
||||
);
|
||||
|
||||
case "reexport-non-harmony-default-strict":
|
||||
return "/* harmony reexport (default from non-hamory) */ " + this.getReexportStatement(module, module.isUsed(mode.name), importVar, "");
|
||||
return (
|
||||
"/* harmony reexport (default from non-hamory) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.isUsed(mode.name),
|
||||
importVar,
|
||||
""
|
||||
)
|
||||
);
|
||||
|
||||
case "reexport-namespace-object":
|
||||
return "/* harmony reexport (module object) */ " + this.getReexportStatement(module, module.isUsed(mode.name), importVar, "");
|
||||
return (
|
||||
"/* harmony reexport (module object) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.isUsed(mode.name),
|
||||
importVar,
|
||||
""
|
||||
)
|
||||
);
|
||||
|
||||
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("");
|
||||
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("");
|
||||
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 + ") ";
|
||||
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.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;
|
||||
return content + `(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${importVar}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`;
|
||||
}
|
||||
// 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;
|
||||
return (
|
||||
content +
|
||||
`(function(key) { __webpack_require__.d(${
|
||||
exportsName
|
||||
}, key, function() { return ${
|
||||
importVar
|
||||
}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown mode ${mode.type}`);
|
||||
|
@ -442,22 +574,30 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
getReexportStatement(module, key, name, valueKey) {
|
||||
const exportsName = module.exportsArgument;
|
||||
const returnValue = this.getReturnValue(valueKey);
|
||||
return `__webpack_require__.d(${exportsName}, ${JSON.stringify(key)}, function() { return ${name}${returnValue}; });\n`;
|
||||
return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
|
||||
key
|
||||
)}, function() { return ${name}${returnValue}; });\n`;
|
||||
}
|
||||
|
||||
getReexportFakeNamespaceObjectStatement(module, key, name) {
|
||||
const exportsName = module.exportsArgument;
|
||||
return `__webpack_require__.d(${exportsName}, ${JSON.stringify(key)}, function() { return { "default": ${name} }; });\n`;
|
||||
return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
|
||||
key
|
||||
)}, function() { return { "default": ${name} }; });\n`;
|
||||
}
|
||||
|
||||
getConditionalReexportStatement(module, key, name, valueKey) {
|
||||
const exportsName = module.exportsArgument;
|
||||
const returnValue = this.getReturnValue(valueKey);
|
||||
return `if(__webpack_require__.o(${name}, ${JSON.stringify(valueKey)})) __webpack_require__.d(${exportsName}, ${JSON.stringify(key)}, function() { return ${name}${returnValue}; });\n`;
|
||||
return `if(__webpack_require__.o(${name}, ${JSON.stringify(
|
||||
valueKey
|
||||
)})) __webpack_require__.d(${exportsName}, ${JSON.stringify(
|
||||
key
|
||||
)}, function() { return ${name}${returnValue}; });\n`;
|
||||
}
|
||||
|
||||
getReturnValue(valueKey) {
|
||||
if(valueKey === null) {
|
||||
if (valueKey === null) {
|
||||
return "_default.a";
|
||||
}
|
||||
|
||||
|
|
|
@ -38,13 +38,15 @@ HarmonyExportSpecifierDependency.Template = class HarmonyExportSpecifierDependen
|
|||
|
||||
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;
|
||||
|
||||
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`;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class HarmonyImportDependency extends ModuleDependency {
|
|||
}
|
||||
|
||||
getReference() {
|
||||
if(!this.module) return null;
|
||||
if (!this.module) return null;
|
||||
|
||||
return {
|
||||
module: this.module,
|
||||
|
@ -26,10 +26,12 @@ class HarmonyImportDependency extends ModuleDependency {
|
|||
|
||||
getImportVar() {
|
||||
let importVarMap = this.parserScope.importVarMap;
|
||||
if(!importVarMap) this.parserScope.importVarMap = importVarMap = new Map();
|
||||
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}__`;
|
||||
if (importVar) return importVar;
|
||||
importVar = `${Template.toIdentifier(
|
||||
`${this.userRequest}`
|
||||
)}__WEBPACK_IMPORTED_MODULE_${importVarMap.size}__`;
|
||||
importVarMap.set(this.module, importVar);
|
||||
return importVar;
|
||||
}
|
||||
|
@ -47,7 +49,11 @@ class HarmonyImportDependency extends ModuleDependency {
|
|||
updateHash(hash) {
|
||||
super.updateHash(hash);
|
||||
const importedModule = this.module;
|
||||
hash.update((importedModule && (!importedModule.buildMeta || importedModule.buildMeta.exportsType)) + "");
|
||||
hash.update(
|
||||
(importedModule &&
|
||||
(!importedModule.buildMeta || importedModule.buildMeta.exportsType)) +
|
||||
""
|
||||
);
|
||||
hash.update((importedModule && importedModule.id) + "");
|
||||
}
|
||||
}
|
||||
|
@ -65,20 +71,23 @@ HarmonyImportDependency.Template = class HarmonyImportDependencyTemplate {
|
|||
|
||||
static isImportEmitted(dep, source) {
|
||||
let sourceInfo = importEmittedMap.get(source);
|
||||
if(!sourceInfo) return false;
|
||||
if (!sourceInfo) return false;
|
||||
const key = dep.module || dep.request;
|
||||
return key && sourceInfo.emittedImports.get(key);
|
||||
}
|
||||
|
||||
harmonyInit(dep, source, runtime) {
|
||||
let sourceInfo = importEmittedMap.get(source);
|
||||
if(!sourceInfo) {
|
||||
importEmittedMap.set(source, sourceInfo = {
|
||||
emittedImports: new Map()
|
||||
});
|
||||
if (!sourceInfo) {
|
||||
importEmittedMap.set(
|
||||
source,
|
||||
(sourceInfo = {
|
||||
emittedImports: new Map()
|
||||
})
|
||||
);
|
||||
}
|
||||
const key = dep.module || dep.request;
|
||||
if(key && sourceInfo.emittedImports.get(key)) return;
|
||||
if (key && sourceInfo.emittedImports.get(key)) return;
|
||||
sourceInfo.emittedImports.set(key, true);
|
||||
const content = dep.getImportStatement(false, runtime);
|
||||
source.insert(-1, content);
|
||||
|
|
|
@ -18,118 +18,197 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
}
|
||||
|
||||
apply(parser) {
|
||||
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 = 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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
dep.directImport = true;
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
if(expr.arguments)
|
||||
parser.walkExpressions(expr.arguments);
|
||||
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.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;
|
||||
});
|
||||
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 dependencies = requests
|
||||
.map(request => {
|
||||
const dep = new HarmonyAcceptImportDependency(request, parser.state.module, parser.state.harmonyParserScope);
|
||||
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 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, true);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
if (dependencies.length > 0) {
|
||||
const dep = new HarmonyAcceptDependency(
|
||||
expr.range,
|
||||
dependencies,
|
||||
true
|
||||
);
|
||||
dep.loc = expr.loc;
|
||||
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);
|
||||
);
|
||||
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.module.addDependency(dep);
|
||||
if (dependencies.length > 0) {
|
||||
const dep = new HarmonyAcceptDependency(
|
||||
expr.range,
|
||||
dependencies,
|
||||
false
|
||||
);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ class HarmonyImportSideEffectDependency extends HarmonyImportDependency {
|
|||
}
|
||||
|
||||
getReference() {
|
||||
if(this.module && this.module.factoryMeta.sideEffectFree) return null;
|
||||
if (this.module && this.module.factoryMeta.sideEffectFree) return null;
|
||||
|
||||
return super.getReference();
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class HarmonyImportSideEffectDependency extends HarmonyImportDependency {
|
|||
|
||||
HarmonyImportSideEffectDependency.Template = class HarmonyImportSideEffectDependencyTemplate extends HarmonyImportDependency.Template {
|
||||
getHarmonyInitOrder(dep) {
|
||||
if(dep.module && dep.module.factoryMeta.sideEffectFree) return NaN;
|
||||
if (dep.module && dep.module.factoryMeta.sideEffectFree) return NaN;
|
||||
return super.getHarmonyInitOrder(dep);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,7 +6,16 @@
|
|||
const HarmonyImportDependency = require("./HarmonyImportDependency");
|
||||
|
||||
class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
||||
constructor(request, originModule, sourceOrder, parserScope, id, name, range, strictExportPresence) {
|
||||
constructor(
|
||||
request,
|
||||
originModule,
|
||||
sourceOrder,
|
||||
parserScope,
|
||||
id,
|
||||
name,
|
||||
range,
|
||||
strictExportPresence
|
||||
) {
|
||||
super(request, originModule, sourceOrder, parserScope);
|
||||
this.id = id === null ? null : `${id}`;
|
||||
this.name = name;
|
||||
|
@ -23,22 +32,29 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
|||
}
|
||||
|
||||
getReference() {
|
||||
if(!this.module) return null;
|
||||
if (!this.module) return null;
|
||||
return {
|
||||
module: this.module,
|
||||
importedNames: this.id && !this.namespaceObjectAsContext ? [this.id] : true
|
||||
importedNames:
|
||||
this.id && !this.namespaceObjectAsContext ? [this.id] : true
|
||||
};
|
||||
}
|
||||
|
||||
getWarnings() {
|
||||
if(this.strictExportPresence || this.originModule.buildMeta.strictHarmonyModule) {
|
||||
if (
|
||||
this.strictExportPresence ||
|
||||
this.originModule.buildMeta.strictHarmonyModule
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
return this._getErrors();
|
||||
}
|
||||
|
||||
getErrors() {
|
||||
if(this.strictExportPresence || this.originModule.buildMeta.strictHarmonyModule) {
|
||||
if (
|
||||
this.strictExportPresence ||
|
||||
this.originModule.buildMeta.strictHarmonyModule
|
||||
) {
|
||||
return this._getErrors();
|
||||
}
|
||||
return [];
|
||||
|
@ -46,34 +62,46 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
|||
|
||||
_getErrors() {
|
||||
const importedModule = this.module;
|
||||
if(!importedModule) {
|
||||
if (!importedModule) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
|
||||
if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
|
||||
// It's not an harmony module
|
||||
if(this.originModule.buildMeta.strictHarmonyModule && this.id !== "default") {
|
||||
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";
|
||||
const err = new Error(`Can't import ${exportName} from non EcmaScript module (only default export is available)`);
|
||||
const exportName = this.id
|
||||
? `the named export '${this.id}'`
|
||||
: "the namespace object";
|
||||
const err = new Error(
|
||||
`Can't import ${
|
||||
exportName
|
||||
} from non EcmaScript module (only default export is available)`
|
||||
);
|
||||
err.hideStack = true;
|
||||
return [err];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.id) {
|
||||
if (!this.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(importedModule.isProvided(this.id) !== false) {
|
||||
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}'`;
|
||||
const idIsNotNameMessage =
|
||||
this.id !== this.name ? ` (imported as '${this.name}')` : "";
|
||||
const errorMessage = `"export '${this.id}'${
|
||||
idIsNotNameMessage
|
||||
} was not found in '${this.userRequest}'`;
|
||||
const err = new Error(errorMessage);
|
||||
err.hideStack = true;
|
||||
return [err];
|
||||
|
@ -88,9 +116,18 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
|||
super.updateHash(hash);
|
||||
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))) + "");
|
||||
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)) + ""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,16 +23,20 @@ HarmonyInitDependency.Template = class HarmonyInitDependencyTemplate {
|
|||
apply(dep, source, runtime, dependencyTemplates) {
|
||||
const module = dep.originModule;
|
||||
const list = [];
|
||||
for(const dependency of module.dependencies) {
|
||||
for (const dependency of module.dependencies) {
|
||||
const template = dependencyTemplates.get(dependency.constructor);
|
||||
if(template && typeof template.harmonyInit === "function" && typeof template.getHarmonyInitOrder === "function") {
|
||||
if (
|
||||
template &&
|
||||
typeof template.harmonyInit === "function" &&
|
||||
typeof template.getHarmonyInitOrder === "function"
|
||||
) {
|
||||
const order = template.getHarmonyInitOrder(dependency);
|
||||
if(!isNaN(order)) {
|
||||
if (!isNaN(order)) {
|
||||
list.push({
|
||||
order,
|
||||
listOrder: list.length,
|
||||
dependency,
|
||||
template,
|
||||
template
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -40,12 +44,17 @@ HarmonyInitDependency.Template = class HarmonyInitDependencyTemplate {
|
|||
|
||||
list.sort((a, b) => {
|
||||
const x = a.order - b.order;
|
||||
if(x) return x;
|
||||
if (x) return x;
|
||||
return a.listOrder - b.listOrder;
|
||||
});
|
||||
|
||||
for(const item of list) {
|
||||
item.template.harmonyInit(item.dependency, source, runtime, dependencyTemplates);
|
||||
for (const item of list) {
|
||||
item.template.harmonyInit(
|
||||
item.dependency,
|
||||
source,
|
||||
runtime,
|
||||
dependencyTemplates
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,52 +27,120 @@ class HarmonyModulesPlugin {
|
|||
}
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("HarmonyModulesPlugin", (compilation, {
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(HarmonyCompatibilityDependency, new NullFactory());
|
||||
compilation.dependencyTemplates.set(HarmonyCompatibilityDependency, new HarmonyCompatibilityDependency.Template());
|
||||
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(
|
||||
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(
|
||||
HarmonyImportSideEffectDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
HarmonyImportSideEffectDependency,
|
||||
new HarmonyImportSideEffectDependency.Template()
|
||||
);
|
||||
|
||||
compilation.dependencyFactories.set(HarmonyImportSpecifierDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(HarmonyImportSpecifierDependency, new HarmonyImportSpecifierDependency.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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
HarmonyAcceptDependency,
|
||||
new NullFactory()
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
HarmonyAcceptDependency,
|
||||
new HarmonyAcceptDependency.Template()
|
||||
);
|
||||
|
||||
compilation.dependencyFactories.set(HarmonyAcceptImportDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(HarmonyAcceptImportDependency, new HarmonyAcceptImportDependency.Template());
|
||||
compilation.dependencyFactories.set(
|
||||
HarmonyAcceptImportDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
HarmonyAcceptImportDependency,
|
||||
new HarmonyAcceptImportDependency.Template()
|
||||
);
|
||||
|
||||
const handler = (parser, parserOptions) => {
|
||||
if(typeof parserOptions.harmony !== "undefined" && !parserOptions.harmony)
|
||||
return;
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (
|
||||
typeof 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);
|
||||
};
|
||||
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);
|
||||
});
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("HarmonyModulesPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/esm")
|
||||
.tap("HarmonyModulesPlugin", handler);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = HarmonyModulesPlugin;
|
||||
|
|
|
@ -8,17 +8,18 @@ const ConstDependency = require("./ConstDependency");
|
|||
|
||||
class HarmonyTopLevelThisParserPlugin {
|
||||
apply(parser) {
|
||||
parser.hooks.expression.for("this").tap("HarmonyTopLevelThisParserPlugin", node => {
|
||||
if(!parser.scope.topLevelScope)
|
||||
return;
|
||||
const module = parser.state.module;
|
||||
const isHarmony = !!(module.buildMeta && module.buildMeta.exportsType);
|
||||
if(isHarmony) {
|
||||
const dep = new ConstDependency("undefined", node.range, false);
|
||||
dep.loc = node.loc;
|
||||
parser.state.current.addDependency(dep);
|
||||
}
|
||||
});
|
||||
parser.hooks.expression
|
||||
.for("this")
|
||||
.tap("HarmonyTopLevelThisParserPlugin", node => {
|
||||
if (!parser.scope.topLevelScope) return;
|
||||
const module = parser.state.module;
|
||||
const isHarmony = !!(module.buildMeta && module.buildMeta.exportsType);
|
||||
if (isHarmony) {
|
||||
const dep = new ConstDependency("undefined", node.range, false);
|
||||
dep.loc = node.loc;
|
||||
parser.state.current.addDependency(dep);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ class ImportContextDependency extends ContextDependency {
|
|||
get type() {
|
||||
return `import() context ${this.options.mode}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ImportContextDependency.Template = ContextDependencyTemplateAsRequireCall;
|
||||
|
|
|
@ -18,8 +18,10 @@ class ImportParserPlugin {
|
|||
|
||||
apply(parser) {
|
||||
parser.hooks.importCall.tap("ImportParserPlugin", expr => {
|
||||
if(expr.arguments.length !== 1)
|
||||
throw new Error("Incorrect number of arguments provided to 'import(module: string) -> Promise'.");
|
||||
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]);
|
||||
|
||||
|
@ -29,68 +31,143 @@ class ImportParserPlugin {
|
|||
let exclude = null;
|
||||
|
||||
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 (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;
|
||||
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;
|
||||
}
|
||||
if(typeof 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}.`));
|
||||
if (typeof 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
|
||||
}.`
|
||||
)
|
||||
);
|
||||
} else {
|
||||
include = new RegExp(importOptions.webpackInclude);
|
||||
}
|
||||
}
|
||||
if(typeof 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}.`));
|
||||
if (typeof 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
|
||||
}.`
|
||||
)
|
||||
);
|
||||
} 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}.`));
|
||||
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(mode === "eager") {
|
||||
const dep = new ImportEagerDependency(param.string, parser.state.module, 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, parser.state.module, 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, parser.state.module);
|
||||
const depBlock = new ImportDependenciesBlock(
|
||||
param.string,
|
||||
expr.range,
|
||||
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
|
||||
}.`
|
||||
)
|
||||
);
|
||||
mode = "lazy";
|
||||
}
|
||||
|
||||
if(mode === "weak") {
|
||||
if (mode === "weak") {
|
||||
mode = "async-weak";
|
||||
}
|
||||
const dep = ContextDependencyHelpers.create(ImportContextDependency, expr.range, param, expr, this.options, {
|
||||
chunkName,
|
||||
include,
|
||||
exclude,
|
||||
mode,
|
||||
namespaceObject: parser.state.module.buildMeta.strictHarmonyModule ? "strict" : true
|
||||
});
|
||||
if(!dep) return;
|
||||
const dep = ContextDependencyHelpers.create(
|
||||
ImportContextDependency,
|
||||
expr.range,
|
||||
param,
|
||||
expr,
|
||||
this.options,
|
||||
{
|
||||
chunkName,
|
||||
include,
|
||||
exclude,
|
||||
mode,
|
||||
namespaceObject: parser.state.module.buildMeta.strictHarmonyModule
|
||||
? "strict"
|
||||
: true
|
||||
}
|
||||
);
|
||||
if (!dep) return;
|
||||
dep.loc = expr.loc;
|
||||
dep.optional = !!parser.scope.inTry;
|
||||
parser.state.current.addDependency(dep);
|
||||
|
|
|
@ -17,33 +17,66 @@ class ImportPlugin {
|
|||
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
compiler.hooks.compilation.tap("ImportPlugin", (compilation, {
|
||||
contextModuleFactory,
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(ImportDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(ImportDependency, new ImportDependency.Template());
|
||||
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(
|
||||
ImportEagerDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
ImportEagerDependency,
|
||||
new ImportEagerDependency.Template()
|
||||
);
|
||||
|
||||
compilation.dependencyFactories.set(ImportWeakDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(ImportWeakDependency, new ImportWeakDependency.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());
|
||||
compilation.dependencyFactories.set(
|
||||
ImportContextDependency,
|
||||
contextModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
ImportContextDependency,
|
||||
new ImportContextDependency.Template()
|
||||
);
|
||||
|
||||
const handler = (parser, parserOptions) => {
|
||||
if(typeof parserOptions.import !== "undefined" && !parserOptions.import)
|
||||
return;
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (
|
||||
typeof parserOptions.import !== "undefined" &&
|
||||
!parserOptions.import
|
||||
)
|
||||
return;
|
||||
|
||||
new ImportParserPlugin(options).apply(parser);
|
||||
};
|
||||
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);
|
||||
});
|
||||
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;
|
||||
|
|
|
@ -7,56 +7,83 @@
|
|||
const LoaderDependency = require("./LoaderDependency");
|
||||
|
||||
class LoaderPlugin {
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("LoaderPlugin", (compilation, {
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(LoaderDependency, normalModuleFactory);
|
||||
});
|
||||
compiler.hooks.compilation.tap(
|
||||
"LoaderPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
compilation.dependencyFactories.set(
|
||||
LoaderDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
compiler.hooks.compilation.tap("LoaderPlugin", (compilation) => {
|
||||
compilation.hooks.normalModuleLoader.tap("LoaderPlugin", (loaderContext, module) => {
|
||||
loaderContext.loadModule = (request, callback) => {
|
||||
const dep = new LoaderDependency(request);
|
||||
dep.loc = 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.addModuleDependencies(module, [{
|
||||
factory,
|
||||
dependencies: [dep]
|
||||
}], true, "lm", false, err => {
|
||||
if(err) return callback(err);
|
||||
compiler.hooks.compilation.tap("LoaderPlugin", compilation => {
|
||||
compilation.hooks.normalModuleLoader.tap(
|
||||
"LoaderPlugin",
|
||||
(loaderContext, module) => {
|
||||
loaderContext.loadModule = (request, callback) => {
|
||||
const dep = new LoaderDependency(request);
|
||||
dep.loc = 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.addModuleDependencies(
|
||||
module,
|
||||
[
|
||||
{
|
||||
factory,
|
||||
dependencies: [dep]
|
||||
}
|
||||
],
|
||||
true,
|
||||
"lm",
|
||||
false,
|
||||
err => {
|
||||
if (err) return callback(err);
|
||||
|
||||
if(!dep.module) return callback(new Error("Cannot load the module"));
|
||||
if (!dep.module)
|
||||
return callback(new Error("Cannot load the module"));
|
||||
|
||||
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.buildInfo.fileDependencies) {
|
||||
for(const d of dep.module.buildInfo.fileDependencies) {
|
||||
loaderContext.addDependency(d);
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
if(dep.module.buildInfo.contextDependencies) {
|
||||
for(const d of dep.module.buildInfo.contextDependencies) {
|
||||
loaderContext.addContextDependency(d);
|
||||
}
|
||||
}
|
||||
return callback(null, source, map, dep.module);
|
||||
});
|
||||
};
|
||||
});
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,12 @@ class LocalModuleDependency extends NullDependency {
|
|||
|
||||
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;
|
||||
source.replace(
|
||||
dep.range[0],
|
||||
dep.range[1] - 1,
|
||||
dep.localModule.variableName()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,37 +8,36 @@ 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("/");
|
||||
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)
|
||||
return state.localModules[i];
|
||||
for (let i = 0; i < state.localModules.length; i++) {
|
||||
if (state.localModules[i].name === name) return state.localModules[i];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
"use strict";
|
||||
|
||||
class ModuleDependencyTemplateAsId {
|
||||
|
||||
apply(dep, source, runtime) {
|
||||
if(!dep.range) return;
|
||||
if (!dep.range) return;
|
||||
const content = runtime.moduleId({
|
||||
module: dep.module,
|
||||
request: dep.request
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
"use strict";
|
||||
|
||||
class ModuleDependencyTemplateAsRequireId {
|
||||
|
||||
apply(dep, source, runtime) {
|
||||
if(!dep.range) return;
|
||||
if (!dep.range) return;
|
||||
const content = runtime.moduleExports({
|
||||
module: dep.module,
|
||||
request: dep.request
|
||||
|
|
|
@ -8,48 +8,49 @@ const RequireContextDependency = require("./RequireContextDependency");
|
|||
|
||||
module.exports = class RequireContextDependencyParserPlugin {
|
||||
apply(parser) {
|
||||
parser.hooks.call.for("require.context").tap("RequireContextDependencyParserPlugin", expr => {
|
||||
let regExp = /^\.\/.*$/;
|
||||
let recursive = true;
|
||||
let mode = "sync";
|
||||
switch(expr.arguments.length) {
|
||||
case 4:
|
||||
{
|
||||
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;
|
||||
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({
|
||||
request: requestExpr.string,
|
||||
recursive,
|
||||
regExp,
|
||||
mode
|
||||
}, 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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,9 +11,9 @@ 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;
|
||||
|
@ -21,75 +21,121 @@ class RequireContextPlugin {
|
|||
}
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("RequireContextPlugin", (compilation, {
|
||||
contextModuleFactory,
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(RequireContextDependency, contextModuleFactory);
|
||||
compilation.dependencyTemplates.set(RequireContextDependency, new RequireContextDependency.Template());
|
||||
compiler.hooks.compilation.tap(
|
||||
"RequireContextPlugin",
|
||||
(compilation, { contextModuleFactory, normalModuleFactory }) => {
|
||||
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(typeof parserOptions.requireContext !== "undefined" && !parserOptions.requireContext)
|
||||
return;
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (
|
||||
typeof parserOptions.requireContext !== "undefined" &&
|
||||
!parserOptions.requireContext
|
||||
)
|
||||
return;
|
||||
|
||||
new RequireContextDependencyParserPlugin().apply(parser);
|
||||
};
|
||||
new RequireContextDependencyParserPlugin().apply(parser);
|
||||
};
|
||||
|
||||
normalModuleFactory.hooks.parser.for("javascript/auto").tap("RequireContextPlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("RequireContextPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("RequireContextPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/dynamic")
|
||||
.tap("RequireContextPlugin", handler);
|
||||
|
||||
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), []);
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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) {
|
||||
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,59 +10,74 @@ const getFunctionExpression = require("./getFunctionExpression");
|
|||
|
||||
module.exports = class RequireEnsureDependenciesBlockParserPlugin {
|
||||
apply(parser) {
|
||||
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:
|
||||
{
|
||||
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([], () => {
|
||||
for(const ee of dependenciesItems) {
|
||||
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,
|
||||
ee.range
|
||||
);
|
||||
edep.loc = dep.loc;
|
||||
dep.addDependency(edep);
|
||||
} else {
|
||||
|
@ -70,33 +85,31 @@ module.exports = class RequireEnsureDependenciesBlockParserPlugin {
|
|||
}
|
||||
}
|
||||
});
|
||||
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
|
||||
parser.walkExpression(successExpression.fn.body);
|
||||
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
|
||||
parser.walkExpression(errorExpression.fn.body);
|
||||
} else if(errorExpressionArg) {
|
||||
else parser.walkExpression(errorExpression.fn.body);
|
||||
} else if (errorExpressionArg) {
|
||||
parser.walkExpression(errorExpressionArg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,16 +23,34 @@ RequireEnsureDependency.Template = class RequireEnsureDependencyTemplate {
|
|||
block: depBlock,
|
||||
message: "require.ensure"
|
||||
});
|
||||
const errorCallbackExists = depBlock.expr.arguments.length === 4 || (!depBlock.chunkName && depBlock.expr.arguments.length === 3);
|
||||
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, ")");
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,29 +14,61 @@ const RequireEnsureDependenciesBlockParserPlugin = require("./RequireEnsureDepen
|
|||
const ParserHelpers = require("../ParserHelpers");
|
||||
|
||||
class RequireEnsurePlugin {
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("RequireEnsurePlugin", (compilation, {
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(RequireEnsureItemDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(RequireEnsureItemDependency, new RequireEnsureItemDependency.Template());
|
||||
compiler.hooks.compilation.tap(
|
||||
"RequireEnsurePlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
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(typeof parserOptions.requireEnsure !== "undefined" && !parserOptions.requireEnsure)
|
||||
return;
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (
|
||||
typeof parserOptions.requireEnsure !== "undefined" &&
|
||||
!parserOptions.requireEnsure
|
||||
)
|
||||
return;
|
||||
|
||||
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")));
|
||||
};
|
||||
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")
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
normalModuleFactory.hooks.parser.for("javascript/auto").tap("RequireEnsurePlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("RequireEnsurePlugin", handler);
|
||||
});
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("RequireEnsurePlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/dynamic")
|
||||
.tap("RequireEnsurePlugin", handler);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = RequireEnsurePlugin;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class RequireIncludeDependency extends ModuleDependency {
|
|||
}
|
||||
|
||||
getReference() {
|
||||
if(!this.module) return null;
|
||||
if (!this.module) return null;
|
||||
return {
|
||||
module: this.module,
|
||||
importedNames: [] // This doesn't use any export
|
||||
|
@ -28,7 +28,11 @@ class RequireIncludeDependency extends ModuleDependency {
|
|||
|
||||
RequireIncludeDependency.Template = class RequireIncludeDependencyTemplate {
|
||||
apply(dep, source, runtime) {
|
||||
const comment = runtime.outputOptions.pathinfo ? Template.toComment(`require.include ${runtime.requestShortener.shorten(dep.request)}`) : "";
|
||||
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}`);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,14 +8,16 @@ const RequireIncludeDependency = require("./RequireIncludeDependency");
|
|||
|
||||
module.exports = class RequireIncludeDependencyParserPlugin {
|
||||
apply(parser) {
|
||||
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;
|
||||
});
|
||||
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;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,24 +11,51 @@ const ParserHelpers = require("../ParserHelpers");
|
|||
|
||||
class RequireIncludePlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("RequireIncludePlugin", (compilation, {
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
compilation.dependencyFactories.set(RequireIncludeDependency, normalModuleFactory);
|
||||
compilation.dependencyTemplates.set(RequireIncludeDependency, new RequireIncludeDependency.Template());
|
||||
compiler.hooks.compilation.tap(
|
||||
"RequireIncludePlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
compilation.dependencyFactories.set(
|
||||
RequireIncludeDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
RequireIncludeDependency,
|
||||
new RequireIncludeDependency.Template()
|
||||
);
|
||||
|
||||
const handler = (parser, parserOptions) => {
|
||||
if(typeof parserOptions.requireInclude !== "undefined" && !parserOptions.requireInclude)
|
||||
return;
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (
|
||||
typeof parserOptions.requireInclude !== "undefined" &&
|
||||
!parserOptions.requireInclude
|
||||
)
|
||||
return;
|
||||
|
||||
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")));
|
||||
};
|
||||
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")
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
normalModuleFactory.hooks.parser.for("javascript/auto").tap("RequireIncludePlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("RequireIncludePlugin", handler);
|
||||
});
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("RequireIncludePlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/dynamic")
|
||||
.tap("RequireIncludePlugin", handler);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = RequireIncludePlugin;
|
||||
|
|
|
@ -16,7 +16,6 @@ class RequireResolveContextDependency extends ContextDependency {
|
|||
get type() {
|
||||
return "amd require context";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RequireResolveContextDependency.Template = ContextDependencyTemplateAsId;
|
||||
|
|
|
@ -18,12 +18,12 @@ class RequireResolveDependencyParserPlugin {
|
|||
const options = this.options;
|
||||
|
||||
const process = (expr, weak) => {
|
||||
if(expr.arguments.length !== 1) return;
|
||||
if (expr.arguments.length !== 1) return;
|
||||
const param = parser.evaluateExpression(expr.arguments[0]);
|
||||
if(param.isConditional()) {
|
||||
for(const option of param.options) {
|
||||
if (param.isConditional()) {
|
||||
for (const option of param.options) {
|
||||
const result = processItem(expr, option, weak);
|
||||
if(result === undefined) {
|
||||
if (result === undefined) {
|
||||
processContext(expr, option, weak);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class RequireResolveDependencyParserPlugin {
|
|||
return true;
|
||||
} else {
|
||||
const result = processItem(expr, param, weak);
|
||||
if(result === undefined) {
|
||||
if (result === undefined) {
|
||||
processContext(expr, param, weak);
|
||||
}
|
||||
const dep = new RequireResolveHeaderDependency(expr.callee.range);
|
||||
|
@ -43,7 +43,7 @@ class RequireResolveDependencyParserPlugin {
|
|||
}
|
||||
};
|
||||
const processItem = (expr, param, weak) => {
|
||||
if(param.isString()) {
|
||||
if (param.isString()) {
|
||||
const dep = new RequireResolveDependency(param.string, param.range);
|
||||
dep.loc = expr.loc;
|
||||
dep.optional = !!parser.scope.inTry;
|
||||
|
@ -53,22 +53,33 @@ class RequireResolveDependencyParserPlugin {
|
|||
}
|
||||
};
|
||||
const processContext = (expr, param, weak) => {
|
||||
const dep = ContextDependencyHelpers.create(RequireResolveContextDependency, param.range, param, expr, options, {
|
||||
mode: weak ? "weak" : "sync"
|
||||
});
|
||||
if(!dep) return;
|
||||
const dep = ContextDependencyHelpers.create(
|
||||
RequireResolveContextDependency,
|
||||
param.range,
|
||||
param,
|
||||
expr,
|
||||
options,
|
||||
{
|
||||
mode: weak ? "weak" : "sync"
|
||||
}
|
||||
);
|
||||
if (!dep) return;
|
||||
dep.loc = expr.loc;
|
||||
dep.optional = !!parser.scope.inTry;
|
||||
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);
|
||||
});
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,49 +13,96 @@ class SystemPlugin {
|
|||
}
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("SystemPlugin", (compilation, {
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
const handler = (parser, parserOptions) => {
|
||||
if(typeof parserOptions.system !== "undefined" && !parserOptions.system)
|
||||
return;
|
||||
compiler.hooks.compilation.tap(
|
||||
"SystemPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (
|
||||
typeof parserOptions.system !== "undefined" &&
|
||||
!parserOptions.system
|
||||
)
|
||||
return;
|
||||
|
||||
const shouldWarn = typeof parserOptions.system === "undefined";
|
||||
const shouldWarn = typeof parserOptions.system === "undefined";
|
||||
|
||||
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.")
|
||||
);
|
||||
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.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.hooks.expression.for("System").tap("SystemPlugin", () => {
|
||||
const systemPolyfillRequire = ParserHelpers.requireFileAsExpression(
|
||||
parser.state.module.context,
|
||||
require.resolve("../../buildin/system.js")
|
||||
);
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
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.hooks.expression.for("System").tap("SystemPlugin", () => {
|
||||
const systemPolyfillRequire = ParserHelpers.requireFileAsExpression(
|
||||
parser.state.module.context, require.resolve("../../buildin/system.js"));
|
||||
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);
|
||||
});
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("SystemPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/dynamic")
|
||||
.tap("SystemPlugin", handler);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +111,8 @@ class SystemImportDeprecationWarning extends WebpackError {
|
|||
super();
|
||||
|
||||
this.name = "SystemImportDeprecationWarning";
|
||||
this.message = "System.import() is deprecated and will be removed soon. Use import() instead.\n" +
|
||||
this.message =
|
||||
"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.origin = this.module = module;
|
||||
|
|
|
@ -16,7 +16,11 @@ class UnsupportedDependency extends NullDependency {
|
|||
|
||||
UnsupportedDependency.Template = class UnsupportedDependencyTemplate {
|
||||
apply(dep, source, runtime) {
|
||||
source.replace(dep.range[0], dep.range[1], webpackMissingModule(dep.request));
|
||||
source.replace(
|
||||
dep.range[0],
|
||||
dep.range[1],
|
||||
webpackMissingModule(dep.request)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ class WebAssemblyImportDependency extends ModuleDependency {
|
|||
}
|
||||
|
||||
getReference() {
|
||||
if(!this.module) return null;
|
||||
if (!this.module) return null;
|
||||
return {
|
||||
module: this.module,
|
||||
importedNames: [this.name]
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
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) => {
|
||||
exports.promise = request => {
|
||||
const errorCode = toErrorCode(`Cannot find module "${request}"`);
|
||||
return `Promise.reject(function webpackMissingModule() { ${errorCode} return e; }())`;
|
||||
return `Promise.reject(function webpackMissingModule() { ${
|
||||
errorCode
|
||||
} return e; }())`;
|
||||
};
|
||||
|
||||
exports.moduleCode = (request) => {
|
||||
exports.moduleCode = request => {
|
||||
const errorCode = toErrorCode(`Cannot find module "${request}"`);
|
||||
return `${errorCode} throw e;`;
|
||||
};
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
*/
|
||||
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,22 @@ module.exports = 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]]
|
||||
};
|
||||
}
|
||||
// (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 +40,8 @@ module.exports = 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: [],
|
||||
|
|
|
@ -8,15 +8,19 @@
|
|||
const ConcatSource = require("webpack-sources").ConcatSource;
|
||||
|
||||
class NodeChunkTemplatePlugin {
|
||||
|
||||
apply(chunkTemplate) {
|
||||
chunkTemplate.hooks.render.tap("NodeChunkTemplatePlugin", (modules, chunk) => {
|
||||
const source = new ConcatSource();
|
||||
source.add(`exports.ids = ${JSON.stringify(chunk.ids)};\nexports.modules = `);
|
||||
source.add(modules);
|
||||
source.add(";");
|
||||
return source;
|
||||
});
|
||||
chunkTemplate.hooks.render.tap(
|
||||
"NodeChunkTemplatePlugin",
|
||||
(modules, chunk) => {
|
||||
const source = new ConcatSource();
|
||||
source.add(
|
||||
`exports.ids = ${JSON.stringify(chunk.ids)};\nexports.modules = `
|
||||
);
|
||||
source.add(modules);
|
||||
source.add(";");
|
||||
return source;
|
||||
}
|
||||
);
|
||||
chunkTemplate.hooks.hash.tap("NodeChunkTemplatePlugin", hash => {
|
||||
hash.update("node");
|
||||
hash.update("3");
|
||||
|
|
|
@ -11,13 +11,17 @@ const CachedInputFileSystem = require("enhanced-resolve/lib/CachedInputFileSyste
|
|||
|
||||
class NodeEnvironmentPlugin {
|
||||
apply(compiler) {
|
||||
compiler.inputFileSystem = new CachedInputFileSystem(new NodeJsInputFileSystem(), 60000);
|
||||
compiler.inputFileSystem = new CachedInputFileSystem(
|
||||
new NodeJsInputFileSystem(),
|
||||
60000
|
||||
);
|
||||
const inputFileSystem = compiler.inputFileSystem;
|
||||
compiler.outputFileSystem = new NodeOutputFileSystem();
|
||||
compiler.watchFileSystem = new NodeWatchFileSystem(compiler.inputFileSystem);
|
||||
compiler.hooks.beforeRun.tap("NodeEnvironmentPlugin", (compiler) => {
|
||||
if(compiler.inputFileSystem === inputFileSystem)
|
||||
inputFileSystem.purge();
|
||||
compiler.watchFileSystem = new NodeWatchFileSystem(
|
||||
compiler.inputFileSystem
|
||||
);
|
||||
compiler.hooks.beforeRun.tap("NodeEnvironmentPlugin", compiler => {
|
||||
if (compiler.inputFileSystem === inputFileSystem) inputFileSystem.purge();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,21 +7,30 @@
|
|||
const ConcatSource = require("webpack-sources").ConcatSource;
|
||||
|
||||
class NodeHotUpdateChunkTemplatePlugin {
|
||||
|
||||
apply(hotUpdateChunkTemplate) {
|
||||
hotUpdateChunkTemplate.hooks.render.tap("NodeHotUpdateChunkTemplatePlugin", (modulesSource, modules, removedModules, hash, id) => {
|
||||
const source = new ConcatSource();
|
||||
source.add("exports.id = " + JSON.stringify(id) + ";\nexports.modules = ");
|
||||
source.add(modulesSource);
|
||||
source.add(";");
|
||||
return source;
|
||||
});
|
||||
hotUpdateChunkTemplate.hooks.hash.tap("NodeHotUpdateChunkTemplatePlugin", hash => {
|
||||
hash.update("NodeHotUpdateChunkTemplatePlugin");
|
||||
hash.update("3");
|
||||
hash.update(hotUpdateChunkTemplate.outputOptions.hotUpdateFunction + "");
|
||||
hash.update(hotUpdateChunkTemplate.outputOptions.library + "");
|
||||
});
|
||||
hotUpdateChunkTemplate.hooks.render.tap(
|
||||
"NodeHotUpdateChunkTemplatePlugin",
|
||||
(modulesSource, modules, removedModules, hash, id) => {
|
||||
const source = new ConcatSource();
|
||||
source.add(
|
||||
"exports.id = " + JSON.stringify(id) + ";\nexports.modules = "
|
||||
);
|
||||
source.add(modulesSource);
|
||||
source.add(";");
|
||||
return source;
|
||||
}
|
||||
);
|
||||
hotUpdateChunkTemplate.hooks.hash.tap(
|
||||
"NodeHotUpdateChunkTemplatePlugin",
|
||||
hash => {
|
||||
hash.update("NodeHotUpdateChunkTemplatePlugin");
|
||||
hash.update("3");
|
||||
hash.update(
|
||||
hotUpdateChunkTemplate.outputOptions.hotUpdateFunction + ""
|
||||
);
|
||||
hash.update(hotUpdateChunkTemplate.outputOptions.library + "");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = NodeHotUpdateChunkTemplatePlugin;
|
||||
|
|
|
@ -4,21 +4,24 @@
|
|||
*/
|
||||
/*global installedChunks $hotChunkFilename$ hotAddUpdateChunk $hotMainFilename$ */
|
||||
module.exports = function() {
|
||||
function hotDownloadUpdateChunk(chunkId) { // eslint-disable-line no-unused-vars
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadUpdateChunk(chunkId) {
|
||||
var chunk = require("./" + $hotChunkFilename$);
|
||||
hotAddUpdateChunk(chunk.id, chunk.modules);
|
||||
}
|
||||
|
||||
function hotDownloadManifest() { // eslint-disable-line no-unused-vars
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadManifest() {
|
||||
try {
|
||||
var update = require("./" + $hotMainFilename$);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.resolve(update);
|
||||
}
|
||||
|
||||
function hotDisposeChunk(chunkId) { //eslint-disable-line no-unused-vars
|
||||
//eslint-disable-next-line no-unused-vars
|
||||
function hotDisposeChunk(chunkId) {
|
||||
delete installedChunks[chunkId];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,29 +4,32 @@
|
|||
*/
|
||||
/*global installedChunks $hotChunkFilename$ $require$ hotAddUpdateChunk $hotMainFilename$ */
|
||||
module.exports = function() {
|
||||
function hotDownloadUpdateChunk(chunkId) { // eslint-disable-line no-unused-vars
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadUpdateChunk(chunkId) {
|
||||
var filename = require("path").join(__dirname, $hotChunkFilename$);
|
||||
require("fs").readFile(filename, "utf-8", function(err, content) {
|
||||
if(err) {
|
||||
if($require$.onError)
|
||||
return $require$.oe(err);
|
||||
else
|
||||
throw err;
|
||||
if (err) {
|
||||
if ($require$.onError) return $require$.oe(err);
|
||||
else throw err;
|
||||
}
|
||||
var chunk = {};
|
||||
require("vm").runInThisContext("(function(exports) {" + content + "\n})", filename)(chunk);
|
||||
require("vm").runInThisContext(
|
||||
"(function(exports) {" + content + "\n})",
|
||||
filename
|
||||
)(chunk);
|
||||
hotAddUpdateChunk(chunk.id, chunk.modules);
|
||||
});
|
||||
}
|
||||
|
||||
function hotDownloadManifest() { // eslint-disable-line no-unused-vars
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadManifest() {
|
||||
var filename = require("path").join(__dirname, $hotMainFilename$);
|
||||
return new Promise(function(resolve, reject) {
|
||||
require("fs").readFile(filename, "utf-8", function(err, content) {
|
||||
if(err) return resolve();
|
||||
if (err) return resolve();
|
||||
try {
|
||||
var update = JSON.parse(content);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
resolve(update);
|
||||
|
@ -34,7 +37,8 @@ module.exports = function() {
|
|||
});
|
||||
}
|
||||
|
||||
function hotDisposeChunk(chunkId) { //eslint-disable-line no-unused-vars
|
||||
//eslint-disable-next-line no-unused-vars
|
||||
function hotDisposeChunk(chunkId) {
|
||||
delete installedChunks[chunkId];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,183 +13,256 @@ module.exports = class NodeMainTemplatePlugin {
|
|||
|
||||
apply(mainTemplate) {
|
||||
const needChunkOnDemandLoadingCode = chunk => {
|
||||
for(const chunkGroup of chunk.groupsIterable) {
|
||||
if(chunkGroup.getNumberOfChildren() > 0) return true;
|
||||
for (const chunkGroup of chunk.groupsIterable) {
|
||||
if (chunkGroup.getNumberOfChildren() > 0) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const asyncChunkLoading = this.asyncChunkLoading;
|
||||
mainTemplate.hooks.localVars.tap("NodeMainTemplatePlugin", (source, chunk) => {
|
||||
if(needChunkOnDemandLoadingCode(chunk)) {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// object to store loaded chunks",
|
||||
"// \"0\" means \"already loaded\"",
|
||||
"var installedChunks = {",
|
||||
Template.indent(chunk.ids.map((id) => `${id}: 0`).join(",\n")),
|
||||
"};"
|
||||
]);
|
||||
mainTemplate.hooks.localVars.tap(
|
||||
"NodeMainTemplatePlugin",
|
||||
(source, chunk) => {
|
||||
if (needChunkOnDemandLoadingCode(chunk)) {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// object to store loaded chunks",
|
||||
'// "0" means "already loaded"',
|
||||
"var installedChunks = {",
|
||||
Template.indent(chunk.ids.map(id => `${id}: 0`).join(",\n")),
|
||||
"};"
|
||||
]);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
return source;
|
||||
});
|
||||
mainTemplate.hooks.requireExtensions.tap("NodeMainTemplatePlugin", (source, chunk) => {
|
||||
if(needChunkOnDemandLoadingCode(chunk)) {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// uncatched error handler for webpack runtime",
|
||||
`${mainTemplate.requireFn}.oe = function(err) {`,
|
||||
Template.indent([
|
||||
"process.nextTick(function() {",
|
||||
Template.indent("throw err; // catch this error by using import().catch()"),
|
||||
"});"
|
||||
]),
|
||||
"};"
|
||||
]);
|
||||
}
|
||||
return source;
|
||||
});
|
||||
mainTemplate.hooks.requireEnsure.tap("NodeMainTemplatePlugin", (source, chunk, hash) => {
|
||||
const chunkFilename = mainTemplate.outputOptions.chunkFilename;
|
||||
const chunkMaps = chunk.getChunkMaps();
|
||||
const insertMoreModules = [
|
||||
"var moreModules = chunk.modules, chunkIds = chunk.ids;",
|
||||
"for(var moduleId in moreModules) {",
|
||||
Template.indent(mainTemplate.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")),
|
||||
"}"
|
||||
];
|
||||
if(asyncChunkLoading) {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// ReadFile + VM.run chunk loading for javascript",
|
||||
"",
|
||||
"var installedChunkData = installedChunks[chunkId];",
|
||||
"if(installedChunkData !== 0) { // 0 means \"already installed\".",
|
||||
Template.indent([
|
||||
"// array of [resolve, reject, promise] means \"currently loading\"",
|
||||
"if(installedChunkData) {",
|
||||
);
|
||||
mainTemplate.hooks.requireExtensions.tap(
|
||||
"NodeMainTemplatePlugin",
|
||||
(source, chunk) => {
|
||||
if (needChunkOnDemandLoadingCode(chunk)) {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// uncatched error handler for webpack runtime",
|
||||
`${mainTemplate.requireFn}.oe = function(err) {`,
|
||||
Template.indent([
|
||||
"promises.push(installedChunkData[2]);"
|
||||
"process.nextTick(function() {",
|
||||
Template.indent(
|
||||
"throw err; // catch this error by using import().catch()"
|
||||
),
|
||||
"});"
|
||||
]),
|
||||
"} else {",
|
||||
"};"
|
||||
]);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
);
|
||||
mainTemplate.hooks.requireEnsure.tap(
|
||||
"NodeMainTemplatePlugin",
|
||||
(source, chunk, hash) => {
|
||||
const chunkFilename = mainTemplate.outputOptions.chunkFilename;
|
||||
const chunkMaps = chunk.getChunkMaps();
|
||||
const insertMoreModules = [
|
||||
"var moreModules = chunk.modules, chunkIds = chunk.ids;",
|
||||
"for(var moduleId in moreModules) {",
|
||||
Template.indent(
|
||||
mainTemplate.renderAddModule(
|
||||
hash,
|
||||
chunk,
|
||||
"moduleId",
|
||||
"moreModules[moduleId]"
|
||||
)
|
||||
),
|
||||
"}"
|
||||
];
|
||||
if (asyncChunkLoading) {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// ReadFile + VM.run chunk loading for javascript",
|
||||
"",
|
||||
"var installedChunkData = installedChunks[chunkId];",
|
||||
'if(installedChunkData !== 0) { // 0 means "already installed".',
|
||||
Template.indent([
|
||||
"// load the chunk and return promise to it",
|
||||
"var promise = new Promise(function(resolve, reject) {",
|
||||
'// array of [resolve, reject, promise] means "currently loading"',
|
||||
"if(installedChunkData) {",
|
||||
Template.indent(["promises.push(installedChunkData[2]);"]),
|
||||
"} else {",
|
||||
Template.indent([
|
||||
"installedChunkData = installedChunks[chunkId] = [resolve, reject];",
|
||||
"var filename = __dirname + " + mainTemplate.getAssetPath(JSON.stringify(`/${chunkFilename}`), {
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: (length) => `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
|
||||
chunk: {
|
||||
id: "\" + chunkId + \"",
|
||||
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
|
||||
hashWithLength: (length) => {
|
||||
const shortChunkHashMap = {};
|
||||
for(const chunkId of Object.keys(chunkMaps.hash)) {
|
||||
if(typeof chunkMaps.hash[chunkId] === "string")
|
||||
shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr(0, length);
|
||||
}
|
||||
return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`;
|
||||
},
|
||||
name: `" + (${JSON.stringify(chunkMaps.name)}[chunkId]||chunkId) + "`
|
||||
}
|
||||
}) + ";",
|
||||
"require('fs').readFile(filename, 'utf-8', function(err, content) {",
|
||||
"// load the chunk and return promise to it",
|
||||
"var promise = new Promise(function(resolve, reject) {",
|
||||
Template.indent([
|
||||
"if(err) return reject(err);",
|
||||
"var chunk = {};",
|
||||
"require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" +
|
||||
"(chunk, require, require('path').dirname(filename), filename);"
|
||||
].concat(insertMoreModules).concat([
|
||||
"var callbacks = [];",
|
||||
"for(var i = 0; i < chunkIds.length; i++) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkIds[i]])",
|
||||
Template.indent([
|
||||
"callbacks = callbacks.concat(installedChunks[chunkIds[i]][0]);"
|
||||
]),
|
||||
"installedChunks[chunkIds[i]] = 0;"
|
||||
]),
|
||||
"}",
|
||||
"for(i = 0; i < callbacks.length; i++)",
|
||||
Template.indent("callbacks[i]();")
|
||||
])),
|
||||
"});"
|
||||
"installedChunkData = installedChunks[chunkId] = [resolve, reject];",
|
||||
"var filename = __dirname + " +
|
||||
mainTemplate.getAssetPath(
|
||||
JSON.stringify(`/${chunkFilename}`),
|
||||
{
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(
|
||||
hash
|
||||
)} + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${mainTemplate.renderCurrentHashCode(
|
||||
hash,
|
||||
length
|
||||
)} + "`,
|
||||
chunk: {
|
||||
id: '" + chunkId + "',
|
||||
hash: `" + ${JSON.stringify(
|
||||
chunkMaps.hash
|
||||
)}[chunkId] + "`,
|
||||
hashWithLength: length => {
|
||||
const shortChunkHashMap = {};
|
||||
for (const chunkId of Object.keys(chunkMaps.hash)) {
|
||||
if (typeof chunkMaps.hash[chunkId] === "string")
|
||||
shortChunkHashMap[chunkId] = chunkMaps.hash[
|
||||
chunkId
|
||||
].substr(0, length);
|
||||
}
|
||||
return `" + ${JSON.stringify(
|
||||
shortChunkHashMap
|
||||
)}[chunkId] + "`;
|
||||
},
|
||||
name: `" + (${JSON.stringify(
|
||||
chunkMaps.name
|
||||
)}[chunkId]||chunkId) + "`
|
||||
}
|
||||
}
|
||||
) +
|
||||
";",
|
||||
"require('fs').readFile(filename, 'utf-8', function(err, content) {",
|
||||
Template.indent(
|
||||
[
|
||||
"if(err) return reject(err);",
|
||||
"var chunk = {};",
|
||||
"require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" +
|
||||
"(chunk, require, require('path').dirname(filename), filename);"
|
||||
]
|
||||
.concat(insertMoreModules)
|
||||
.concat([
|
||||
"var callbacks = [];",
|
||||
"for(var i = 0; i < chunkIds.length; i++) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkIds[i]])",
|
||||
Template.indent([
|
||||
"callbacks = callbacks.concat(installedChunks[chunkIds[i]][0]);"
|
||||
]),
|
||||
"installedChunks[chunkIds[i]] = 0;"
|
||||
]),
|
||||
"}",
|
||||
"for(i = 0; i < callbacks.length; i++)",
|
||||
Template.indent("callbacks[i]();")
|
||||
])
|
||||
),
|
||||
"});"
|
||||
]),
|
||||
"});",
|
||||
"promises.push(installedChunkData[2] = promise);"
|
||||
]),
|
||||
"});",
|
||||
"promises.push(installedChunkData[2] = promise);"
|
||||
"}"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}"
|
||||
]);
|
||||
} else {
|
||||
const request = mainTemplate.getAssetPath(JSON.stringify(`./${chunkFilename}`), {
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: (length) => `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
|
||||
chunk: {
|
||||
id: "\" + chunkId + \"",
|
||||
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
|
||||
hashWithLength: (length) => {
|
||||
const shortChunkHashMap = {};
|
||||
for(const chunkId of Object.keys(chunkMaps.hash)) {
|
||||
if(typeof chunkMaps.hash[chunkId] === "string")
|
||||
shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr(0, length);
|
||||
]);
|
||||
} else {
|
||||
const request = mainTemplate.getAssetPath(
|
||||
JSON.stringify(`./${chunkFilename}`),
|
||||
{
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
|
||||
chunk: {
|
||||
id: '" + chunkId + "',
|
||||
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
|
||||
hashWithLength: length => {
|
||||
const shortChunkHashMap = {};
|
||||
for (const chunkId of Object.keys(chunkMaps.hash)) {
|
||||
if (typeof chunkMaps.hash[chunkId] === "string")
|
||||
shortChunkHashMap[chunkId] = chunkMaps.hash[
|
||||
chunkId
|
||||
].substr(0, length);
|
||||
}
|
||||
return `" + ${JSON.stringify(
|
||||
shortChunkHashMap
|
||||
)}[chunkId] + "`;
|
||||
},
|
||||
name: `" + (${JSON.stringify(
|
||||
chunkMaps.name
|
||||
)}[chunkId]||chunkId) + "`
|
||||
}
|
||||
return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`;
|
||||
},
|
||||
name: `" + (${JSON.stringify(chunkMaps.name)}[chunkId]||chunkId) + "`
|
||||
}
|
||||
});
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// require() chunk loading for javascript",
|
||||
"",
|
||||
"// \"0\" is the signal for \"already loaded\"",
|
||||
"if(installedChunks[chunkId] !== 0) {",
|
||||
Template.indent([
|
||||
`var chunk = require(${request});`
|
||||
].concat(insertMoreModules).concat([
|
||||
"for(var i = 0; i < chunkIds.length; i++)",
|
||||
Template.indent("installedChunks[chunkIds[i]] = 0;")
|
||||
])),
|
||||
"}",
|
||||
]);
|
||||
}
|
||||
});
|
||||
mainTemplate.hooks.hotBootstrap.tap("NodeMainTemplatePlugin", (source, chunk, hash) => {
|
||||
const hotUpdateChunkFilename = mainTemplate.outputOptions.hotUpdateChunkFilename;
|
||||
const hotUpdateMainFilename = mainTemplate.outputOptions.hotUpdateMainFilename;
|
||||
const chunkMaps = chunk.getChunkMaps();
|
||||
const currentHotUpdateChunkFilename = mainTemplate.getAssetPath(JSON.stringify(hotUpdateChunkFilename), {
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: (length) => `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
|
||||
chunk: {
|
||||
id: "\" + chunkId + \"",
|
||||
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
|
||||
hashWithLength: (length) => {
|
||||
const shortChunkHashMap = {};
|
||||
for(const chunkId of Object.keys(chunkMaps.hash)) {
|
||||
if(typeof chunkMaps.hash[chunkId] === "string")
|
||||
shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr(0, length);
|
||||
}
|
||||
return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`;
|
||||
},
|
||||
name: `" + (${JSON.stringify(chunkMaps.name)}[chunkId]||chunkId) + "`
|
||||
);
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// require() chunk loading for javascript",
|
||||
"",
|
||||
'// "0" is the signal for "already loaded"',
|
||||
"if(installedChunks[chunkId] !== 0) {",
|
||||
Template.indent(
|
||||
[`var chunk = require(${request});`]
|
||||
.concat(insertMoreModules)
|
||||
.concat([
|
||||
"for(var i = 0; i < chunkIds.length; i++)",
|
||||
Template.indent("installedChunks[chunkIds[i]] = 0;")
|
||||
])
|
||||
),
|
||||
"}"
|
||||
]);
|
||||
}
|
||||
});
|
||||
const currentHotUpdateMainFilename = mainTemplate.getAssetPath(JSON.stringify(hotUpdateMainFilename), {
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: (length) => `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`
|
||||
});
|
||||
return Template.getFunctionContent(asyncChunkLoading ? require("./NodeMainTemplateAsync.runtime.js") : require("./NodeMainTemplate.runtime.js"))
|
||||
.replace(/\$require\$/g, mainTemplate.requireFn)
|
||||
.replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
|
||||
.replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename);
|
||||
});
|
||||
}
|
||||
);
|
||||
mainTemplate.hooks.hotBootstrap.tap(
|
||||
"NodeMainTemplatePlugin",
|
||||
(source, chunk, hash) => {
|
||||
const hotUpdateChunkFilename =
|
||||
mainTemplate.outputOptions.hotUpdateChunkFilename;
|
||||
const hotUpdateMainFilename =
|
||||
mainTemplate.outputOptions.hotUpdateMainFilename;
|
||||
const chunkMaps = chunk.getChunkMaps();
|
||||
const currentHotUpdateChunkFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateChunkFilename),
|
||||
{
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
|
||||
chunk: {
|
||||
id: '" + chunkId + "',
|
||||
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
|
||||
hashWithLength: length => {
|
||||
const shortChunkHashMap = {};
|
||||
for (const chunkId of Object.keys(chunkMaps.hash)) {
|
||||
if (typeof chunkMaps.hash[chunkId] === "string")
|
||||
shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr(
|
||||
0,
|
||||
length
|
||||
);
|
||||
}
|
||||
return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`;
|
||||
},
|
||||
name: `" + (${JSON.stringify(
|
||||
chunkMaps.name
|
||||
)}[chunkId]||chunkId) + "`
|
||||
}
|
||||
}
|
||||
);
|
||||
const currentHotUpdateMainFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateMainFilename),
|
||||
{
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`
|
||||
}
|
||||
);
|
||||
return Template.getFunctionContent(
|
||||
asyncChunkLoading
|
||||
? require("./NodeMainTemplateAsync.runtime.js")
|
||||
: require("./NodeMainTemplate.runtime.js")
|
||||
)
|
||||
.replace(/\$require\$/g, mainTemplate.requireFn)
|
||||
.replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
|
||||
.replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename);
|
||||
}
|
||||
);
|
||||
mainTemplate.hooks.hash.tap("NodeMainTemplatePlugin", hash => {
|
||||
hash.update("node");
|
||||
hash.update("3");
|
||||
|
|
|
@ -13,16 +13,20 @@ module.exports = class NodeSourcePlugin {
|
|||
}
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
if(options === false) // allow single kill switch to turn off this plugin
|
||||
if (options === false)
|
||||
// allow single kill switch to turn off this plugin
|
||||
return;
|
||||
|
||||
const getPathToModule = (module, type) => {
|
||||
if(type === true || (type === undefined && nodeLibsBrowser[module])) {
|
||||
if(!nodeLibsBrowser[module]) throw new Error(`No browser version for node.js core module ${module} available`);
|
||||
if (type === true || (type === undefined && nodeLibsBrowser[module])) {
|
||||
if (!nodeLibsBrowser[module])
|
||||
throw new Error(
|
||||
`No browser version for node.js core module ${module} available`
|
||||
);
|
||||
return nodeLibsBrowser[module];
|
||||
} else if(type === "mock") {
|
||||
} else if (type === "mock") {
|
||||
return require.resolve(`node-libs-browser/mock/${module}`);
|
||||
} else if(type === "empty") {
|
||||
} else if (type === "empty") {
|
||||
return require.resolve("node-libs-browser/mock/empty");
|
||||
} else return module;
|
||||
};
|
||||
|
@ -30,61 +34,105 @@ module.exports = class NodeSourcePlugin {
|
|||
const addExpression = (parser, name, module, type, suffix) => {
|
||||
suffix = suffix || "";
|
||||
parser.hooks.expression.for(name).tap("NodeSourcePlugin", () => {
|
||||
if(parser.state.module && parser.state.module.resource === getPathToModule(module, type)) return;
|
||||
const mockModule = ParserHelpers.requireFileAsExpression(parser.state.module.context, getPathToModule(module, type));
|
||||
return ParserHelpers.addParsedVariableToModule(parser, name, mockModule + suffix);
|
||||
if (
|
||||
parser.state.module &&
|
||||
parser.state.module.resource === getPathToModule(module, type)
|
||||
)
|
||||
return;
|
||||
const mockModule = ParserHelpers.requireFileAsExpression(
|
||||
parser.state.module.context,
|
||||
getPathToModule(module, type)
|
||||
);
|
||||
return ParserHelpers.addParsedVariableToModule(
|
||||
parser,
|
||||
name,
|
||||
mockModule + suffix
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
compiler.hooks.compilation.tap("NodeSourcePlugin", (compilation, {
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
const handler = (parser, parserOptions) => {
|
||||
if(parserOptions.node === false)
|
||||
return;
|
||||
compiler.hooks.compilation.tap(
|
||||
"NodeSourcePlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
const handler = (parser, parserOptions) => {
|
||||
if (parserOptions.node === false) return;
|
||||
|
||||
let localOptions = options;
|
||||
if(parserOptions.node)
|
||||
localOptions = Object.assign({}, localOptions, parserOptions.node);
|
||||
let localOptions = options;
|
||||
if (parserOptions.node)
|
||||
localOptions = Object.assign({}, localOptions, parserOptions.node);
|
||||
|
||||
if(localOptions.global) {
|
||||
parser.hooks.expression.for("global").tap("NodeSourcePlugin", () => {
|
||||
const retrieveGlobalModule = ParserHelpers.requireFileAsExpression(parser.state.module.context, require.resolve("../../buildin/global.js"));
|
||||
return ParserHelpers.addParsedVariableToModule(parser, "global", retrieveGlobalModule);
|
||||
});
|
||||
}
|
||||
if(localOptions.process) {
|
||||
const processType = localOptions.process;
|
||||
addExpression(parser, "process", "process", processType);
|
||||
}
|
||||
if(localOptions.console) {
|
||||
const consoleType = localOptions.console;
|
||||
addExpression(parser, "console", "console", consoleType);
|
||||
}
|
||||
const bufferType = localOptions.Buffer;
|
||||
if(bufferType) {
|
||||
addExpression(parser, "Buffer", "buffer", bufferType, ".Buffer");
|
||||
}
|
||||
if(localOptions.setImmediate) {
|
||||
const setImmediateType = localOptions.setImmediate;
|
||||
addExpression(parser, "setImmediate", "timers", setImmediateType, ".setImmediate");
|
||||
addExpression(parser, "clearImmediate", "timers", setImmediateType, ".clearImmediate");
|
||||
}
|
||||
};
|
||||
normalModuleFactory.hooks.parser.for("javascript/auto").tap("NodeSourcePlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("NodeSourcePlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/esm").tap("NodeSourcePlugin", handler);
|
||||
});
|
||||
compiler.hooks.afterResolvers.tap("NodeSourcePlugin", (compiler) => {
|
||||
for(const lib of Object.keys(nodeLibsBrowser)) {
|
||||
if(options[lib] !== false) {
|
||||
compiler.resolverFactory.hooks.resolver.for("normal").tap("NodeSourcePlugin", resolver => {
|
||||
new AliasPlugin("described-resolve", {
|
||||
name: lib,
|
||||
onlyModule: true,
|
||||
alias: getPathToModule(lib, options[lib])
|
||||
}, "resolve").apply(resolver);
|
||||
});
|
||||
if (localOptions.global) {
|
||||
parser.hooks.expression
|
||||
.for("global")
|
||||
.tap("NodeSourcePlugin", () => {
|
||||
const retrieveGlobalModule = ParserHelpers.requireFileAsExpression(
|
||||
parser.state.module.context,
|
||||
require.resolve("../../buildin/global.js")
|
||||
);
|
||||
return ParserHelpers.addParsedVariableToModule(
|
||||
parser,
|
||||
"global",
|
||||
retrieveGlobalModule
|
||||
);
|
||||
});
|
||||
}
|
||||
if (localOptions.process) {
|
||||
const processType = localOptions.process;
|
||||
addExpression(parser, "process", "process", processType);
|
||||
}
|
||||
if (localOptions.console) {
|
||||
const consoleType = localOptions.console;
|
||||
addExpression(parser, "console", "console", consoleType);
|
||||
}
|
||||
const bufferType = localOptions.Buffer;
|
||||
if (bufferType) {
|
||||
addExpression(parser, "Buffer", "buffer", bufferType, ".Buffer");
|
||||
}
|
||||
if (localOptions.setImmediate) {
|
||||
const setImmediateType = localOptions.setImmediate;
|
||||
addExpression(
|
||||
parser,
|
||||
"setImmediate",
|
||||
"timers",
|
||||
setImmediateType,
|
||||
".setImmediate"
|
||||
);
|
||||
addExpression(
|
||||
parser,
|
||||
"clearImmediate",
|
||||
"timers",
|
||||
setImmediateType,
|
||||
".clearImmediate"
|
||||
);
|
||||
}
|
||||
};
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("NodeSourcePlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/dynamic")
|
||||
.tap("NodeSourcePlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/esm")
|
||||
.tap("NodeSourcePlugin", handler);
|
||||
}
|
||||
);
|
||||
compiler.hooks.afterResolvers.tap("NodeSourcePlugin", compiler => {
|
||||
for (const lib of Object.keys(nodeLibsBrowser)) {
|
||||
if (options[lib] !== false) {
|
||||
compiler.resolverFactory.hooks.resolver
|
||||
.for("normal")
|
||||
.tap("NodeSourcePlugin", resolver => {
|
||||
new AliasPlugin(
|
||||
"described-resolve",
|
||||
{
|
||||
name: lib,
|
||||
onlyModule: true,
|
||||
alias: getPathToModule(lib, options[lib])
|
||||
},
|
||||
"resolve"
|
||||
).apply(resolver);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
const ExternalsPlugin = require("../ExternalsPlugin");
|
||||
|
||||
const builtins = require("module").builtinModules || Object.keys(process.binding("natives"));
|
||||
const builtins =
|
||||
require("module").builtinModules || Object.keys(process.binding("natives"));
|
||||
|
||||
class NodeTargetPlugin {
|
||||
apply(compiler) {
|
||||
|
|
|
@ -16,10 +16,14 @@ class NodeTemplatePlugin {
|
|||
}
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap("NodeTemplatePlugin", (compilation) => {
|
||||
new NodeMainTemplatePlugin(this.asyncChunkLoading).apply(compilation.mainTemplate);
|
||||
compiler.hooks.thisCompilation.tap("NodeTemplatePlugin", compilation => {
|
||||
new NodeMainTemplatePlugin(this.asyncChunkLoading).apply(
|
||||
compilation.mainTemplate
|
||||
);
|
||||
new NodeChunkTemplatePlugin().apply(compilation.chunkTemplate);
|
||||
new NodeHotUpdateChunkTemplatePlugin().apply(compilation.hotUpdateChunkTemplate);
|
||||
new NodeHotUpdateChunkTemplatePlugin().apply(
|
||||
compilation.hotUpdateChunkTemplate
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,66 +17,63 @@ class NodeWatchFileSystem {
|
|||
}
|
||||
|
||||
watch(files, dirs, missing, startTime, options, callback, callbackUndelayed) {
|
||||
if(!Array.isArray(files))
|
||||
throw new Error("Invalid arguments: 'files'");
|
||||
if(!Array.isArray(dirs))
|
||||
throw new Error("Invalid arguments: 'dirs'");
|
||||
if(!Array.isArray(missing))
|
||||
if (!Array.isArray(files)) throw new Error("Invalid arguments: 'files'");
|
||||
if (!Array.isArray(dirs)) throw new Error("Invalid arguments: 'dirs'");
|
||||
if (!Array.isArray(missing))
|
||||
throw new Error("Invalid arguments: 'missing'");
|
||||
if(typeof callback !== "function")
|
||||
if (typeof callback !== "function")
|
||||
throw new Error("Invalid arguments: 'callback'");
|
||||
if(typeof startTime !== "number" && startTime)
|
||||
if (typeof startTime !== "number" && startTime)
|
||||
throw new Error("Invalid arguments: 'startTime'");
|
||||
if(typeof options !== "object")
|
||||
if (typeof options !== "object")
|
||||
throw new Error("Invalid arguments: 'options'");
|
||||
if(typeof callbackUndelayed !== "function" && callbackUndelayed)
|
||||
if (typeof callbackUndelayed !== "function" && callbackUndelayed)
|
||||
throw new Error("Invalid arguments: 'callbackUndelayed'");
|
||||
const oldWatcher = this.watcher;
|
||||
this.watcher = new Watchpack(options);
|
||||
|
||||
if(callbackUndelayed)
|
||||
this.watcher.once("change", callbackUndelayed);
|
||||
if (callbackUndelayed) this.watcher.once("change", callbackUndelayed);
|
||||
|
||||
this.watcher.once("aggregated", (changes, removals) => {
|
||||
changes = changes.concat(removals);
|
||||
if(this.inputFileSystem && this.inputFileSystem.purge) {
|
||||
if (this.inputFileSystem && this.inputFileSystem.purge) {
|
||||
this.inputFileSystem.purge(changes);
|
||||
}
|
||||
const times = objectToMap(this.watcher.getTimes());
|
||||
callback(null,
|
||||
callback(
|
||||
null,
|
||||
changes.filter(file => files.includes(file)).sort(),
|
||||
changes.filter(file => dirs.includes(file)).sort(),
|
||||
changes.filter(file => missing.includes(file)).sort(), times, times);
|
||||
changes.filter(file => missing.includes(file)).sort(),
|
||||
times,
|
||||
times
|
||||
);
|
||||
});
|
||||
|
||||
this.watcher.watch(files.concat(missing), dirs.concat(missing), startTime);
|
||||
|
||||
if(oldWatcher) {
|
||||
if (oldWatcher) {
|
||||
oldWatcher.close();
|
||||
}
|
||||
return {
|
||||
close: () => {
|
||||
if(this.watcher) {
|
||||
if (this.watcher) {
|
||||
this.watcher.close();
|
||||
this.watcher = null;
|
||||
}
|
||||
},
|
||||
pause: () => {
|
||||
if(this.watcher) {
|
||||
if (this.watcher) {
|
||||
this.watcher.pause();
|
||||
}
|
||||
},
|
||||
getFileTimestamps: () => {
|
||||
if(this.watcher)
|
||||
return objectToMap(this.watcher.getTimes());
|
||||
else
|
||||
return new Map();
|
||||
if (this.watcher) return objectToMap(this.watcher.getTimes());
|
||||
else return new Map();
|
||||
},
|
||||
getContextTimestamps: () => {
|
||||
if(this.watcher)
|
||||
return objectToMap(this.watcher.getTimes());
|
||||
else
|
||||
return new Map();
|
||||
if (this.watcher) return objectToMap(this.watcher.getTimes());
|
||||
else return new Map();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,79 +7,109 @@
|
|||
const Template = require("../Template");
|
||||
|
||||
class ReadFileCompileWasmMainTemplatePlugin {
|
||||
|
||||
apply(mainTemplate) {
|
||||
mainTemplate.hooks.localVars.tap("ReadFileCompileWasmMainTemplatePlugin", (source, chunk) => {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// object to store loaded and loading wasm modules",
|
||||
"var installedWasmModules = {};",
|
||||
]);
|
||||
});
|
||||
mainTemplate.hooks.requireEnsure.tap("ReadFileCompileWasmMainTemplatePlugin", (source, chunk, hash) => {
|
||||
const webassemblyModuleFilename = mainTemplate.outputOptions.webassemblyModuleFilename;
|
||||
const chunkModuleMaps = chunk.getChunkModuleMaps(m => m.type.startsWith("webassembly"));
|
||||
if(Object.keys(chunkModuleMaps.id).length === 0) return source;
|
||||
const wasmModuleSrcPath = mainTemplate.getAssetPath(JSON.stringify(webassemblyModuleFilename), {
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: length => `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
|
||||
module: {
|
||||
id: "\" + wasmModuleId + \"",
|
||||
hash: `" + ${JSON.stringify(chunkModuleMaps.hash)}[wasmModuleId] + "`,
|
||||
hashWithLength(length) {
|
||||
const shortChunkHashMap = Object.create(null);
|
||||
for(const wasmModuleId of Object.keys(chunkModuleMaps.hash)) {
|
||||
if(typeof chunkModuleMaps.hash[wasmModuleId] === "string")
|
||||
shortChunkHashMap[wasmModuleId] = chunkModuleMaps.hash[wasmModuleId].substr(0, length);
|
||||
}
|
||||
return `" + ${JSON.stringify(shortChunkHashMap)}[wasmModuleId] + "`;
|
||||
}
|
||||
}
|
||||
});
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// ReadFile + compile chunk loading for webassembly",
|
||||
"",
|
||||
`var wasmModules = ${JSON.stringify(chunkModuleMaps.id)}[chunkId] || [];`,
|
||||
"",
|
||||
"wasmModules.forEach(function(wasmModuleId) {",
|
||||
Template.indent([
|
||||
"var installedWasmModuleData = installedWasmModules[wasmModuleId];",
|
||||
mainTemplate.hooks.localVars.tap(
|
||||
"ReadFileCompileWasmMainTemplatePlugin",
|
||||
(source, chunk) => {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// a Promise means \"currently loading\" or \"already loaded\".",
|
||||
"promises.push(installedWasmModuleData ||",
|
||||
"// object to store loaded and loading wasm modules",
|
||||
"var installedWasmModules = {};"
|
||||
]);
|
||||
}
|
||||
);
|
||||
mainTemplate.hooks.requireEnsure.tap(
|
||||
"ReadFileCompileWasmMainTemplatePlugin",
|
||||
(source, chunk, hash) => {
|
||||
const webassemblyModuleFilename =
|
||||
mainTemplate.outputOptions.webassemblyModuleFilename;
|
||||
const chunkModuleMaps = chunk.getChunkModuleMaps(m =>
|
||||
m.type.startsWith("webassembly")
|
||||
);
|
||||
if (Object.keys(chunkModuleMaps.id).length === 0) return source;
|
||||
const wasmModuleSrcPath = mainTemplate.getAssetPath(
|
||||
JSON.stringify(webassemblyModuleFilename),
|
||||
{
|
||||
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
|
||||
module: {
|
||||
id: '" + wasmModuleId + "',
|
||||
hash: `" + ${JSON.stringify(
|
||||
chunkModuleMaps.hash
|
||||
)}[wasmModuleId] + "`,
|
||||
hashWithLength(length) {
|
||||
const shortChunkHashMap = Object.create(null);
|
||||
for (const wasmModuleId of Object.keys(chunkModuleMaps.hash)) {
|
||||
if (typeof chunkModuleMaps.hash[wasmModuleId] === "string")
|
||||
shortChunkHashMap[wasmModuleId] = chunkModuleMaps.hash[
|
||||
wasmModuleId
|
||||
].substr(0, length);
|
||||
}
|
||||
return `" + ${JSON.stringify(
|
||||
shortChunkHashMap
|
||||
)}[wasmModuleId] + "`;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// ReadFile + compile chunk loading for webassembly",
|
||||
"",
|
||||
`var wasmModules = ${JSON.stringify(
|
||||
chunkModuleMaps.id
|
||||
)}[chunkId] || [];`,
|
||||
"",
|
||||
"wasmModules.forEach(function(wasmModuleId) {",
|
||||
Template.indent([
|
||||
"(installedWasmModules[wasmModuleId] = new Promise(function(resolve, reject) {",
|
||||
"var installedWasmModuleData = installedWasmModules[wasmModuleId];",
|
||||
"",
|
||||
'// a Promise means "currently loading" or "already loaded".',
|
||||
"promises.push(installedWasmModuleData ||",
|
||||
Template.indent([
|
||||
`require('fs').readFile(require('path').resolve(__dirname, ${wasmModuleSrcPath}), function(err, buffer) {`,
|
||||
"(installedWasmModules[wasmModuleId] = new Promise(function(resolve, reject) {",
|
||||
Template.indent([
|
||||
"if(err) return reject(err);",
|
||||
"resolve(WebAssembly.compile(buffer));"
|
||||
`require('fs').readFile(require('path').resolve(__dirname, ${
|
||||
wasmModuleSrcPath
|
||||
}), function(err, buffer) {`,
|
||||
Template.indent([
|
||||
"if(err) return reject(err);",
|
||||
"resolve(WebAssembly.compile(buffer));"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"});"
|
||||
`}).then(function(module) { ${
|
||||
mainTemplate.requireFn
|
||||
}.w[wasmModuleId] = module; }))`
|
||||
]),
|
||||
`}).then(function(module) { ${mainTemplate.requireFn}.w[wasmModuleId] = module; }))`
|
||||
");"
|
||||
]),
|
||||
");",
|
||||
]),
|
||||
"});",
|
||||
]);
|
||||
});
|
||||
mainTemplate.hooks.requireExtensions.tap("ReadFileCompileWasmMainTemplatePlugin", (source, chunk) => {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// object with all compiled WebAssmbly.Modules",
|
||||
`${mainTemplate.requireFn}.w = {};`
|
||||
]);
|
||||
});
|
||||
mainTemplate.hooks.hash.tap("ReadFileCompileWasmMainTemplatePlugin", hash => {
|
||||
hash.update("ReadFileCompileWasmMainTemplatePlugin");
|
||||
hash.update("1");
|
||||
hash.update(`${mainTemplate.outputOptions.webassemblyModuleFilename}`);
|
||||
});
|
||||
"});"
|
||||
]);
|
||||
}
|
||||
);
|
||||
mainTemplate.hooks.requireExtensions.tap(
|
||||
"ReadFileCompileWasmMainTemplatePlugin",
|
||||
(source, chunk) => {
|
||||
return Template.asString([
|
||||
source,
|
||||
"",
|
||||
"// object with all compiled WebAssmbly.Modules",
|
||||
`${mainTemplate.requireFn}.w = {};`
|
||||
]);
|
||||
}
|
||||
);
|
||||
mainTemplate.hooks.hash.tap(
|
||||
"ReadFileCompileWasmMainTemplatePlugin",
|
||||
hash => {
|
||||
hash.update("ReadFileCompileWasmMainTemplatePlugin");
|
||||
hash.update("1");
|
||||
hash.update(`${mainTemplate.outputOptions.webassemblyModuleFilename}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = ReadFileCompileWasmMainTemplatePlugin;
|
||||
|
|
|
@ -9,10 +9,17 @@ const WasmModuleTemplatePlugin = require("../wasm/WasmModuleTemplatePlugin");
|
|||
|
||||
class ReadFileCompileWasmTemplatePlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap("ReadFileCompileWasmTemplatePlugin", (compilation) => {
|
||||
new ReadFileCompileWasmMainTemplatePlugin().apply(compilation.mainTemplate);
|
||||
new WasmModuleTemplatePlugin().apply(compilation.moduleTemplates.javascript);
|
||||
});
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
"ReadFileCompileWasmTemplatePlugin",
|
||||
compilation => {
|
||||
new ReadFileCompileWasmMainTemplatePlugin().apply(
|
||||
compilation.mainTemplate
|
||||
);
|
||||
new WasmModuleTemplatePlugin().apply(
|
||||
compilation.moduleTemplates.javascript
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,13 @@
|
|||
|
||||
class AggressiveMergingPlugin {
|
||||
constructor(options) {
|
||||
if(options !== undefined && typeof options !== "object" || Array.isArray(options)) {
|
||||
throw new Error("Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/");
|
||||
if (
|
||||
(options !== undefined && typeof options !== "object") ||
|
||||
Array.isArray(options)
|
||||
) {
|
||||
throw new Error(
|
||||
"Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/"
|
||||
);
|
||||
}
|
||||
this.options = options || {};
|
||||
}
|
||||
|
@ -16,60 +21,66 @@ class AggressiveMergingPlugin {
|
|||
const options = this.options;
|
||||
const minSizeReduce = options.minSizeReduce || 1.5;
|
||||
|
||||
compiler.hooks.thisCompilation.tap("AggressiveMergingPlugin", (compilation) => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap("AggressiveMergingPlugin", (chunks) => {
|
||||
let combinations = [];
|
||||
chunks.forEach((a, idx) => {
|
||||
if(a.canBeInitial()) return;
|
||||
for(let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
if(b.canBeInitial()) continue;
|
||||
combinations.push({
|
||||
a,
|
||||
b,
|
||||
improvement: undefined
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
"AggressiveMergingPlugin",
|
||||
compilation => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"AggressiveMergingPlugin",
|
||||
chunks => {
|
||||
let combinations = [];
|
||||
chunks.forEach((a, idx) => {
|
||||
if (a.canBeInitial()) return;
|
||||
for (let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
if (b.canBeInitial()) continue;
|
||||
combinations.push({
|
||||
a,
|
||||
b,
|
||||
improvement: undefined
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (const pair of combinations) {
|
||||
const a = pair.b.size({
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const b = pair.a.size({
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const ab = pair.b.integratedSize(pair.a, {
|
||||
chunkOverhead: 0
|
||||
});
|
||||
let newSize;
|
||||
if (ab === false) {
|
||||
pair.improvement = false;
|
||||
return;
|
||||
} else {
|
||||
newSize = ab;
|
||||
}
|
||||
|
||||
pair.improvement = (a + b) / newSize;
|
||||
}
|
||||
combinations = combinations.filter(pair => {
|
||||
return pair.improvement !== false;
|
||||
});
|
||||
combinations.sort((a, b) => {
|
||||
return b.improvement - a.improvement;
|
||||
});
|
||||
|
||||
const pair = combinations[0];
|
||||
|
||||
if (!pair) return;
|
||||
if (pair.improvement < minSizeReduce) return;
|
||||
|
||||
if (pair.b.integrate(pair.a, "aggressive-merge")) {
|
||||
chunks.splice(chunks.indexOf(pair.a), 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for(const pair of combinations) {
|
||||
const a = pair.b.size({
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const b = pair.a.size({
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const ab = pair.b.integratedSize(pair.a, {
|
||||
chunkOverhead: 0
|
||||
});
|
||||
let newSize;
|
||||
if(ab === false) {
|
||||
pair.improvement = false;
|
||||
return;
|
||||
} else {
|
||||
newSize = ab;
|
||||
}
|
||||
|
||||
pair.improvement = (a + b) / newSize;
|
||||
}
|
||||
combinations = combinations.filter((pair) => {
|
||||
return pair.improvement !== false;
|
||||
});
|
||||
combinations.sort((a, b) => {
|
||||
return b.improvement - a.improvement;
|
||||
});
|
||||
|
||||
const pair = combinations[0];
|
||||
|
||||
if(!pair) return;
|
||||
if(pair.improvement < minSizeReduce) return;
|
||||
|
||||
if(pair.b.integrate(pair.a, "aggressive-merge")) {
|
||||
chunks.splice(chunks.indexOf(pair.a), 1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,219 +26,256 @@ class AggressiveSplittingPlugin {
|
|||
validateOptions(schema, options || {}, "Aggressive Splitting Plugin");
|
||||
|
||||
this.options = options || {};
|
||||
if(typeof this.options.minSize !== "number") this.options.minSize = 30 * 1024;
|
||||
if(typeof this.options.maxSize !== "number") this.options.maxSize = 50 * 1024;
|
||||
if(typeof this.options.chunkOverhead !== "number") this.options.chunkOverhead = 0;
|
||||
if(typeof this.options.entryChunkMultiplicator !== "number") this.options.entryChunkMultiplicator = 1;
|
||||
|
||||
if (typeof this.options.minSize !== "number")
|
||||
this.options.minSize = 30 * 1024;
|
||||
if (typeof this.options.maxSize !== "number")
|
||||
this.options.maxSize = 50 * 1024;
|
||||
if (typeof this.options.chunkOverhead !== "number")
|
||||
this.options.chunkOverhead = 0;
|
||||
if (typeof this.options.entryChunkMultiplicator !== "number")
|
||||
this.options.entryChunkMultiplicator = 1;
|
||||
}
|
||||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap("AggressiveSplittingPlugin", (compilation) => {
|
||||
let needAdditionalSeal = false;
|
||||
let newSplits;
|
||||
let fromAggressiveSplittingSet;
|
||||
let chunkSplitDataMap;
|
||||
compilation.hooks.optimize.tap("AggressiveSplittingPlugin", () => {
|
||||
newSplits = [];
|
||||
fromAggressiveSplittingSet = new Set();
|
||||
chunkSplitDataMap = new Map();
|
||||
});
|
||||
compilation.hooks.optimizeChunksAdvanced.tap("AggressiveSplittingPlugin", (chunks) => {
|
||||
// Precompute stuff
|
||||
const nameToModuleMap = new Map();
|
||||
const moduleToNameMap = new Map();
|
||||
for(const m of compilation.modules) {
|
||||
const name = identifierUtils.makePathsRelative(compiler.context, m.identifier(), compilation.cache);
|
||||
nameToModuleMap.set(name, m);
|
||||
moduleToNameMap.set(m, name);
|
||||
}
|
||||
|
||||
// Check used chunk ids
|
||||
const usedIds = new Set();
|
||||
for(const chunk of chunks) {
|
||||
usedIds.add(chunk.id);
|
||||
}
|
||||
|
||||
const recordedSplits = compilation.records && compilation.records.aggressiveSplits || [];
|
||||
const usedSplits = newSplits ? recordedSplits.concat(newSplits) : recordedSplits;
|
||||
|
||||
const minSize = this.options.minSize;
|
||||
const maxSize = this.options.maxSize;
|
||||
|
||||
const applySplit = (splitData) => {
|
||||
// Cannot split if id is already taken
|
||||
if(splitData.id !== undefined && usedIds.has(splitData.id)) return false;
|
||||
|
||||
// Get module objects from names
|
||||
const selectedModules = splitData.modules.map(name => nameToModuleMap.get(name));
|
||||
|
||||
// Does the modules exist at all?
|
||||
if(!selectedModules.every(Boolean)) return false;
|
||||
|
||||
// Check if size matches (faster than waiting for hash)
|
||||
const size = selectedModules.reduce((sum, m) => sum + m.size(), 0);
|
||||
if(size !== splitData.size) return false;
|
||||
|
||||
// get chunks with all modules
|
||||
const selectedChunks = intersect(selectedModules.map(m => new Set(m.chunksIterable)));
|
||||
|
||||
// No relevant chunks found
|
||||
if(selectedChunks.size === 0) return false;
|
||||
|
||||
// The found chunk is already the split or similar
|
||||
if(selectedChunks.size === 1 && Array.from(selectedChunks)[0].getNumberOfModules() === selectedModules.length) {
|
||||
const chunk = Array.from(selectedChunks)[0];
|
||||
if(fromAggressiveSplittingSet.has(chunk)) return false;
|
||||
fromAggressiveSplittingSet.add(chunk);
|
||||
chunkSplitDataMap.set(chunk, splitData);
|
||||
return true;
|
||||
}
|
||||
|
||||
// split the chunk into two parts
|
||||
const newChunk = compilation.addChunk();
|
||||
newChunk.chunkReason = "aggressive splitted";
|
||||
for(const chunk of selectedChunks) {
|
||||
selectedModules.forEach(moveModuleBetween(chunk, newChunk));
|
||||
chunk.split(newChunk);
|
||||
chunk.name = null;
|
||||
}
|
||||
fromAggressiveSplittingSet.add(newChunk);
|
||||
chunkSplitDataMap.set(newChunk, splitData);
|
||||
|
||||
if(splitData.id !== null && splitData.id !== undefined) {
|
||||
newChunk.id = splitData.id;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// try to restore to recorded splitting
|
||||
let changed = false;
|
||||
for(let j = 0; j < usedSplits.length; j++) {
|
||||
const splitData = usedSplits[j];
|
||||
if(applySplit(splitData))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// for any chunk which isn't splitted yet, split it and create a new entry
|
||||
// start with the biggest chunk
|
||||
const sortedChunks = chunks.slice().sort((a, b) => {
|
||||
const diff1 = b.modulesSize() - a.modulesSize();
|
||||
if(diff1) return diff1;
|
||||
const diff2 = a.getNumberOfModules() - b.getNumberOfModules();
|
||||
if(diff2) return diff2;
|
||||
const modulesA = Array.from(a.modulesIterable);
|
||||
const modulesB = Array.from(b.modulesIterable);
|
||||
modulesA.sort();
|
||||
modulesB.sort();
|
||||
const aI = modulesA[Symbol.iterator]();
|
||||
const bI = modulesB[Symbol.iterator]();
|
||||
while(true) { // eslint-disable-line
|
||||
const aItem = aI.next();
|
||||
const bItem = bI.next();
|
||||
if(aItem.done) return 0;
|
||||
const aModuleIdentifier = aItem.value.identifier();
|
||||
const bModuleIdentifier = bItem.value.identifier();
|
||||
if(aModuleIdentifier > bModuleIdentifier) return -1;
|
||||
if(aModuleIdentifier < bModuleIdentifier) return 1;
|
||||
}
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
"AggressiveSplittingPlugin",
|
||||
compilation => {
|
||||
let needAdditionalSeal = false;
|
||||
let newSplits;
|
||||
let fromAggressiveSplittingSet;
|
||||
let chunkSplitDataMap;
|
||||
compilation.hooks.optimize.tap("AggressiveSplittingPlugin", () => {
|
||||
newSplits = [];
|
||||
fromAggressiveSplittingSet = new Set();
|
||||
chunkSplitDataMap = new Map();
|
||||
});
|
||||
for(const chunk of sortedChunks) {
|
||||
if(fromAggressiveSplittingSet.has(chunk)) continue;
|
||||
const size = chunk.modulesSize();
|
||||
if(size > maxSize && chunk.getNumberOfModules() > 1) {
|
||||
const modules = chunk.getModules()
|
||||
.filter(isNotAEntryModule(chunk.entryModule))
|
||||
.sort((a, b) => {
|
||||
a = a.identifier();
|
||||
b = b.identifier();
|
||||
if(a > b) return 1;
|
||||
if(a < b) return -1;
|
||||
return 0;
|
||||
});
|
||||
const selectedModules = [];
|
||||
let selectedModulesSize = 0;
|
||||
for(let k = 0; k < modules.length; k++) {
|
||||
const module = modules[k];
|
||||
const newSize = selectedModulesSize + module.size();
|
||||
if(newSize > maxSize && selectedModulesSize >= minSize) break;
|
||||
selectedModulesSize = newSize;
|
||||
selectedModules.push(module);
|
||||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"AggressiveSplittingPlugin",
|
||||
chunks => {
|
||||
// Precompute stuff
|
||||
const nameToModuleMap = new Map();
|
||||
const moduleToNameMap = new Map();
|
||||
for (const m of compilation.modules) {
|
||||
const name = identifierUtils.makePathsRelative(
|
||||
compiler.context,
|
||||
m.identifier(),
|
||||
compilation.cache
|
||||
);
|
||||
nameToModuleMap.set(name, m);
|
||||
moduleToNameMap.set(m, name);
|
||||
}
|
||||
if(selectedModules.length === 0) continue;
|
||||
const splitData = {
|
||||
modules: selectedModules.map(m => moduleToNameMap.get(m)).sort(),
|
||||
size: selectedModulesSize
|
||||
|
||||
// Check used chunk ids
|
||||
const usedIds = new Set();
|
||||
for (const chunk of chunks) {
|
||||
usedIds.add(chunk.id);
|
||||
}
|
||||
|
||||
const recordedSplits =
|
||||
(compilation.records && compilation.records.aggressiveSplits) ||
|
||||
[];
|
||||
const usedSplits = newSplits
|
||||
? recordedSplits.concat(newSplits)
|
||||
: recordedSplits;
|
||||
|
||||
const minSize = this.options.minSize;
|
||||
const maxSize = this.options.maxSize;
|
||||
|
||||
const applySplit = splitData => {
|
||||
// Cannot split if id is already taken
|
||||
if (splitData.id !== undefined && usedIds.has(splitData.id))
|
||||
return false;
|
||||
|
||||
// Get module objects from names
|
||||
const selectedModules = splitData.modules.map(name =>
|
||||
nameToModuleMap.get(name)
|
||||
);
|
||||
|
||||
// Does the modules exist at all?
|
||||
if (!selectedModules.every(Boolean)) return false;
|
||||
|
||||
// Check if size matches (faster than waiting for hash)
|
||||
const size = selectedModules.reduce(
|
||||
(sum, m) => sum + m.size(),
|
||||
0
|
||||
);
|
||||
if (size !== splitData.size) return false;
|
||||
|
||||
// get chunks with all modules
|
||||
const selectedChunks = intersect(
|
||||
selectedModules.map(m => new Set(m.chunksIterable))
|
||||
);
|
||||
|
||||
// No relevant chunks found
|
||||
if (selectedChunks.size === 0) return false;
|
||||
|
||||
// The found chunk is already the split or similar
|
||||
if (
|
||||
selectedChunks.size === 1 &&
|
||||
Array.from(selectedChunks)[0].getNumberOfModules() ===
|
||||
selectedModules.length
|
||||
) {
|
||||
const chunk = Array.from(selectedChunks)[0];
|
||||
if (fromAggressiveSplittingSet.has(chunk)) return false;
|
||||
fromAggressiveSplittingSet.add(chunk);
|
||||
chunkSplitDataMap.set(chunk, splitData);
|
||||
return true;
|
||||
}
|
||||
|
||||
// split the chunk into two parts
|
||||
const newChunk = compilation.addChunk();
|
||||
newChunk.chunkReason = "aggressive splitted";
|
||||
for (const chunk of selectedChunks) {
|
||||
selectedModules.forEach(moveModuleBetween(chunk, newChunk));
|
||||
chunk.split(newChunk);
|
||||
chunk.name = null;
|
||||
}
|
||||
fromAggressiveSplittingSet.add(newChunk);
|
||||
chunkSplitDataMap.set(newChunk, splitData);
|
||||
|
||||
if (splitData.id !== null && splitData.id !== undefined) {
|
||||
newChunk.id = splitData.id;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if(applySplit(splitData)) {
|
||||
newSplits = (newSplits || []).concat(splitData);
|
||||
changed = true;
|
||||
// try to restore to recorded splitting
|
||||
let changed = false;
|
||||
for (let j = 0; j < usedSplits.length; j++) {
|
||||
const splitData = usedSplits[j];
|
||||
if (applySplit(splitData)) changed = true;
|
||||
}
|
||||
|
||||
// for any chunk which isn't splitted yet, split it and create a new entry
|
||||
// start with the biggest chunk
|
||||
const sortedChunks = chunks.slice().sort((a, b) => {
|
||||
const diff1 = b.modulesSize() - a.modulesSize();
|
||||
if (diff1) return diff1;
|
||||
const diff2 = a.getNumberOfModules() - b.getNumberOfModules();
|
||||
if (diff2) return diff2;
|
||||
const modulesA = Array.from(a.modulesIterable);
|
||||
const modulesB = Array.from(b.modulesIterable);
|
||||
modulesA.sort();
|
||||
modulesB.sort();
|
||||
const aI = modulesA[Symbol.iterator]();
|
||||
const bI = modulesB[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const aItem = aI.next();
|
||||
const bItem = bI.next();
|
||||
if (aItem.done) return 0;
|
||||
const aModuleIdentifier = aItem.value.identifier();
|
||||
const bModuleIdentifier = bItem.value.identifier();
|
||||
if (aModuleIdentifier > bModuleIdentifier) return -1;
|
||||
if (aModuleIdentifier < bModuleIdentifier) return 1;
|
||||
}
|
||||
});
|
||||
for (const chunk of sortedChunks) {
|
||||
if (fromAggressiveSplittingSet.has(chunk)) continue;
|
||||
const size = chunk.modulesSize();
|
||||
if (size > maxSize && chunk.getNumberOfModules() > 1) {
|
||||
const modules = chunk
|
||||
.getModules()
|
||||
.filter(isNotAEntryModule(chunk.entryModule))
|
||||
.sort((a, b) => {
|
||||
a = a.identifier();
|
||||
b = b.identifier();
|
||||
if (a > b) return 1;
|
||||
if (a < b) return -1;
|
||||
return 0;
|
||||
});
|
||||
const selectedModules = [];
|
||||
let selectedModulesSize = 0;
|
||||
for (let k = 0; k < modules.length; k++) {
|
||||
const module = modules[k];
|
||||
const newSize = selectedModulesSize + module.size();
|
||||
if (newSize > maxSize && selectedModulesSize >= minSize)
|
||||
break;
|
||||
selectedModulesSize = newSize;
|
||||
selectedModules.push(module);
|
||||
}
|
||||
if (selectedModules.length === 0) continue;
|
||||
const splitData = {
|
||||
modules: selectedModules
|
||||
.map(m => moduleToNameMap.get(m))
|
||||
.sort(),
|
||||
size: selectedModulesSize
|
||||
};
|
||||
|
||||
if (applySplit(splitData)) {
|
||||
newSplits = (newSplits || []).concat(splitData);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) return true;
|
||||
}
|
||||
);
|
||||
compilation.hooks.recordHash.tap(
|
||||
"AggressiveSplittingPlugin",
|
||||
records => {
|
||||
// 4. save made splittings to records
|
||||
const allSplits = new Set();
|
||||
const invalidSplits = new Set();
|
||||
|
||||
// Check if some splittings are invalid
|
||||
// We remove invalid splittings and try again
|
||||
for (const chunk of compilation.chunks) {
|
||||
const splitData = chunkSplitDataMap.get(chunk);
|
||||
if (splitData !== undefined) {
|
||||
if (splitData.hash && chunk.hash !== splitData.hash) {
|
||||
// Split was successful, but hash doesn't equal
|
||||
// We can throw away the split since it's useless now
|
||||
invalidSplits.add(splitData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidSplits.size > 0) {
|
||||
records.aggressiveSplits = records.aggressiveSplits.filter(
|
||||
splitData => !invalidSplits.has(splitData)
|
||||
);
|
||||
needAdditionalSeal = true;
|
||||
} else {
|
||||
// set hash and id values on all (new) splittings
|
||||
for (const chunk of compilation.chunks) {
|
||||
const splitData = chunkSplitDataMap.get(chunk);
|
||||
if (splitData !== undefined) {
|
||||
splitData.hash = chunk.hash;
|
||||
splitData.id = chunk.id;
|
||||
allSplits.add(splitData);
|
||||
// set flag for stats
|
||||
chunk.recorded = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Also add all unused historial splits (after the used ones)
|
||||
// They can still be used in some future compilation
|
||||
const recordedSplits =
|
||||
compilation.records && compilation.records.aggressiveSplits;
|
||||
if (recordedSplits) {
|
||||
for (const splitData of recordedSplits) {
|
||||
if (!invalidSplits.has(splitData)) allSplits.add(splitData);
|
||||
}
|
||||
}
|
||||
|
||||
// record all splits
|
||||
records.aggressiveSplits = Array.from(allSplits);
|
||||
|
||||
needAdditionalSeal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(changed)
|
||||
return true;
|
||||
});
|
||||
compilation.hooks.recordHash.tap("AggressiveSplittingPlugin", (records) => {
|
||||
// 4. save made splittings to records
|
||||
const allSplits = new Set();
|
||||
const invalidSplits = new Set();
|
||||
|
||||
// Check if some splittings are invalid
|
||||
// We remove invalid splittings and try again
|
||||
for(const chunk of compilation.chunks) {
|
||||
const splitData = chunkSplitDataMap.get(chunk);
|
||||
if(splitData !== undefined) {
|
||||
if(splitData.hash && chunk.hash !== splitData.hash) {
|
||||
// Split was successful, but hash doesn't equal
|
||||
// We can throw away the split since it's useless now
|
||||
invalidSplits.add(splitData);
|
||||
);
|
||||
compilation.hooks.needAdditionalSeal.tap(
|
||||
"AggressiveSplittingPlugin",
|
||||
() => {
|
||||
if (needAdditionalSeal) {
|
||||
needAdditionalSeal = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(invalidSplits.size > 0) {
|
||||
|
||||
records.aggressiveSplits = records.aggressiveSplits.filter(splitData => !invalidSplits.has(splitData));
|
||||
needAdditionalSeal = true;
|
||||
|
||||
} else {
|
||||
|
||||
// set hash and id values on all (new) splittings
|
||||
for(const chunk of compilation.chunks) {
|
||||
const splitData = chunkSplitDataMap.get(chunk);
|
||||
if(splitData !== undefined) {
|
||||
splitData.hash = chunk.hash;
|
||||
splitData.id = chunk.id;
|
||||
allSplits.add(splitData);
|
||||
// set flag for stats
|
||||
chunk.recorded = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Also add all unused historial splits (after the used ones)
|
||||
// They can still be used in some future compilation
|
||||
const recordedSplits = compilation.records && compilation.records.aggressiveSplits;
|
||||
if(recordedSplits) {
|
||||
for(const splitData of recordedSplits) {
|
||||
if(!invalidSplits.has(splitData))
|
||||
allSplits.add(splitData);
|
||||
}
|
||||
}
|
||||
|
||||
// record all splits
|
||||
records.aggressiveSplits = Array.from(allSplits);
|
||||
|
||||
needAdditionalSeal = false;
|
||||
}
|
||||
});
|
||||
compilation.hooks.needAdditionalSeal.tap("AggressiveSplittingPlugin", () => {
|
||||
if(needAdditionalSeal) {
|
||||
needAdditionalSeal = false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = AggressiveSplittingPlugin;
|
||||
|
|
|
@ -9,15 +9,20 @@ class ChunkModuleIdRangePlugin {
|
|||
}
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
compiler.hooks.compilation.tap("ChunkModuleIdRangePlugin", (compilation) => {
|
||||
compilation.hooks.moduleIds.tap("ChunkModuleIdRangePlugin", (modules) => {
|
||||
const chunk = this.chunks.find((chunk) => chunk.name === options.name);
|
||||
if(!chunk) throw new Error("ChunkModuleIdRangePlugin: Chunk with name '" + options.name + "' was not found");
|
||||
compiler.hooks.compilation.tap("ChunkModuleIdRangePlugin", compilation => {
|
||||
compilation.hooks.moduleIds.tap("ChunkModuleIdRangePlugin", modules => {
|
||||
const chunk = this.chunks.find(chunk => chunk.name === options.name);
|
||||
if (!chunk)
|
||||
throw new Error(
|
||||
"ChunkModuleIdRangePlugin: Chunk with name '" +
|
||||
options.name +
|
||||
"' was not found"
|
||||
);
|
||||
let currentId = options.start;
|
||||
let chunkModules;
|
||||
if(options.order) {
|
||||
if (options.order) {
|
||||
chunkModules = chunk.modules.slice();
|
||||
switch(options.order) {
|
||||
switch (options.order) {
|
||||
case "index":
|
||||
chunkModules.sort((a, b) => {
|
||||
return a.index - b.index;
|
||||
|
@ -29,22 +34,22 @@ class ChunkModuleIdRangePlugin {
|
|||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error("ChunkModuleIdRangePlugin: unexpected value of order");
|
||||
throw new Error(
|
||||
"ChunkModuleIdRangePlugin: unexpected value of order"
|
||||
);
|
||||
}
|
||||
|
||||
} else {
|
||||
chunkModules = modules.filter((m) => {
|
||||
chunkModules = modules.filter(m => {
|
||||
return m.chunks.includes(chunk);
|
||||
});
|
||||
}
|
||||
|
||||
for(let i = 0; i < chunkModules.length; i++) {
|
||||
for (let i = 0; i < chunkModules.length; i++) {
|
||||
const m = chunkModules[i];
|
||||
if(m.id === null) {
|
||||
if (m.id === null) {
|
||||
m.id = currentId++;
|
||||
}
|
||||
if(options.end && currentId > options.end)
|
||||
break;
|
||||
if (options.end && currentId > options.end) break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,54 +7,64 @@
|
|||
const GraphHelpers = require("../GraphHelpers");
|
||||
|
||||
class EnsureChunkConditionsPlugin {
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("EnsureChunkConditionsPlugin", (compilation) => {
|
||||
const handler = (chunks) => {
|
||||
let changed = false;
|
||||
for(const module of compilation.modules) {
|
||||
if(!module.chunkCondition) continue;
|
||||
const sourceChunks = new Set();
|
||||
const chunkGroups = new Set();
|
||||
for(const chunk of module.chunksIterable) {
|
||||
if(!module.chunkCondition(chunk)) {
|
||||
sourceChunks.add(chunk);
|
||||
for(const group of chunk.groupsIterable) {
|
||||
compiler.hooks.compilation.tap(
|
||||
"EnsureChunkConditionsPlugin",
|
||||
compilation => {
|
||||
const handler = chunks => {
|
||||
let changed = false;
|
||||
for (const module of compilation.modules) {
|
||||
if (!module.chunkCondition) continue;
|
||||
const sourceChunks = new Set();
|
||||
const chunkGroups = new Set();
|
||||
for (const chunk of module.chunksIterable) {
|
||||
if (!module.chunkCondition(chunk)) {
|
||||
sourceChunks.add(chunk);
|
||||
for (const group of chunk.groupsIterable) {
|
||||
chunkGroups.add(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sourceChunks.size === 0) continue;
|
||||
const targetChunks = new Set();
|
||||
chunkGroupLoop: for (const chunkGroup of chunkGroups) {
|
||||
// Can module be placed in a chunk of this group?
|
||||
for (const chunk of chunkGroup.chunks) {
|
||||
if (module.chunkCondition(chunk)) {
|
||||
targetChunks.add(chunk);
|
||||
continue chunkGroupLoop;
|
||||
}
|
||||
}
|
||||
// We reached the entrypoint: fail
|
||||
if (chunkGroup.isInitial()) {
|
||||
throw new Error(
|
||||
"Cannot fullfill chunk condition of " + module.identifier()
|
||||
);
|
||||
}
|
||||
// Try placing in all parents
|
||||
for (const group of chunkGroup.parentsIterable) {
|
||||
chunkGroups.add(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(sourceChunks.size === 0) continue;
|
||||
const targetChunks = new Set();
|
||||
chunkGroupLoop: for(const chunkGroup of chunkGroups) {
|
||||
// Can module be placed in a chunk of this group?
|
||||
for(const chunk of chunkGroup.chunks) {
|
||||
if(module.chunkCondition(chunk)) {
|
||||
targetChunks.add(chunk);
|
||||
continue chunkGroupLoop;
|
||||
}
|
||||
for (const sourceChunk of sourceChunks) {
|
||||
GraphHelpers.disconnectChunkAndModule(sourceChunk, module);
|
||||
}
|
||||
// We reached the entrypoint: fail
|
||||
if(chunkGroup.isInitial()) {
|
||||
throw new Error("Cannot fullfill chunk condition of " + module.identifier());
|
||||
}
|
||||
// Try placing in all parents
|
||||
for(const group of chunkGroup.parentsIterable) {
|
||||
chunkGroups.add(group);
|
||||
for (const targetChunk of targetChunks) {
|
||||
GraphHelpers.connectChunkAndModule(targetChunk, module);
|
||||
}
|
||||
}
|
||||
for(const sourceChunk of sourceChunks) {
|
||||
GraphHelpers.disconnectChunkAndModule(sourceChunk, module);
|
||||
}
|
||||
for(const targetChunk of targetChunks) {
|
||||
GraphHelpers.connectChunkAndModule(targetChunk, module);
|
||||
}
|
||||
}
|
||||
if(changed) return true;
|
||||
};
|
||||
compilation.hooks.optimizeChunksBasic.tap("EnsureChunkConditionsPlugin", handler);
|
||||
compilation.hooks.optimizeExtractedChunksBasic.tap("EnsureChunkConditionsPlugin", handler);
|
||||
});
|
||||
if (changed) return true;
|
||||
};
|
||||
compilation.hooks.optimizeChunksBasic.tap(
|
||||
"EnsureChunkConditionsPlugin",
|
||||
handler
|
||||
);
|
||||
compilation.hooks.optimizeExtractedChunksBasic.tap(
|
||||
"EnsureChunkConditionsPlugin",
|
||||
handler
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = EnsureChunkConditionsPlugin;
|
||||
|
|
|
@ -5,30 +5,33 @@
|
|||
"use strict";
|
||||
|
||||
class FlagIncludedChunksPlugin {
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("FlagIncludedChunksPlugin", (compilation) => {
|
||||
compilation.hooks.optimizeChunkIds.tap("FlagIncludedChunksPlugin", (chunks) => {
|
||||
for(const chunkA of chunks) {
|
||||
loopB: for(const chunkB of chunks) {
|
||||
// as we iterate the same iterables twice
|
||||
// skip if we find ourselves
|
||||
if(chunkA === chunkB) continue loopB;
|
||||
compiler.hooks.compilation.tap("FlagIncludedChunksPlugin", compilation => {
|
||||
compilation.hooks.optimizeChunkIds.tap(
|
||||
"FlagIncludedChunksPlugin",
|
||||
chunks => {
|
||||
for (const chunkA of chunks) {
|
||||
loopB: for (const chunkB of chunks) {
|
||||
// as we iterate the same iterables twice
|
||||
// skip if we find ourselves
|
||||
if (chunkA === chunkB) continue loopB;
|
||||
|
||||
// instead of swapping A and B just bail
|
||||
// as we loop twice the current A will be B and B then A
|
||||
if(chunkA.getNumberOfModules() < chunkB.getNumberOfModules()) continue loopB;
|
||||
// instead of swapping A and B just bail
|
||||
// as we loop twice the current A will be B and B then A
|
||||
if (chunkA.getNumberOfModules() < chunkB.getNumberOfModules())
|
||||
continue loopB;
|
||||
|
||||
if(chunkB.getNumberOfModules() === 0) continue loopB;
|
||||
if (chunkB.getNumberOfModules() === 0) continue loopB;
|
||||
|
||||
// is chunkB in chunkA?
|
||||
for(const m of chunkB.modulesIterable) {
|
||||
if(!chunkA.containsModule(m)) continue loopB;
|
||||
// is chunkB in chunkA?
|
||||
for (const m of chunkB.modulesIterable) {
|
||||
if (!chunkA.containsModule(m)) continue loopB;
|
||||
}
|
||||
chunkA.ids.push(chunkB.id);
|
||||
}
|
||||
chunkA.ids.push(chunkB.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,44 +14,52 @@ class LimitChunkCountPlugin {
|
|||
}
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
compiler.hooks.compilation.tap("LimitChunkCountPlugin", (compilation) => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap("LimitChunkCountPlugin", (chunks) => {
|
||||
const maxChunks = options.maxChunks;
|
||||
if(!maxChunks) return;
|
||||
if(maxChunks < 1) return;
|
||||
if(chunks.length <= maxChunks) return;
|
||||
compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"LimitChunkCountPlugin",
|
||||
chunks => {
|
||||
const maxChunks = options.maxChunks;
|
||||
if (!maxChunks) return;
|
||||
if (maxChunks < 1) return;
|
||||
if (chunks.length <= maxChunks) return;
|
||||
|
||||
const sortedExtendedPairCombinations = chunks.reduce((combinations, a, idx) => {
|
||||
// create combination pairs
|
||||
for(let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
combinations.push([b, a]);
|
||||
const sortedExtendedPairCombinations = chunks
|
||||
.reduce((combinations, a, idx) => {
|
||||
// create combination pairs
|
||||
for (let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
combinations.push([b, a]);
|
||||
}
|
||||
return combinations;
|
||||
}, [])
|
||||
.map(pair => {
|
||||
// extend combination pairs with size and integrated size
|
||||
const a = pair[0].size(options);
|
||||
const b = pair[1].size(options);
|
||||
const ab = pair[0].integratedSize(pair[1], options);
|
||||
return [a + b - ab, ab, pair[0], pair[1], a, b];
|
||||
})
|
||||
.filter(extendedPair => {
|
||||
// filter pairs that do not have an integratedSize
|
||||
// meaning they can NOT be integrated!
|
||||
return extendedPair[1] !== false;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// sadly javascript does an inplace sort here
|
||||
// sort them by size
|
||||
const diff = b[0] - a[0];
|
||||
if (diff !== 0) return diff;
|
||||
return a[1] - b[1];
|
||||
});
|
||||
|
||||
const pair = sortedExtendedPairCombinations[0];
|
||||
|
||||
if (pair && pair[2].integrate(pair[3], "limit")) {
|
||||
chunks.splice(chunks.indexOf(pair[3]), 1);
|
||||
return true;
|
||||
}
|
||||
return combinations;
|
||||
}, []).map((pair) => {
|
||||
// extend combination pairs with size and integrated size
|
||||
const a = pair[0].size(options);
|
||||
const b = pair[1].size(options);
|
||||
const ab = pair[0].integratedSize(pair[1], options);
|
||||
return [a + b - ab, ab, pair[0], pair[1], a, b];
|
||||
}).filter((extendedPair) => {
|
||||
// filter pairs that do not have an integratedSize
|
||||
// meaning they can NOT be integrated!
|
||||
return extendedPair[1] !== false;
|
||||
}).sort((a, b) => { // sadly javascript does an inplace sort here
|
||||
// sort them by size
|
||||
const diff = b[0] - a[0];
|
||||
if(diff !== 0) return diff;
|
||||
return a[1] - b[1];
|
||||
});
|
||||
|
||||
const pair = sortedExtendedPairCombinations[0];
|
||||
|
||||
if(pair && pair[2].integrate(pair[3], "limit")) {
|
||||
chunks.splice(chunks.indexOf(pair[3]), 1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,60 +5,71 @@
|
|||
"use strict";
|
||||
|
||||
class MergeDuplicateChunksPlugin {
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("MergeDuplicateChunksPlugin", (compilation) => {
|
||||
compilation.hooks.optimizeChunksBasic.tap("MergeDuplicateChunksPlugin", (chunks) => {
|
||||
// remember already tested chunks for performance
|
||||
const notDuplicates = new Set();
|
||||
compiler.hooks.compilation.tap(
|
||||
"MergeDuplicateChunksPlugin",
|
||||
compilation => {
|
||||
compilation.hooks.optimizeChunksBasic.tap(
|
||||
"MergeDuplicateChunksPlugin",
|
||||
chunks => {
|
||||
// remember already tested chunks for performance
|
||||
const notDuplicates = new Set();
|
||||
|
||||
// for each chunk
|
||||
for(const chunk of chunks) {
|
||||
|
||||
// track a Set of all chunk that could be duplicates
|
||||
let possibleDuplicates;
|
||||
for(const module of chunk.modulesIterable) {
|
||||
if(possibleDuplicates === undefined) {
|
||||
// when possibleDuplicates is not yet set,
|
||||
// create a new Set from chunks of the current module
|
||||
// including only chunks with the same number of modules
|
||||
for(const dup of module.chunksIterable) {
|
||||
if(dup !== chunk && chunk.getNumberOfModules() === dup.getNumberOfModules() && !notDuplicates.has(dup)) {
|
||||
// delay allocating the new Set until here, reduce memory pressure
|
||||
if(possibleDuplicates === undefined)
|
||||
possibleDuplicates = new Set();
|
||||
possibleDuplicates.add(dup);
|
||||
// for each chunk
|
||||
for (const chunk of chunks) {
|
||||
// track a Set of all chunk that could be duplicates
|
||||
let possibleDuplicates;
|
||||
for (const module of chunk.modulesIterable) {
|
||||
if (possibleDuplicates === undefined) {
|
||||
// when possibleDuplicates is not yet set,
|
||||
// create a new Set from chunks of the current module
|
||||
// including only chunks with the same number of modules
|
||||
for (const dup of module.chunksIterable) {
|
||||
if (
|
||||
dup !== chunk &&
|
||||
chunk.getNumberOfModules() === dup.getNumberOfModules() &&
|
||||
!notDuplicates.has(dup)
|
||||
) {
|
||||
// delay allocating the new Set until here, reduce memory pressure
|
||||
if (possibleDuplicates === undefined)
|
||||
possibleDuplicates = new Set();
|
||||
possibleDuplicates.add(dup);
|
||||
}
|
||||
}
|
||||
// when no chunk is possible we can break here
|
||||
if (possibleDuplicates === undefined) break;
|
||||
} else {
|
||||
// validate existing possible duplicates
|
||||
for (const dup of possibleDuplicates) {
|
||||
// remove possible duplicate when module is not contained
|
||||
if (!dup.containsModule(module))
|
||||
possibleDuplicates.delete(dup);
|
||||
}
|
||||
// when all chunks has been removed we can break here
|
||||
if (possibleDuplicates.size === 0) break;
|
||||
}
|
||||
}
|
||||
// when no chunk is possible we can break here
|
||||
if(possibleDuplicates === undefined) break;
|
||||
} else {
|
||||
// validate existing possible duplicates
|
||||
for(const dup of possibleDuplicates) {
|
||||
// remove possible duplicate when module is not contained
|
||||
if(!dup.containsModule(module))
|
||||
possibleDuplicates.delete(dup);
|
||||
|
||||
// when we found duplicates
|
||||
if (
|
||||
possibleDuplicates !== undefined &&
|
||||
possibleDuplicates.size > 0
|
||||
) {
|
||||
for (const otherChunk of possibleDuplicates) {
|
||||
if (otherChunk.hasRuntime() !== chunk.hasRuntime()) continue;
|
||||
// merge them
|
||||
if (chunk.integrate(otherChunk, "duplicate"))
|
||||
chunks.splice(chunks.indexOf(otherChunk), 1);
|
||||
}
|
||||
}
|
||||
// when all chunks has been removed we can break here
|
||||
if(possibleDuplicates.size === 0) break;
|
||||
|
||||
// don't check already processed chunks twice
|
||||
notDuplicates.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// when we found duplicates
|
||||
if(possibleDuplicates !== undefined && possibleDuplicates.size > 0) {
|
||||
for(const otherChunk of possibleDuplicates) {
|
||||
if(otherChunk.hasRuntime() !== chunk.hasRuntime()) continue;
|
||||
// merge them
|
||||
if(chunk.integrate(otherChunk, "duplicate"))
|
||||
chunks.splice(chunks.indexOf(otherChunk), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// don't check already processed chunks twice
|
||||
notDuplicates.add(chunk);
|
||||
}
|
||||
});
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = MergeDuplicateChunksPlugin;
|
||||
|
|
|
@ -16,50 +16,61 @@ class MinChunkSizePlugin {
|
|||
apply(compiler) {
|
||||
const options = this.options;
|
||||
const minChunkSize = options.minChunkSize;
|
||||
compiler.hooks.compilation.tap("MinChunkSizePlugin", (compilation) => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap("MinChunkSizePlugin", (chunks) => {
|
||||
const equalOptions = {
|
||||
chunkOverhead: 1,
|
||||
entryChunkMultiplicator: 1
|
||||
};
|
||||
compiler.hooks.compilation.tap("MinChunkSizePlugin", compilation => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"MinChunkSizePlugin",
|
||||
chunks => {
|
||||
const equalOptions = {
|
||||
chunkOverhead: 1,
|
||||
entryChunkMultiplicator: 1
|
||||
};
|
||||
|
||||
const sortedSizeFilteredExtendedPairCombinations = chunks.reduce((combinations, a, idx) => {
|
||||
// create combination pairs
|
||||
for(let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
combinations.push([b, a]);
|
||||
}
|
||||
return combinations;
|
||||
}, []).filter((pair) => {
|
||||
// check if one of the chunks sizes is smaller than the minChunkSize
|
||||
const p0SmallerThanMinChunkSize = pair[0].size(equalOptions) < minChunkSize;
|
||||
const p1SmallerThanMinChunkSize = pair[1].size(equalOptions) < minChunkSize;
|
||||
return p0SmallerThanMinChunkSize || p1SmallerThanMinChunkSize;
|
||||
}).map((pair) => {
|
||||
// extend combination pairs with size and integrated size
|
||||
const a = pair[0].size(options);
|
||||
const b = pair[1].size(options);
|
||||
const ab = pair[0].integratedSize(pair[1], options);
|
||||
return [a + b - ab, ab, pair[0], pair[1]];
|
||||
}).filter((pair) => {
|
||||
// filter pairs that do not have an integratedSize
|
||||
// meaning they can NOT be integrated!
|
||||
return pair[1] !== false;
|
||||
}).sort((a, b) => { // sadly javascript does an inplace sort here
|
||||
// sort by size
|
||||
const diff = b[0] - a[0];
|
||||
if(diff !== 0) return diff;
|
||||
return a[1] - b[1];
|
||||
});
|
||||
const sortedSizeFilteredExtendedPairCombinations = chunks
|
||||
.reduce((combinations, a, idx) => {
|
||||
// create combination pairs
|
||||
for (let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
combinations.push([b, a]);
|
||||
}
|
||||
return combinations;
|
||||
}, [])
|
||||
.filter(pair => {
|
||||
// check if one of the chunks sizes is smaller than the minChunkSize
|
||||
const p0SmallerThanMinChunkSize =
|
||||
pair[0].size(equalOptions) < minChunkSize;
|
||||
const p1SmallerThanMinChunkSize =
|
||||
pair[1].size(equalOptions) < minChunkSize;
|
||||
return p0SmallerThanMinChunkSize || p1SmallerThanMinChunkSize;
|
||||
})
|
||||
.map(pair => {
|
||||
// extend combination pairs with size and integrated size
|
||||
const a = pair[0].size(options);
|
||||
const b = pair[1].size(options);
|
||||
const ab = pair[0].integratedSize(pair[1], options);
|
||||
return [a + b - ab, ab, pair[0], pair[1]];
|
||||
})
|
||||
.filter(pair => {
|
||||
// filter pairs that do not have an integratedSize
|
||||
// meaning they can NOT be integrated!
|
||||
return pair[1] !== false;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// sadly javascript does an inplace sort here
|
||||
// sort by size
|
||||
const diff = b[0] - a[0];
|
||||
if (diff !== 0) return diff;
|
||||
return a[1] - b[1];
|
||||
});
|
||||
|
||||
if(sortedSizeFilteredExtendedPairCombinations.length === 0) return;
|
||||
if (sortedSizeFilteredExtendedPairCombinations.length === 0) return;
|
||||
|
||||
const pair = sortedSizeFilteredExtendedPairCombinations[0];
|
||||
const pair = sortedSizeFilteredExtendedPairCombinations[0];
|
||||
|
||||
pair[2].integrate(pair[3], "min-size");
|
||||
chunks.splice(chunks.indexOf(pair[3]), 1);
|
||||
return true;
|
||||
});
|
||||
pair[2].integrate(pair[3], "min-size");
|
||||
chunks.splice(chunks.indexOf(pair[3]), 1);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,240 +17,333 @@ const formatBailoutReason = msg => {
|
|||
|
||||
class ModuleConcatenationPlugin {
|
||||
constructor(options) {
|
||||
if(typeof options !== "object") options = {};
|
||||
if (typeof options !== "object") options = {};
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("ModuleConcatenationPlugin", (compilation, {
|
||||
normalModuleFactory
|
||||
}) => {
|
||||
const handler = (parser, parserOptions) => {
|
||||
parser.hooks.call.for("eval").tap("ModuleConcatenationPlugin", () => {
|
||||
// Because of variable renaming we can't use modules with eval.
|
||||
parser.state.module.buildMeta.moduleConcatenationBailout = "eval()";
|
||||
});
|
||||
};
|
||||
compiler.hooks.compilation.tap(
|
||||
"ModuleConcatenationPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
const handler = (parser, parserOptions) => {
|
||||
parser.hooks.call.for("eval").tap("ModuleConcatenationPlugin", () => {
|
||||
// Because of variable renaming we can't use modules with eval.
|
||||
parser.state.module.buildMeta.moduleConcatenationBailout = "eval()";
|
||||
});
|
||||
};
|
||||
|
||||
normalModuleFactory.hooks.parser.for("javascript/auto").tap("ModuleConcatenationPlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("ModuleConcatenationPlugin", handler);
|
||||
normalModuleFactory.hooks.parser.for("javascript/esm").tap("ModuleConcatenationPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("ModuleConcatenationPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/dynamic")
|
||||
.tap("ModuleConcatenationPlugin", handler);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/esm")
|
||||
.tap("ModuleConcatenationPlugin", handler);
|
||||
|
||||
const bailoutReasonMap = new Map();
|
||||
const bailoutReasonMap = new Map();
|
||||
|
||||
const setBailoutReason = (module, reason) => {
|
||||
bailoutReasonMap.set(module, reason);
|
||||
module.optimizationBailout.push(typeof reason === "function" ? (rs) => formatBailoutReason(reason(rs)) : formatBailoutReason(reason));
|
||||
};
|
||||
const setBailoutReason = (module, reason) => {
|
||||
bailoutReasonMap.set(module, reason);
|
||||
module.optimizationBailout.push(
|
||||
typeof reason === "function"
|
||||
? rs => formatBailoutReason(reason(rs))
|
||||
: formatBailoutReason(reason)
|
||||
);
|
||||
};
|
||||
|
||||
const getBailoutReason = (module, requestShortener) => {
|
||||
const reason = bailoutReasonMap.get(module);
|
||||
if(typeof reason === "function") return reason(requestShortener);
|
||||
return reason;
|
||||
};
|
||||
const getBailoutReason = (module, requestShortener) => {
|
||||
const reason = bailoutReasonMap.get(module);
|
||||
if (typeof reason === "function") return reason(requestShortener);
|
||||
return reason;
|
||||
};
|
||||
|
||||
compilation.hooks.optimizeChunkModules.tap("ModuleConcatenationPlugin", (chunks, modules) => {
|
||||
const relevantModules = [];
|
||||
const possibleInners = new Set();
|
||||
for(const module of modules) {
|
||||
// Only harmony modules are valid for optimization
|
||||
if(!module.buildMeta || module.buildMeta.exportsType !== "namespace" || !module.dependencies.some(d => d instanceof HarmonyCompatibilityDependency)) {
|
||||
setBailoutReason(module, "Module is not an ECMAScript module");
|
||||
continue;
|
||||
}
|
||||
compilation.hooks.optimizeChunkModules.tap(
|
||||
"ModuleConcatenationPlugin",
|
||||
(chunks, modules) => {
|
||||
const relevantModules = [];
|
||||
const possibleInners = new Set();
|
||||
for (const module of modules) {
|
||||
// Only harmony modules are valid for optimization
|
||||
if (
|
||||
!module.buildMeta ||
|
||||
module.buildMeta.exportsType !== "namespace" ||
|
||||
!module.dependencies.some(
|
||||
d => d instanceof HarmonyCompatibilityDependency
|
||||
)
|
||||
) {
|
||||
setBailoutReason(module, "Module is not an ECMAScript module");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Some expressions are not compatible with module concatenation
|
||||
// because they may produce unexpected results. The plugin bails out
|
||||
// if some were detected upfront.
|
||||
if(module.buildMeta && module.buildMeta.moduleConcatenationBailout) {
|
||||
setBailoutReason(module, `Module uses ${module.buildMeta.moduleConcatenationBailout}`);
|
||||
continue;
|
||||
}
|
||||
// Some expressions are not compatible with module concatenation
|
||||
// because they may produce unexpected results. The plugin bails out
|
||||
// if some were detected upfront.
|
||||
if (
|
||||
module.buildMeta &&
|
||||
module.buildMeta.moduleConcatenationBailout
|
||||
) {
|
||||
setBailoutReason(
|
||||
module,
|
||||
`Module uses ${module.buildMeta.moduleConcatenationBailout}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exports must be known (and not dynamic)
|
||||
if(!Array.isArray(module.buildMeta.providedExports)) {
|
||||
setBailoutReason(module, "Module exports are unknown");
|
||||
continue;
|
||||
}
|
||||
// Exports must be known (and not dynamic)
|
||||
if (!Array.isArray(module.buildMeta.providedExports)) {
|
||||
setBailoutReason(module, "Module exports are unknown");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Using dependency variables is not possible as this wraps the code in a function
|
||||
if(module.variables.length > 0) {
|
||||
setBailoutReason(module, `Module uses injected variables (${module.variables.map(v => v.name).join(", ")})`);
|
||||
continue;
|
||||
}
|
||||
// Using dependency variables is not possible as this wraps the code in a function
|
||||
if (module.variables.length > 0) {
|
||||
setBailoutReason(
|
||||
module,
|
||||
`Module uses injected variables (${module.variables
|
||||
.map(v => v.name)
|
||||
.join(", ")})`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hot Module Replacement need it's own module to work correctly
|
||||
if(module.dependencies.some(dep => dep instanceof ModuleHotAcceptDependency || dep instanceof ModuleHotDeclineDependency)) {
|
||||
setBailoutReason(module, "Module uses Hot Module Replacement");
|
||||
continue;
|
||||
}
|
||||
// Hot Module Replacement need it's own module to work correctly
|
||||
if (
|
||||
module.dependencies.some(
|
||||
dep =>
|
||||
dep instanceof ModuleHotAcceptDependency ||
|
||||
dep instanceof ModuleHotDeclineDependency
|
||||
)
|
||||
) {
|
||||
setBailoutReason(module, "Module uses Hot Module Replacement");
|
||||
continue;
|
||||
}
|
||||
|
||||
relevantModules.push(module);
|
||||
relevantModules.push(module);
|
||||
|
||||
// Module must not be the entry points
|
||||
if(module.isEntryModule()) {
|
||||
setBailoutReason(module, "Module is an entry point");
|
||||
continue;
|
||||
}
|
||||
// Module must not be the entry points
|
||||
if (module.isEntryModule()) {
|
||||
setBailoutReason(module, "Module is an entry point");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Module must be in any chunk (we don't want to do useless work)
|
||||
if(module.getNumberOfChunks() === 0) {
|
||||
setBailoutReason(module, "Module is not in any chunk");
|
||||
continue;
|
||||
}
|
||||
// Module must be in any chunk (we don't want to do useless work)
|
||||
if (module.getNumberOfChunks() === 0) {
|
||||
setBailoutReason(module, "Module is not in any chunk");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Module must only be used by Harmony Imports
|
||||
const nonHarmonyReasons = module.reasons.filter(reason => !reason.dependency || !(reason.dependency instanceof HarmonyImportDependency));
|
||||
if(nonHarmonyReasons.length > 0) {
|
||||
const importingModules = new Set(nonHarmonyReasons.map(r => r.module).filter(Boolean));
|
||||
const importingExplanations = new Set(nonHarmonyReasons.map(r => r.explanation).filter(Boolean));
|
||||
const importingModuleTypes = new Map(Array.from(importingModules).map(m => [m, new Set(nonHarmonyReasons.filter(r => r.module === m).map(r => r.dependency.type).sort())]));
|
||||
setBailoutReason(module, (requestShortener) => {
|
||||
const names = Array.from(importingModules).map(m => `${m.readableIdentifier(requestShortener)} (referenced with ${Array.from(importingModuleTypes.get(m)).join(", ")})`).sort();
|
||||
const explanations = Array.from(importingExplanations).sort();
|
||||
if(names.length > 0 && explanations.length === 0)
|
||||
return `Module is referenced from these modules with unsupported syntax: ${names.join(", ")}`;
|
||||
else if(names.length === 0 && explanations.length > 0)
|
||||
return `Module is referenced by: ${explanations.join(", ")}`;
|
||||
else if(names.length > 0 && explanations.length > 0)
|
||||
return `Module is referenced from these modules with unsupported syntax: ${names.join(", ")} and by: ${explanations.join(", ")}`;
|
||||
else
|
||||
return "Module is referenced in a unsupported way";
|
||||
// Module must only be used by Harmony Imports
|
||||
const nonHarmonyReasons = module.reasons.filter(
|
||||
reason =>
|
||||
!reason.dependency ||
|
||||
!(reason.dependency instanceof HarmonyImportDependency)
|
||||
);
|
||||
if (nonHarmonyReasons.length > 0) {
|
||||
const importingModules = new Set(
|
||||
nonHarmonyReasons.map(r => r.module).filter(Boolean)
|
||||
);
|
||||
const importingExplanations = new Set(
|
||||
nonHarmonyReasons.map(r => r.explanation).filter(Boolean)
|
||||
);
|
||||
const importingModuleTypes = new Map(
|
||||
Array.from(importingModules).map(m => [
|
||||
m,
|
||||
new Set(
|
||||
nonHarmonyReasons
|
||||
.filter(r => r.module === m)
|
||||
.map(r => r.dependency.type)
|
||||
.sort()
|
||||
)
|
||||
])
|
||||
);
|
||||
setBailoutReason(module, requestShortener => {
|
||||
const names = Array.from(importingModules)
|
||||
.map(
|
||||
m =>
|
||||
`${m.readableIdentifier(
|
||||
requestShortener
|
||||
)} (referenced with ${Array.from(
|
||||
importingModuleTypes.get(m)
|
||||
).join(", ")})`
|
||||
)
|
||||
.sort();
|
||||
const explanations = Array.from(importingExplanations).sort();
|
||||
if (names.length > 0 && explanations.length === 0)
|
||||
return `Module is referenced from these modules with unsupported syntax: ${names.join(
|
||||
", "
|
||||
)}`;
|
||||
else if (names.length === 0 && explanations.length > 0)
|
||||
return `Module is referenced by: ${explanations.join(
|
||||
", "
|
||||
)}`;
|
||||
else if (names.length > 0 && explanations.length > 0)
|
||||
return `Module is referenced from these modules with unsupported syntax: ${names.join(
|
||||
", "
|
||||
)} and by: ${explanations.join(", ")}`;
|
||||
else return "Module is referenced in a unsupported way";
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
possibleInners.add(module);
|
||||
}
|
||||
// sort by depth
|
||||
// modules with lower depth are more likely suited as roots
|
||||
// this improves performance, because modules already selected as inner are skipped
|
||||
relevantModules.sort((a, b) => {
|
||||
return a.depth - b.depth;
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const concatConfigurations = [];
|
||||
const usedAsInner = new Set();
|
||||
for (const currentRoot of relevantModules) {
|
||||
// when used by another configuration as inner:
|
||||
// the other configuration is better and we can skip this one
|
||||
if (usedAsInner.has(currentRoot)) continue;
|
||||
|
||||
possibleInners.add(module);
|
||||
}
|
||||
// sort by depth
|
||||
// modules with lower depth are more likely suited as roots
|
||||
// this improves performance, because modules already selected as inner are skipped
|
||||
relevantModules.sort((a, b) => {
|
||||
return a.depth - b.depth;
|
||||
});
|
||||
const concatConfigurations = [];
|
||||
const usedAsInner = new Set();
|
||||
for(const currentRoot of relevantModules) {
|
||||
// when used by another configuration as inner:
|
||||
// the other configuration is better and we can skip this one
|
||||
if(usedAsInner.has(currentRoot))
|
||||
continue;
|
||||
// create a configuration with the root
|
||||
const currentConfiguration = new ConcatConfiguration(currentRoot);
|
||||
|
||||
// create a configuration with the root
|
||||
const currentConfiguration = new ConcatConfiguration(currentRoot);
|
||||
// cache failures to add modules
|
||||
const failureCache = new Map();
|
||||
|
||||
// cache failures to add modules
|
||||
const failureCache = new Map();
|
||||
|
||||
// try to add all imports
|
||||
for(const imp of this.getImports(currentRoot)) {
|
||||
const problem = this.tryToAdd(currentConfiguration, imp, possibleInners, failureCache);
|
||||
if(problem) {
|
||||
failureCache.set(imp, problem);
|
||||
currentConfiguration.addWarning(imp, problem);
|
||||
}
|
||||
}
|
||||
if(!currentConfiguration.isEmpty()) {
|
||||
concatConfigurations.push(currentConfiguration);
|
||||
for(const module of currentConfiguration.getModules()) {
|
||||
if(module !== currentConfiguration.rootModule)
|
||||
usedAsInner.add(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
// HACK: Sort configurations by length and start with the longest one
|
||||
// to get the biggers groups possible. Used modules are marked with usedModules
|
||||
// TODO: Allow to reuse existing configuration while trying to add dependencies.
|
||||
// This would improve performance. O(n^2) -> O(n)
|
||||
concatConfigurations.sort((a, b) => {
|
||||
return b.modules.size - a.modules.size;
|
||||
});
|
||||
const usedModules = new Set();
|
||||
for(const concatConfiguration of concatConfigurations) {
|
||||
if(usedModules.has(concatConfiguration.rootModule))
|
||||
continue;
|
||||
const modules = concatConfiguration.getModules();
|
||||
const newModule = new ConcatenatedModule(concatConfiguration.rootModule, modules);
|
||||
for(const warning of concatConfiguration.getWarningsSorted()) {
|
||||
newModule.optimizationBailout.push((requestShortener) => {
|
||||
const reason = getBailoutReason(warning[0], requestShortener);
|
||||
const reasonWithPrefix = reason ? ` (<- ${reason})` : "";
|
||||
if(warning[0] === warning[1])
|
||||
return formatBailoutReason(`Cannot concat with ${warning[0].readableIdentifier(requestShortener)}${reasonWithPrefix}`);
|
||||
else
|
||||
return formatBailoutReason(`Cannot concat with ${warning[0].readableIdentifier(requestShortener)} because of ${warning[1].readableIdentifier(requestShortener)}${reasonWithPrefix}`);
|
||||
});
|
||||
}
|
||||
const chunks = concatConfiguration.rootModule.getChunks();
|
||||
for(const m of modules) {
|
||||
usedModules.add(m);
|
||||
for(const chunk of chunks) {
|
||||
chunk.removeModule(m);
|
||||
}
|
||||
}
|
||||
for(const chunk of chunks) {
|
||||
chunk.addModule(newModule);
|
||||
newModule.addChunk(chunk);
|
||||
if(chunk.entryModule === concatConfiguration.rootModule)
|
||||
chunk.entryModule = newModule;
|
||||
}
|
||||
compilation.modules.push(newModule);
|
||||
for(const reason of newModule.reasons) {
|
||||
reason.dependency.module = newModule;
|
||||
}
|
||||
for(const dep of newModule.dependencies) {
|
||||
if(dep.module) {
|
||||
for(const reason of dep.module.reasons) {
|
||||
if(reason.dependency === dep)
|
||||
reason.module = newModule;
|
||||
// try to add all imports
|
||||
for (const imp of this.getImports(currentRoot)) {
|
||||
const problem = this.tryToAdd(
|
||||
currentConfiguration,
|
||||
imp,
|
||||
possibleInners,
|
||||
failureCache
|
||||
);
|
||||
if (problem) {
|
||||
failureCache.set(imp, problem);
|
||||
currentConfiguration.addWarning(imp, problem);
|
||||
}
|
||||
}
|
||||
if (!currentConfiguration.isEmpty()) {
|
||||
concatConfigurations.push(currentConfiguration);
|
||||
for (const module of currentConfiguration.getModules()) {
|
||||
if (module !== currentConfiguration.rootModule)
|
||||
usedAsInner.add(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
// HACK: Sort configurations by length and start with the longest one
|
||||
// to get the biggers groups possible. Used modules are marked with usedModules
|
||||
// TODO: Allow to reuse existing configuration while trying to add dependencies.
|
||||
// This would improve performance. O(n^2) -> O(n)
|
||||
concatConfigurations.sort((a, b) => {
|
||||
return b.modules.size - a.modules.size;
|
||||
});
|
||||
const usedModules = new Set();
|
||||
for (const concatConfiguration of concatConfigurations) {
|
||||
if (usedModules.has(concatConfiguration.rootModule)) continue;
|
||||
const modules = concatConfiguration.getModules();
|
||||
const newModule = new ConcatenatedModule(
|
||||
concatConfiguration.rootModule,
|
||||
modules
|
||||
);
|
||||
for (const warning of concatConfiguration.getWarningsSorted()) {
|
||||
newModule.optimizationBailout.push(requestShortener => {
|
||||
const reason = getBailoutReason(warning[0], requestShortener);
|
||||
const reasonWithPrefix = reason ? ` (<- ${reason})` : "";
|
||||
if (warning[0] === warning[1])
|
||||
return formatBailoutReason(
|
||||
`Cannot concat with ${warning[0].readableIdentifier(
|
||||
requestShortener
|
||||
)}${reasonWithPrefix}`
|
||||
);
|
||||
else
|
||||
return formatBailoutReason(
|
||||
`Cannot concat with ${warning[0].readableIdentifier(
|
||||
requestShortener
|
||||
)} because of ${warning[1].readableIdentifier(
|
||||
requestShortener
|
||||
)}${reasonWithPrefix}`
|
||||
);
|
||||
});
|
||||
}
|
||||
const chunks = concatConfiguration.rootModule.getChunks();
|
||||
for (const m of modules) {
|
||||
usedModules.add(m);
|
||||
for (const chunk of chunks) {
|
||||
chunk.removeModule(m);
|
||||
}
|
||||
}
|
||||
for (const chunk of chunks) {
|
||||
chunk.addModule(newModule);
|
||||
newModule.addChunk(chunk);
|
||||
if (chunk.entryModule === concatConfiguration.rootModule)
|
||||
chunk.entryModule = newModule;
|
||||
}
|
||||
compilation.modules.push(newModule);
|
||||
for (const reason of newModule.reasons) {
|
||||
reason.dependency.module = newModule;
|
||||
}
|
||||
for (const dep of newModule.dependencies) {
|
||||
if (dep.module) {
|
||||
for (const reason of dep.module.reasons) {
|
||||
if (reason.dependency === dep) reason.module = newModule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
compilation.modules = compilation.modules.filter(
|
||||
m => !usedModules.has(m)
|
||||
);
|
||||
}
|
||||
}
|
||||
compilation.modules = compilation.modules.filter(m => !usedModules.has(m));
|
||||
});
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getImports(module) {
|
||||
return Array.from(new Set(module.dependencies
|
||||
return Array.from(
|
||||
new Set(
|
||||
module.dependencies
|
||||
|
||||
// Only harmony Dependencies
|
||||
.filter(dep => dep instanceof HarmonyImportDependency && dep.module)
|
||||
// Only harmony Dependencies
|
||||
.filter(dep => dep instanceof HarmonyImportDependency && dep.module)
|
||||
|
||||
// Get reference info for this dependency
|
||||
.map(dep => dep.getReference())
|
||||
// Get reference info for this dependency
|
||||
.map(dep => dep.getReference())
|
||||
|
||||
// Reference is valid and has a module
|
||||
.filter(ref => ref && ref.module)
|
||||
// Reference is valid and has a module
|
||||
.filter(ref => ref && ref.module)
|
||||
|
||||
// Dependencies are simple enough to concat them
|
||||
.filter(ref => Array.isArray(ref.importedNames) || Array.isArray(ref.module.buildMeta.providedExports))
|
||||
// Dependencies are simple enough to concat them
|
||||
.filter(
|
||||
ref =>
|
||||
Array.isArray(ref.importedNames) ||
|
||||
Array.isArray(ref.module.buildMeta.providedExports)
|
||||
)
|
||||
|
||||
// Take the imported module
|
||||
.map(ref => ref.module)
|
||||
));
|
||||
// Take the imported module
|
||||
.map(ref => ref.module)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
tryToAdd(config, module, possibleModules, failureCache) {
|
||||
const cacheEntry = failureCache.get(module);
|
||||
if(cacheEntry) {
|
||||
if (cacheEntry) {
|
||||
return cacheEntry;
|
||||
}
|
||||
|
||||
// Already added?
|
||||
if(config.has(module)) {
|
||||
if (config.has(module)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Not possible to add?
|
||||
if(!possibleModules.has(module)) {
|
||||
if (!possibleModules.has(module)) {
|
||||
failureCache.set(module, module); // cache failures for performance
|
||||
return module;
|
||||
}
|
||||
|
||||
// module must be in the same chunks
|
||||
if(!config.rootModule.hasEqualsChunks(module)) {
|
||||
if (!config.rootModule.hasEqualsChunks(module)) {
|
||||
failureCache.set(module, module); // cache failures for performance
|
||||
return module;
|
||||
}
|
||||
|
@ -262,22 +355,35 @@ class ModuleConcatenationPlugin {
|
|||
testConfig.add(module);
|
||||
|
||||
// Every module which depends on the added module must be in the configuration too.
|
||||
for(const reason of module.reasons) {
|
||||
|
||||
for (const reason of module.reasons) {
|
||||
// Modules that are not used can be ignored
|
||||
if(reason.module.factoryMeta.sideEffectFree && reason.module.used === false) continue;
|
||||
if (
|
||||
reason.module.factoryMeta.sideEffectFree &&
|
||||
reason.module.used === false
|
||||
)
|
||||
continue;
|
||||
|
||||
const problem = this.tryToAdd(testConfig, reason.module, possibleModules, failureCache);
|
||||
if(problem) {
|
||||
const problem = this.tryToAdd(
|
||||
testConfig,
|
||||
reason.module,
|
||||
possibleModules,
|
||||
failureCache
|
||||
);
|
||||
if (problem) {
|
||||
failureCache.set(module, problem); // cache failures for performance
|
||||
return problem;
|
||||
}
|
||||
}
|
||||
|
||||
// Eagerly try to add imports too if possible
|
||||
for(const imp of this.getImports(module)) {
|
||||
const problem = this.tryToAdd(testConfig, imp, possibleModules, failureCache);
|
||||
if(problem) {
|
||||
for (const imp of this.getImports(module)) {
|
||||
const problem = this.tryToAdd(
|
||||
testConfig,
|
||||
imp,
|
||||
possibleModules,
|
||||
failureCache
|
||||
);
|
||||
if (problem) {
|
||||
config.addWarning(module, problem);
|
||||
}
|
||||
}
|
||||
|
@ -291,7 +397,7 @@ class ModuleConcatenationPlugin {
|
|||
class ConcatConfiguration {
|
||||
constructor(rootModule, cloneFrom) {
|
||||
this.rootModule = rootModule;
|
||||
if(cloneFrom) {
|
||||
if (cloneFrom) {
|
||||
this.modules = cloneFrom.modules.createChild(5);
|
||||
this.warnings = cloneFrom.warnings.createChild(5);
|
||||
} else {
|
||||
|
@ -318,13 +424,15 @@ class ConcatConfiguration {
|
|||
}
|
||||
|
||||
getWarningsSorted() {
|
||||
return new Map(this.warnings.asPairArray().sort((a, b) => {
|
||||
const ai = a[0].identifier();
|
||||
const bi = b[0].identifier();
|
||||
if(ai < bi) return -1;
|
||||
if(ai > bi) return 1;
|
||||
return 0;
|
||||
}));
|
||||
return new Map(
|
||||
this.warnings.asPairArray().sort((a, b) => {
|
||||
const ai = a[0].identifier();
|
||||
const bi = b[0].identifier();
|
||||
if (ai < bi) return -1;
|
||||
if (ai > bi) return 1;
|
||||
return 0;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getModules() {
|
||||
|
|
|
@ -6,106 +6,119 @@
|
|||
|
||||
class OccurrenceOrderPlugin {
|
||||
constructor(preferEntry) {
|
||||
if(preferEntry !== undefined && typeof preferEntry !== "boolean") {
|
||||
throw new Error("Argument should be a boolean.\nFor more info on this plugin, see https://webpack.js.org/plugins/");
|
||||
if (preferEntry !== undefined && typeof preferEntry !== "boolean") {
|
||||
throw new Error(
|
||||
"Argument should be a boolean.\nFor more info on this plugin, see https://webpack.js.org/plugins/"
|
||||
);
|
||||
}
|
||||
this.preferEntry = preferEntry;
|
||||
}
|
||||
apply(compiler) {
|
||||
const preferEntry = this.preferEntry;
|
||||
compiler.hooks.compilation.tap("OccurrenceOrderPlugin", (compilation) => {
|
||||
compilation.hooks.optimizeModuleOrder.tap("OccurrenceOrderPlugin", (modules) => {
|
||||
const occursInInitialChunksMap = new Map();
|
||||
const occursInAllChunksMap = new Map();
|
||||
compiler.hooks.compilation.tap("OccurrenceOrderPlugin", compilation => {
|
||||
compilation.hooks.optimizeModuleOrder.tap(
|
||||
"OccurrenceOrderPlugin",
|
||||
modules => {
|
||||
const occursInInitialChunksMap = new Map();
|
||||
const occursInAllChunksMap = new Map();
|
||||
|
||||
const initialChunkChunkMap = new Map();
|
||||
const entryCountMap = new Map();
|
||||
for(const m of modules) {
|
||||
let initial = 0;
|
||||
let entry = 0;
|
||||
for(const c of m.chunksIterable) {
|
||||
if(c.canBeInitial()) initial++;
|
||||
if(c.entryModule === m) entry++;
|
||||
const initialChunkChunkMap = new Map();
|
||||
const entryCountMap = new Map();
|
||||
for (const m of modules) {
|
||||
let initial = 0;
|
||||
let entry = 0;
|
||||
for (const c of m.chunksIterable) {
|
||||
if (c.canBeInitial()) initial++;
|
||||
if (c.entryModule === m) entry++;
|
||||
}
|
||||
initialChunkChunkMap.set(m, initial);
|
||||
entryCountMap.set(m, entry);
|
||||
}
|
||||
initialChunkChunkMap.set(m, initial);
|
||||
entryCountMap.set(m, entry);
|
||||
}
|
||||
|
||||
const countOccursInEntry = (sum, r) => {
|
||||
if(!r.module) return sum;
|
||||
return sum + initialChunkChunkMap.get(r.module);
|
||||
};
|
||||
const countOccurs = (sum, r) => {
|
||||
if(!r.module) return sum;
|
||||
let factor = 1;
|
||||
if(typeof r.dependency.getNumberOfIdOccurrences === "function")
|
||||
factor = r.dependency.getNumberOfIdOccurrences();
|
||||
if(factor === 0) return sum;
|
||||
return sum + factor * r.module.getNumberOfChunks();
|
||||
};
|
||||
const countOccursInEntry = (sum, r) => {
|
||||
if (!r.module) return sum;
|
||||
return sum + initialChunkChunkMap.get(r.module);
|
||||
};
|
||||
const countOccurs = (sum, r) => {
|
||||
if (!r.module) return sum;
|
||||
let factor = 1;
|
||||
if (typeof r.dependency.getNumberOfIdOccurrences === "function")
|
||||
factor = r.dependency.getNumberOfIdOccurrences();
|
||||
if (factor === 0) return sum;
|
||||
return sum + factor * r.module.getNumberOfChunks();
|
||||
};
|
||||
|
||||
if(preferEntry) {
|
||||
for(const m of modules) {
|
||||
const result = m.reasons.reduce(countOccursInEntry, 0) + initialChunkChunkMap.get(m) + entryCountMap.get(m);
|
||||
occursInInitialChunksMap.set(m, result);
|
||||
}
|
||||
}
|
||||
|
||||
const originalOrder = new Map();
|
||||
let i = 0;
|
||||
for(const m of modules) {
|
||||
const result = m.reasons.reduce(countOccurs, 0) + m.getNumberOfChunks() + entryCountMap.get(m);
|
||||
occursInAllChunksMap.set(m, result);
|
||||
originalOrder.set(m, i++);
|
||||
}
|
||||
|
||||
modules.sort((a, b) => {
|
||||
if(preferEntry) {
|
||||
const aEntryOccurs = occursInInitialChunksMap.get(a);
|
||||
const bEntryOccurs = occursInInitialChunksMap.get(b);
|
||||
if(aEntryOccurs > bEntryOccurs) return -1;
|
||||
if(aEntryOccurs < bEntryOccurs) return 1;
|
||||
}
|
||||
const aOccurs = occursInAllChunksMap.get(a);
|
||||
const bOccurs = occursInAllChunksMap.get(b);
|
||||
if(aOccurs > bOccurs) return -1;
|
||||
if(aOccurs < bOccurs) return 1;
|
||||
const orgA = originalOrder.get(a);
|
||||
const orgB = originalOrder.get(b);
|
||||
return orgB - orgA;
|
||||
});
|
||||
});
|
||||
compilation.hooks.optimizeChunkOrder.tap("OccurrenceOrderPlugin", (chunks) => {
|
||||
const occursInInitialChunksMap = new Map();
|
||||
const originalOrder = new Map();
|
||||
|
||||
let i = 0;
|
||||
for(const c of chunks) {
|
||||
let occurs = 0;
|
||||
for(const chunkGroup of c.groupsIterable) {
|
||||
for(const parent of chunkGroup.parentsIterable) {
|
||||
if(parent.isInitial())
|
||||
occurs++;
|
||||
if (preferEntry) {
|
||||
for (const m of modules) {
|
||||
const result =
|
||||
m.reasons.reduce(countOccursInEntry, 0) +
|
||||
initialChunkChunkMap.get(m) +
|
||||
entryCountMap.get(m);
|
||||
occursInInitialChunksMap.set(m, result);
|
||||
}
|
||||
}
|
||||
occursInInitialChunksMap.set(c, occurs);
|
||||
originalOrder.set(c, i++);
|
||||
}
|
||||
|
||||
chunks.sort((a, b) => {
|
||||
const aEntryOccurs = occursInInitialChunksMap.get(a);
|
||||
const bEntryOccurs = occursInInitialChunksMap.get(b);
|
||||
if(aEntryOccurs > bEntryOccurs) return -1;
|
||||
if(aEntryOccurs < bEntryOccurs) return 1;
|
||||
const aOccurs = a.getNumberOfGroups();
|
||||
const bOccurs = b.getNumberOfGroups();
|
||||
if(aOccurs > bOccurs) return -1;
|
||||
if(aOccurs < bOccurs) return 1;
|
||||
const orgA = originalOrder.get(a);
|
||||
const orgB = originalOrder.get(b);
|
||||
return orgB - orgA;
|
||||
});
|
||||
});
|
||||
const originalOrder = new Map();
|
||||
let i = 0;
|
||||
for (const m of modules) {
|
||||
const result =
|
||||
m.reasons.reduce(countOccurs, 0) +
|
||||
m.getNumberOfChunks() +
|
||||
entryCountMap.get(m);
|
||||
occursInAllChunksMap.set(m, result);
|
||||
originalOrder.set(m, i++);
|
||||
}
|
||||
|
||||
modules.sort((a, b) => {
|
||||
if (preferEntry) {
|
||||
const aEntryOccurs = occursInInitialChunksMap.get(a);
|
||||
const bEntryOccurs = occursInInitialChunksMap.get(b);
|
||||
if (aEntryOccurs > bEntryOccurs) return -1;
|
||||
if (aEntryOccurs < bEntryOccurs) return 1;
|
||||
}
|
||||
const aOccurs = occursInAllChunksMap.get(a);
|
||||
const bOccurs = occursInAllChunksMap.get(b);
|
||||
if (aOccurs > bOccurs) return -1;
|
||||
if (aOccurs < bOccurs) return 1;
|
||||
const orgA = originalOrder.get(a);
|
||||
const orgB = originalOrder.get(b);
|
||||
return orgB - orgA;
|
||||
});
|
||||
}
|
||||
);
|
||||
compilation.hooks.optimizeChunkOrder.tap(
|
||||
"OccurrenceOrderPlugin",
|
||||
chunks => {
|
||||
const occursInInitialChunksMap = new Map();
|
||||
const originalOrder = new Map();
|
||||
|
||||
let i = 0;
|
||||
for (const c of chunks) {
|
||||
let occurs = 0;
|
||||
for (const chunkGroup of c.groupsIterable) {
|
||||
for (const parent of chunkGroup.parentsIterable) {
|
||||
if (parent.isInitial()) occurs++;
|
||||
}
|
||||
}
|
||||
occursInInitialChunksMap.set(c, occurs);
|
||||
originalOrder.set(c, i++);
|
||||
}
|
||||
|
||||
chunks.sort((a, b) => {
|
||||
const aEntryOccurs = occursInInitialChunksMap.get(a);
|
||||
const bEntryOccurs = occursInInitialChunksMap.get(b);
|
||||
if (aEntryOccurs > bEntryOccurs) return -1;
|
||||
if (aEntryOccurs < bEntryOccurs) return 1;
|
||||
const aOccurs = a.getNumberOfGroups();
|
||||
const bOccurs = b.getNumberOfGroups();
|
||||
if (aOccurs > bOccurs) return -1;
|
||||
if (aOccurs < bOccurs) return 1;
|
||||
const orgA = originalOrder.get(a);
|
||||
const orgB = originalOrder.get(b);
|
||||
return orgB - orgA;
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,26 @@
|
|||
|
||||
class RemoveEmptyChunksPlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("RemoveEmptyChunksPlugin", (compilation) => {
|
||||
const handler = (chunks) => {
|
||||
chunks.filter((chunk) => chunk.isEmpty() && !chunk.hasRuntime() && !chunk.hasEntryModule())
|
||||
.forEach((chunk) => {
|
||||
compiler.hooks.compilation.tap("RemoveEmptyChunksPlugin", compilation => {
|
||||
const handler = chunks => {
|
||||
chunks
|
||||
.filter(
|
||||
chunk =>
|
||||
chunk.isEmpty() && !chunk.hasRuntime() && !chunk.hasEntryModule()
|
||||
)
|
||||
.forEach(chunk => {
|
||||
chunk.remove("empty");
|
||||
chunks.splice(chunks.indexOf(chunk), 1);
|
||||
});
|
||||
};
|
||||
compilation.hooks.optimizeChunksBasic.tap("RemoveEmptyChunksPlugin", handler);
|
||||
compilation.hooks.optimizeExtractedChunksBasic.tap("RemoveEmptyChunksPlugin", handler);
|
||||
compilation.hooks.optimizeChunksBasic.tap(
|
||||
"RemoveEmptyChunksPlugin",
|
||||
handler
|
||||
);
|
||||
compilation.hooks.optimizeExtractedChunksBasic.tap(
|
||||
"RemoveEmptyChunksPlugin",
|
||||
handler
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ const getParentChunksWithModule = (currentChunk, module) => {
|
|||
const chunks = [];
|
||||
const stack = new Set(currentChunk.parentsIterable);
|
||||
|
||||
for(const chunk of stack) {
|
||||
if(chunk.containsModule(module)) {
|
||||
for (const chunk of stack) {
|
||||
if (chunk.containsModule(module)) {
|
||||
chunks.push(chunk);
|
||||
} else {
|
||||
for(const parent of chunk.parentsIterable) {
|
||||
for (const parent of chunk.parentsIterable) {
|
||||
stack.add(parent);
|
||||
}
|
||||
}
|
||||
|
@ -26,38 +26,40 @@ const getParentChunksWithModule = (currentChunk, module) => {
|
|||
|
||||
class RemoveParentModulesPlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("RemoveParentModulesPlugin", (compilation) => {
|
||||
compiler.hooks.compilation.tap("RemoveParentModulesPlugin", compilation => {
|
||||
const handler = (chunks, chunkGroups) => {
|
||||
const queue = new Queue();
|
||||
const availableModulesMap = new Map();
|
||||
|
||||
for(const chunkGroup of compilation.entrypoints.values()) {
|
||||
for (const chunkGroup of compilation.entrypoints.values()) {
|
||||
// initialize available modules for chunks without parents
|
||||
availableModulesMap.set(chunkGroup, new Set());
|
||||
for(const child of chunkGroup.childrenIterable)
|
||||
queue.enqueue(child);
|
||||
for (const child of chunkGroup.childrenIterable) queue.enqueue(child);
|
||||
}
|
||||
|
||||
while(queue.length > 0) {
|
||||
while (queue.length > 0) {
|
||||
const chunkGroup = queue.dequeue();
|
||||
let availableModules = availableModulesMap.get(chunkGroup);
|
||||
let changed = false;
|
||||
for(const parent of chunkGroup.parentsIterable) {
|
||||
for (const parent of chunkGroup.parentsIterable) {
|
||||
const availableModulesInParent = availableModulesMap.get(parent);
|
||||
if(availableModulesInParent !== undefined) {
|
||||
if (availableModulesInParent !== undefined) {
|
||||
// If we know the available modules in parent: process these
|
||||
if(availableModules === undefined) {
|
||||
if (availableModules === undefined) {
|
||||
// if we have not own info yet: create new entry
|
||||
availableModules = new Set(availableModulesInParent);
|
||||
for(const chunk of parent.chunks) {
|
||||
for(const m of chunk.modulesIterable)
|
||||
for (const chunk of parent.chunks) {
|
||||
for (const m of chunk.modulesIterable)
|
||||
availableModules.add(m);
|
||||
}
|
||||
availableModulesMap.set(chunkGroup, availableModules);
|
||||
changed = true;
|
||||
} else {
|
||||
for(const m of availableModules) {
|
||||
if(!parent.containsModule(m) && !availableModulesInParent.has(m)) {
|
||||
for (const m of availableModules) {
|
||||
if (
|
||||
!parent.containsModule(m) &&
|
||||
!availableModulesInParent.has(m)
|
||||
) {
|
||||
availableModules.delete(m);
|
||||
changed = true;
|
||||
}
|
||||
|
@ -65,37 +67,47 @@ class RemoveParentModulesPlugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
if(changed) {
|
||||
if (changed) {
|
||||
// if something changed: enqueue our children
|
||||
for(const child of chunkGroup.childrenIterable)
|
||||
for (const child of chunkGroup.childrenIterable)
|
||||
queue.enqueue(child);
|
||||
}
|
||||
}
|
||||
|
||||
// now we have available modules for every chunk
|
||||
for(const chunk of chunks) {
|
||||
const availableModulesSets = Array.from(chunk.groupsIterable, chunkGroup => availableModulesMap.get(chunkGroup));
|
||||
if(availableModulesSets.some(s => s === undefined)) continue; // No info about this chunk group
|
||||
for (const chunk of chunks) {
|
||||
const availableModulesSets = Array.from(
|
||||
chunk.groupsIterable,
|
||||
chunkGroup => availableModulesMap.get(chunkGroup)
|
||||
);
|
||||
if (availableModulesSets.some(s => s === undefined)) continue; // No info about this chunk group
|
||||
const availableModules = intersect(availableModulesSets);
|
||||
const numberOfModules = chunk.getNumberOfModules();
|
||||
const toRemove = new Set();
|
||||
if(numberOfModules < availableModules.size) {
|
||||
for(const m of chunk.modulesIterable)
|
||||
if(availableModules.has(m))
|
||||
toRemove.add(m);
|
||||
if (numberOfModules < availableModules.size) {
|
||||
for (const m of chunk.modulesIterable)
|
||||
if (availableModules.has(m)) toRemove.add(m);
|
||||
} else {
|
||||
for(const m of availableModules)
|
||||
if(chunk.containsModule(m))
|
||||
toRemove.add(m);
|
||||
for (const m of availableModules)
|
||||
if (chunk.containsModule(m)) toRemove.add(m);
|
||||
}
|
||||
for(const module of toRemove) {
|
||||
module.rewriteChunkInReasons(chunk, getParentChunksWithModule(chunk, module));
|
||||
for (const module of toRemove) {
|
||||
module.rewriteChunkInReasons(
|
||||
chunk,
|
||||
getParentChunksWithModule(chunk, module)
|
||||
);
|
||||
chunk.removeModule(module);
|
||||
}
|
||||
}
|
||||
};
|
||||
compilation.hooks.optimizeChunksBasic.tap("RemoveParentModulesPlugin", handler);
|
||||
compilation.hooks.optimizeExtractedChunksBasic.tap("RemoveParentModulesPlugin", handler);
|
||||
compilation.hooks.optimizeChunksBasic.tap(
|
||||
"RemoveParentModulesPlugin",
|
||||
handler
|
||||
);
|
||||
compilation.hooks.optimizeExtractedChunksBasic.tap(
|
||||
"RemoveParentModulesPlugin",
|
||||
handler
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,19 +6,22 @@
|
|||
|
||||
module.exports = class RuntimeChunkPlugin {
|
||||
constructor(options) {
|
||||
this.options = Object.assign({
|
||||
name: entrypoint => `runtime~${entrypoint.name}`
|
||||
}, options);
|
||||
this.options = Object.assign(
|
||||
{
|
||||
name: entrypoint => `runtime~${entrypoint.name}`
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap("RuntimeChunkPlugin", compilation => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap("RuntimeChunkPlugin", () => {
|
||||
for(const entrypoint of compilation.entrypoints.values()) {
|
||||
for (const entrypoint of compilation.entrypoints.values()) {
|
||||
const chunk = entrypoint.getRuntimeChunk();
|
||||
if(chunk.getNumberOfModules() > 0) {
|
||||
if (chunk.getNumberOfModules() > 0) {
|
||||
let name = this.options.name;
|
||||
if(typeof name === "function") {
|
||||
if (typeof name === "function") {
|
||||
name = name(entrypoint);
|
||||
}
|
||||
const newChunk = compilation.addChunk(name);
|
||||
|
|
|
@ -11,13 +11,20 @@ const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportS
|
|||
|
||||
class SideEffectsFlagPlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", (nmf) => {
|
||||
compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", nmf => {
|
||||
nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => {
|
||||
const resolveData = data.resourceResolveData;
|
||||
if(resolveData && resolveData.descriptionFileData && resolveData.relativePath) {
|
||||
if (
|
||||
resolveData &&
|
||||
resolveData.descriptionFileData &&
|
||||
resolveData.relativePath
|
||||
) {
|
||||
const sideEffects = resolveData.descriptionFileData.sideEffects;
|
||||
const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects(resolveData.relativePath, sideEffects);
|
||||
if(!hasSideEffects) {
|
||||
const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects(
|
||||
resolveData.relativePath,
|
||||
sideEffects
|
||||
);
|
||||
if (!hasSideEffects) {
|
||||
module.factoryMeta.sideEffectFree = true;
|
||||
}
|
||||
}
|
||||
|
@ -25,115 +32,124 @@ class SideEffectsFlagPlugin {
|
|||
return module;
|
||||
});
|
||||
nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => {
|
||||
if(data.settings.sideEffects === false)
|
||||
if (data.settings.sideEffects === false)
|
||||
module.factoryMeta.sideEffectFree = true;
|
||||
else if(data.settings.sideEffects === true)
|
||||
else if (data.settings.sideEffects === true)
|
||||
module.factoryMeta.sideEffectFree = false;
|
||||
});
|
||||
});
|
||||
compiler.hooks.compilation.tap("SideEffectsFlagPlugin", (compilation) => {
|
||||
compilation.hooks.optimizeDependencies.tap("SideEffectsFlagPlugin", (modules) => {
|
||||
const reexportMaps = new Map();
|
||||
compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => {
|
||||
compilation.hooks.optimizeDependencies.tap(
|
||||
"SideEffectsFlagPlugin",
|
||||
modules => {
|
||||
const reexportMaps = new Map();
|
||||
|
||||
// Capture reexports of sideEffectFree modules
|
||||
for(const module of modules) {
|
||||
const removeDependencies = [];
|
||||
for(const dep of module.dependencies) {
|
||||
if(dep instanceof HarmonyImportSideEffectDependency) {
|
||||
if(dep.module && dep.module.factoryMeta.sideEffectFree) {
|
||||
removeDependencies.push(dep);
|
||||
}
|
||||
} else if(dep instanceof HarmonyExportImportedSpecifierDependency) {
|
||||
if(module.factoryMeta.sideEffectFree) {
|
||||
const mode = dep.getMode(true);
|
||||
if(mode.type === "safe-reexport") {
|
||||
let map = reexportMaps.get(module);
|
||||
if(!map) {
|
||||
reexportMaps.set(module, map = new Map());
|
||||
}
|
||||
for(const pair of mode.map) {
|
||||
map.set(pair[0], {
|
||||
module: mode.module,
|
||||
exportName: pair[1]
|
||||
});
|
||||
// Capture reexports of sideEffectFree modules
|
||||
for (const module of modules) {
|
||||
const removeDependencies = [];
|
||||
for (const dep of module.dependencies) {
|
||||
if (dep instanceof HarmonyImportSideEffectDependency) {
|
||||
if (dep.module && dep.module.factoryMeta.sideEffectFree) {
|
||||
removeDependencies.push(dep);
|
||||
}
|
||||
} else if (
|
||||
dep instanceof HarmonyExportImportedSpecifierDependency
|
||||
) {
|
||||
if (module.factoryMeta.sideEffectFree) {
|
||||
const mode = dep.getMode(true);
|
||||
if (mode.type === "safe-reexport") {
|
||||
let map = reexportMaps.get(module);
|
||||
if (!map) {
|
||||
reexportMaps.set(module, (map = new Map()));
|
||||
}
|
||||
for (const pair of mode.map) {
|
||||
map.set(pair[0], {
|
||||
module: mode.module,
|
||||
exportName: pair[1]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(const dep of removeDependencies) {
|
||||
module.removeDependency(dep);
|
||||
dep.module.reasons = dep.module.reasons.filter(r => r.dependency !== dep);
|
||||
}
|
||||
}
|
||||
|
||||
// Flatten reexports
|
||||
for(const map of reexportMaps.values()) {
|
||||
for(const pair of map) {
|
||||
let mapping = pair[1];
|
||||
while(mapping) {
|
||||
const innerMap = reexportMaps.get(mapping.module);
|
||||
if(!innerMap) break;
|
||||
const newMapping = innerMap.get(mapping.exportName);
|
||||
if(newMapping) {
|
||||
map.set(pair[0], newMapping);
|
||||
}
|
||||
mapping = newMapping;
|
||||
for (const dep of removeDependencies) {
|
||||
module.removeDependency(dep);
|
||||
dep.module.reasons = dep.module.reasons.filter(
|
||||
r => r.dependency !== dep
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update imports along the reexports from sideEffectFree modules
|
||||
const updates = [];
|
||||
for(const pair of reexportMaps) {
|
||||
const module = pair[0];
|
||||
const map = pair[1];
|
||||
for(const reason of module.reasons) {
|
||||
const dep = reason.dependency;
|
||||
if(dep instanceof HarmonyImportSpecifierDependency) {
|
||||
const mapping = map.get(dep.id);
|
||||
if(mapping) {
|
||||
updates.push({
|
||||
dep,
|
||||
mapping,
|
||||
module,
|
||||
reason
|
||||
});
|
||||
// Flatten reexports
|
||||
for (const map of reexportMaps.values()) {
|
||||
for (const pair of map) {
|
||||
let mapping = pair[1];
|
||||
while (mapping) {
|
||||
const innerMap = reexportMaps.get(mapping.module);
|
||||
if (!innerMap) break;
|
||||
const newMapping = innerMap.get(mapping.exportName);
|
||||
if (newMapping) {
|
||||
map.set(pair[0], newMapping);
|
||||
}
|
||||
mapping = newMapping;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute updates
|
||||
for(const update of updates) {
|
||||
const dep = update.dep;
|
||||
const mapping = update.mapping;
|
||||
const module = update.module;
|
||||
const reason = update.reason;
|
||||
dep.module = mapping.module;
|
||||
dep.id = mapping.exportName;
|
||||
module.removeReason(reason.module, dep);
|
||||
mapping.module.addReason(reason.module, dep);
|
||||
// Update imports along the reexports from sideEffectFree modules
|
||||
const updates = [];
|
||||
for (const pair of reexportMaps) {
|
||||
const module = pair[0];
|
||||
const map = pair[1];
|
||||
for (const reason of module.reasons) {
|
||||
const dep = reason.dependency;
|
||||
if (dep instanceof HarmonyImportSpecifierDependency) {
|
||||
const mapping = map.get(dep.id);
|
||||
if (mapping) {
|
||||
updates.push({
|
||||
dep,
|
||||
mapping,
|
||||
module,
|
||||
reason
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute updates
|
||||
for (const update of updates) {
|
||||
const dep = update.dep;
|
||||
const mapping = update.mapping;
|
||||
const module = update.module;
|
||||
const reason = update.reason;
|
||||
dep.module = mapping.module;
|
||||
dep.id = mapping.exportName;
|
||||
module.removeReason(reason.module, dep);
|
||||
mapping.module.addReason(reason.module, dep);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
static moduleHasSideEffects(moduleName, flagValue) {
|
||||
switch(typeof flagValue) {
|
||||
switch (typeof flagValue) {
|
||||
case "undefined":
|
||||
return true;
|
||||
case "boolean":
|
||||
return flagValue;
|
||||
case "string":
|
||||
if(process.platform === "win32") {
|
||||
if (process.platform === "win32") {
|
||||
flagValue = flagValue.replace(/\\/g, "/");
|
||||
}
|
||||
return mm.isMatch(moduleName, flagValue, {
|
||||
matchBase: true
|
||||
});
|
||||
case "object":
|
||||
return flagValue.some(glob => SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob));
|
||||
return flagValue.some(glob =>
|
||||
SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,19 +9,23 @@ const SortableSet = require("../util/SortableSet");
|
|||
const GraphHelpers = require("../GraphHelpers");
|
||||
const isSubset = require("../util/SetHelpers").isSubset;
|
||||
|
||||
const hashFilename = (name) => {
|
||||
return crypto.createHash("md4").update(name).digest("hex").slice(0, 8);
|
||||
const hashFilename = name => {
|
||||
return crypto
|
||||
.createHash("md4")
|
||||
.update(name)
|
||||
.digest("hex")
|
||||
.slice(0, 8);
|
||||
};
|
||||
|
||||
const sortByIdentifier = (a, b) => {
|
||||
if(a.identifier() > b.identifier()) return 1;
|
||||
if(a.identifier() < b.identifier()) return -1;
|
||||
if (a.identifier() > b.identifier()) return 1;
|
||||
if (a.identifier() < b.identifier()) return -1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
const getRequests = chunk => {
|
||||
let requests = 0;
|
||||
for(const chunkGroup of chunk.groupsIterable) {
|
||||
for (const chunkGroup of chunk.groupsIterable) {
|
||||
requests = Math.max(requests, chunkGroup.chunks.length);
|
||||
}
|
||||
return requests;
|
||||
|
@ -29,14 +33,13 @@ const getRequests = chunk => {
|
|||
|
||||
const getModulesSize = modules => {
|
||||
let sum = 0;
|
||||
for(const m of modules)
|
||||
sum += m.size();
|
||||
for (const m of modules) sum += m.size();
|
||||
return sum;
|
||||
};
|
||||
|
||||
const isOverlap = (a, b) => {
|
||||
for(const item of a.keys()) {
|
||||
if(b.has(item)) return true;
|
||||
for (const item of a.keys()) {
|
||||
if (b.has(item)) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
@ -44,33 +47,34 @@ const isOverlap = (a, b) => {
|
|||
const compareEntries = (a, b) => {
|
||||
// 1. by priority
|
||||
const diffPriority = a.cacheGroup.priority - b.cacheGroup.priority;
|
||||
if(diffPriority) return diffPriority;
|
||||
if (diffPriority) return diffPriority;
|
||||
// 2. by number of chunks
|
||||
const diffCount = a.chunks.size - b.chunks.size;
|
||||
if(diffCount) return diffCount;
|
||||
if (diffCount) return diffCount;
|
||||
// 3. by size reduction
|
||||
const aSizeReduce = a.size * (a.chunks.size - 1);
|
||||
const bSizeReduce = b.size * (b.chunks.size - 1);
|
||||
const diffSizeReduce = aSizeReduce - bSizeReduce;
|
||||
if(diffSizeReduce) return diffSizeReduce;
|
||||
if (diffSizeReduce) return diffSizeReduce;
|
||||
// 4. by number of modules (to be able to compare by identifier)
|
||||
const modulesA = a.modules;
|
||||
const modulesB = b.modules;
|
||||
const diff = modulesA.size - modulesB.size;
|
||||
if(diff) return diff;
|
||||
if (diff) return diff;
|
||||
// 5. by module identifiers
|
||||
modulesA.sort();
|
||||
modulesB.sort();
|
||||
const aI = modulesA[Symbol.iterator]();
|
||||
const bI = modulesB[Symbol.iterator]();
|
||||
while(true) { // eslint-disable-line
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const aItem = aI.next();
|
||||
const bItem = bI.next();
|
||||
if(aItem.done) return 0;
|
||||
if (aItem.done) return 0;
|
||||
const aModuleIdentifier = aItem.value.identifier();
|
||||
const bModuleIdentifier = bItem.value.identifier();
|
||||
if(aModuleIdentifier > bModuleIdentifier) return -1;
|
||||
if(aModuleIdentifier < bModuleIdentifier) return 1;
|
||||
if (aModuleIdentifier > bModuleIdentifier) return -1;
|
||||
if (aModuleIdentifier < bModuleIdentifier) return 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -87,69 +91,74 @@ module.exports = class SplitChunksPlugin {
|
|||
maxAsyncRequests: options.maxAsyncRequests || 1,
|
||||
maxInitialRequests: options.maxInitialRequests || 1,
|
||||
getName: SplitChunksPlugin.normalizeName(options.name) || (() => {}),
|
||||
getCacheGroups: SplitChunksPlugin.normalizeCacheGroups(options.cacheGroups),
|
||||
getCacheGroups: SplitChunksPlugin.normalizeCacheGroups(
|
||||
options.cacheGroups
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
static normalizeName(option) {
|
||||
if(option === true) {
|
||||
if (option === true) {
|
||||
const fn = (module, chunks, cacheGroup) => {
|
||||
const names = chunks.map(c => c.name);
|
||||
if(!names.every(Boolean)) return;
|
||||
if (!names.every(Boolean)) return;
|
||||
names.sort();
|
||||
let name = (cacheGroup && cacheGroup !== "default" ? cacheGroup + "~" : "") + names.join("~");
|
||||
let name =
|
||||
(cacheGroup && cacheGroup !== "default" ? cacheGroup + "~" : "") +
|
||||
names.join("~");
|
||||
// Filenames and paths can't be too long otherwise an
|
||||
// ENAMETOOLONG error is raised. If the generated name if too
|
||||
// long, it is truncated and a hash is appended. The limit has
|
||||
// been set to 100 to prevent `[name].[chunkhash].[ext]` from
|
||||
// generating a 256+ character string.
|
||||
if(name.length > 100) {
|
||||
if (name.length > 100) {
|
||||
name = name.slice(0, 100) + "~" + hashFilename(name);
|
||||
}
|
||||
return name;
|
||||
};
|
||||
return fn;
|
||||
}
|
||||
if(typeof option === "string") {
|
||||
if (typeof option === "string") {
|
||||
const fn = () => {
|
||||
return option;
|
||||
};
|
||||
return fn;
|
||||
}
|
||||
if(typeof option === "function")
|
||||
return option;
|
||||
if (typeof option === "function") return option;
|
||||
}
|
||||
|
||||
static normalizeCacheGroups(cacheGroups) {
|
||||
if(typeof cacheGroups === "function") {
|
||||
if (typeof cacheGroups === "function") {
|
||||
return cacheGroups;
|
||||
}
|
||||
if(cacheGroups && typeof cacheGroups === "object") {
|
||||
if (cacheGroups && typeof cacheGroups === "object") {
|
||||
const fn = (module, chunks) => {
|
||||
let results;
|
||||
for(const key of Object.keys(cacheGroups)) {
|
||||
for (const key of Object.keys(cacheGroups)) {
|
||||
let option = cacheGroups[key];
|
||||
if(option === false)
|
||||
continue;
|
||||
if(option instanceof RegExp || typeof option === "string") {
|
||||
if (option === false) continue;
|
||||
if (option instanceof RegExp || typeof option === "string") {
|
||||
option = {
|
||||
test: option
|
||||
};
|
||||
}
|
||||
if(typeof option === "function") {
|
||||
if (typeof option === "function") {
|
||||
let result = option(module);
|
||||
if(result) {
|
||||
if(results === undefined) results = [];
|
||||
for(const r of (Array.isArray(result) ? result : [result])) {
|
||||
const result = Object.assign({
|
||||
key,
|
||||
}, r);
|
||||
if(result.name) result.getName = () => result.name;
|
||||
if (result) {
|
||||
if (results === undefined) results = [];
|
||||
for (const r of Array.isArray(result) ? result : [result]) {
|
||||
const result = Object.assign(
|
||||
{
|
||||
key
|
||||
},
|
||||
r
|
||||
);
|
||||
if (result.name) result.getName = () => result.name;
|
||||
results.push(result);
|
||||
}
|
||||
}
|
||||
} else if(SplitChunksPlugin.checkTest(option.test, module, chunks)) {
|
||||
if(results === undefined) results = [];
|
||||
} else if (SplitChunksPlugin.checkTest(option.test, module, chunks)) {
|
||||
if (results === undefined) results = [];
|
||||
results.push({
|
||||
key: key,
|
||||
priority: option.priority,
|
||||
|
@ -173,23 +182,19 @@ module.exports = class SplitChunksPlugin {
|
|||
}
|
||||
|
||||
static checkTest(test, module, chunks) {
|
||||
if(test === undefined)
|
||||
return true;
|
||||
if(typeof test === "function")
|
||||
return test(module, chunks);
|
||||
if(typeof test === "boolean")
|
||||
return test;
|
||||
const names = chunks.map(c => c.name).concat(module.nameForCondition ? [module.nameForCondition()] : []).filter(Boolean);
|
||||
if(typeof test === "string") {
|
||||
for(const name of names)
|
||||
if(name.startsWith(test))
|
||||
return true;
|
||||
if (test === undefined) return true;
|
||||
if (typeof test === "function") return test(module, chunks);
|
||||
if (typeof test === "boolean") return test;
|
||||
const names = chunks
|
||||
.map(c => c.name)
|
||||
.concat(module.nameForCondition ? [module.nameForCondition()] : [])
|
||||
.filter(Boolean);
|
||||
if (typeof test === "string") {
|
||||
for (const name of names) if (name.startsWith(test)) return true;
|
||||
return false;
|
||||
}
|
||||
if(test instanceof RegExp) {
|
||||
for(const name of names)
|
||||
if(test.test(name))
|
||||
return true;
|
||||
if (test instanceof RegExp) {
|
||||
for (const name of names) if (test.test(name)) return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
@ -201,213 +206,269 @@ module.exports = class SplitChunksPlugin {
|
|||
compilation.hooks.unseal.tap("SplitChunksPlugin", () => {
|
||||
alreadyOptimized = false;
|
||||
});
|
||||
compilation.hooks.optimizeChunksAdvanced.tap("SplitChunksPlugin", chunks => {
|
||||
if(alreadyOptimized) return;
|
||||
alreadyOptimized = true;
|
||||
// Give each selected chunk an index (to create strings from chunks)
|
||||
const indexMap = new Map();
|
||||
let index = 1;
|
||||
for(const chunk of chunks) {
|
||||
indexMap.set(chunk, index++);
|
||||
}
|
||||
const getKey = chunks => {
|
||||
return Array.from(chunks, c => indexMap.get(c)).sort().join();
|
||||
};
|
||||
// Create a list of possible combinations
|
||||
const chunkSetsInGraph = new Map(); // Map<string, Set<Chunk>>
|
||||
for(const module of compilation.modules) {
|
||||
const chunkIndices = getKey(module.chunksIterable);
|
||||
chunkSetsInGraph.set(chunkIndices, new Set(module.chunksIterable));
|
||||
}
|
||||
const combinations = new Map(); // Map<string, Set<Chunk>[]>
|
||||
for(const [key, chunksSet] of chunkSetsInGraph) {
|
||||
var array = [];
|
||||
for(const set of chunkSetsInGraph.values()) {
|
||||
if(isSubset(chunksSet, set)) {
|
||||
array.push(set);
|
||||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"SplitChunksPlugin",
|
||||
chunks => {
|
||||
if (alreadyOptimized) return;
|
||||
alreadyOptimized = true;
|
||||
// Give each selected chunk an index (to create strings from chunks)
|
||||
const indexMap = new Map();
|
||||
let index = 1;
|
||||
for (const chunk of chunks) {
|
||||
indexMap.set(chunk, index++);
|
||||
}
|
||||
const getKey = chunks => {
|
||||
return Array.from(chunks, c => indexMap.get(c))
|
||||
.sort()
|
||||
.join();
|
||||
};
|
||||
// Create a list of possible combinations
|
||||
const chunkSetsInGraph = new Map(); // Map<string, Set<Chunk>>
|
||||
for (const module of compilation.modules) {
|
||||
const chunkIndices = getKey(module.chunksIterable);
|
||||
chunkSetsInGraph.set(chunkIndices, new Set(module.chunksIterable));
|
||||
}
|
||||
const combinations = new Map(); // Map<string, Set<Chunk>[]>
|
||||
for (const [key, chunksSet] of chunkSetsInGraph) {
|
||||
var array = [];
|
||||
for (const set of chunkSetsInGraph.values()) {
|
||||
if (isSubset(chunksSet, set)) {
|
||||
array.push(set);
|
||||
}
|
||||
}
|
||||
combinations.set(key, array);
|
||||
}
|
||||
// Map a list of chunks to a list of modules
|
||||
// For the key the chunk "index" is used, the value is a SortableSet of modules
|
||||
const chunksInfoMap = new Map();
|
||||
// Walk through all modules
|
||||
for (const module of compilation.modules) {
|
||||
// Get array of chunks
|
||||
const chunks = module.getChunks();
|
||||
// Get cache group
|
||||
let cacheGroups = this.options.getCacheGroups(module, chunks);
|
||||
if (!Array.isArray(cacheGroups)) continue;
|
||||
for (const cacheGroupSource of cacheGroups) {
|
||||
const cacheGroup = {
|
||||
key: cacheGroupSource.key,
|
||||
priority: cacheGroupSource.priority || 0,
|
||||
chunks: cacheGroupSource.chunks || this.options.chunks,
|
||||
minSize:
|
||||
cacheGroupSource.minSize !== undefined
|
||||
? cacheGroupSource.minSize
|
||||
: cacheGroupSource.enforce ? 0 : this.options.minSize,
|
||||
minChunks:
|
||||
cacheGroupSource.minChunks !== undefined
|
||||
? cacheGroupSource.minChunks
|
||||
: cacheGroupSource.enforce ? 1 : this.options.minChunks,
|
||||
maxAsyncRequests:
|
||||
cacheGroupSource.maxAsyncRequests !== undefined
|
||||
? cacheGroupSource.maxAsyncRequests
|
||||
: cacheGroupSource.enforce
|
||||
? Infinity
|
||||
: this.options.maxAsyncRequests,
|
||||
maxInitialRequests:
|
||||
cacheGroupSource.maxInitialRequests !== undefined
|
||||
? cacheGroupSource.maxInitialRequests
|
||||
: cacheGroupSource.enforce
|
||||
? Infinity
|
||||
: this.options.maxInitialRequests,
|
||||
getName:
|
||||
cacheGroupSource.getName !== undefined
|
||||
? cacheGroupSource.getName
|
||||
: this.options.getName,
|
||||
reuseExistingChunk: cacheGroupSource.reuseExistingChunk
|
||||
};
|
||||
// For all combination of chunk selection
|
||||
for (const chunkCombination of combinations.get(getKey(chunks))) {
|
||||
// Get indices of chunks in which this module occurs
|
||||
const chunkIndices = Array.from(chunkCombination, chunk =>
|
||||
indexMap.get(chunk)
|
||||
);
|
||||
// Break if minimum number of chunks is not reached
|
||||
if (chunkIndices.length < cacheGroup.minChunks) continue;
|
||||
// Select chunks by configuration
|
||||
const selectedChunks =
|
||||
cacheGroup.chunks === "initial"
|
||||
? Array.from(chunkCombination).filter(chunk =>
|
||||
chunk.canBeInitial()
|
||||
)
|
||||
: cacheGroup.chunks === "async"
|
||||
? Array.from(chunkCombination).filter(
|
||||
chunk => !chunk.canBeInitial()
|
||||
)
|
||||
: Array.from(chunkCombination);
|
||||
// Determine name for split chunk
|
||||
const name = cacheGroup.getName(
|
||||
module,
|
||||
selectedChunks,
|
||||
cacheGroup.key
|
||||
);
|
||||
// Create key for maps
|
||||
// When it has a name we use the name as key
|
||||
// Elsewise we create the key from chunks and cache group key
|
||||
// This automatically merges equal names
|
||||
const chunksKey = getKey(selectedChunks);
|
||||
const key =
|
||||
(name && `name:${name}`) ||
|
||||
`chunks:${chunksKey} key:${cacheGroup.key}`;
|
||||
// Add module to maps
|
||||
let info = chunksInfoMap.get(key);
|
||||
if (info === undefined) {
|
||||
chunksInfoMap.set(
|
||||
key,
|
||||
(info = {
|
||||
modules: new SortableSet(undefined, sortByIdentifier),
|
||||
cacheGroup,
|
||||
name,
|
||||
chunks: new Map(),
|
||||
reusedableChunks: new Set(),
|
||||
chunksKeys: new Set()
|
||||
})
|
||||
);
|
||||
}
|
||||
info.modules.add(module);
|
||||
if (!info.chunksKeys.has(chunksKey)) {
|
||||
info.chunksKeys.add(chunksKey);
|
||||
for (const chunk of selectedChunks) {
|
||||
info.chunks.set(chunk, chunk.getNumberOfModules());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
combinations.set(key, array);
|
||||
}
|
||||
// Map a list of chunks to a list of modules
|
||||
// For the key the chunk "index" is used, the value is a SortableSet of modules
|
||||
const chunksInfoMap = new Map();
|
||||
// Walk through all modules
|
||||
for(const module of compilation.modules) {
|
||||
// Get array of chunks
|
||||
const chunks = module.getChunks();
|
||||
// Get cache group
|
||||
let cacheGroups = this.options.getCacheGroups(module, chunks);
|
||||
if(!Array.isArray(cacheGroups)) continue;
|
||||
for(const cacheGroupSource of cacheGroups) {
|
||||
const cacheGroup = {
|
||||
key: cacheGroupSource.key,
|
||||
priority: cacheGroupSource.priority || 0,
|
||||
chunks: cacheGroupSource.chunks || this.options.chunks,
|
||||
minSize: cacheGroupSource.minSize !== undefined ? cacheGroupSource.minSize : cacheGroupSource.enforce ? 0 : this.options.minSize,
|
||||
minChunks: cacheGroupSource.minChunks !== undefined ? cacheGroupSource.minChunks : cacheGroupSource.enforce ? 1 : this.options.minChunks,
|
||||
maxAsyncRequests: cacheGroupSource.maxAsyncRequests !== undefined ? cacheGroupSource.maxAsyncRequests : cacheGroupSource.enforce ? Infinity : this.options.maxAsyncRequests,
|
||||
maxInitialRequests: cacheGroupSource.maxInitialRequests !== undefined ? cacheGroupSource.maxInitialRequests : cacheGroupSource.enforce ? Infinity : this.options.maxInitialRequests,
|
||||
getName: cacheGroupSource.getName !== undefined ? cacheGroupSource.getName : this.options.getName,
|
||||
reuseExistingChunk: cacheGroupSource.reuseExistingChunk
|
||||
};
|
||||
// For all combination of chunk selection
|
||||
for(const chunkCombination of combinations.get(getKey(chunks))) {
|
||||
// Get indices of chunks in which this module occurs
|
||||
const chunkIndices = Array.from(chunkCombination, chunk => indexMap.get(chunk));
|
||||
// Break if minimum number of chunks is not reached
|
||||
if(chunkIndices.length < cacheGroup.minChunks)
|
||||
for (const [key, info] of chunksInfoMap) {
|
||||
// Get size of module lists
|
||||
info.size = getModulesSize(info.modules);
|
||||
if (info.size < info.cacheGroup.minSize) {
|
||||
chunksInfoMap.delete(key);
|
||||
}
|
||||
}
|
||||
let changed = false;
|
||||
while (chunksInfoMap.size > 0) {
|
||||
// Find best matching entry
|
||||
let bestEntryKey;
|
||||
let bestEntry;
|
||||
for (const pair of chunksInfoMap) {
|
||||
const key = pair[0];
|
||||
const info = pair[1];
|
||||
if (bestEntry === undefined) {
|
||||
bestEntry = info;
|
||||
bestEntryKey = key;
|
||||
} else if (compareEntries(bestEntry, info) < 0) {
|
||||
bestEntry = info;
|
||||
bestEntryKey = key;
|
||||
}
|
||||
}
|
||||
|
||||
const item = bestEntry;
|
||||
chunksInfoMap.delete(bestEntryKey);
|
||||
|
||||
let chunkName = item.name;
|
||||
// Variable for the new chunk (lazy created)
|
||||
let newChunk;
|
||||
// When no chunk name, check if we can reuse a chunk instead of creating a new one
|
||||
let isReused = false;
|
||||
if (item.cacheGroup.reuseExistingChunk) {
|
||||
for (const pair of item.chunks) {
|
||||
if (pair[1] === item.modules.size) {
|
||||
const chunk = pair[0];
|
||||
if (chunk.hasEntryModule()) continue;
|
||||
if (!newChunk || !newChunk.name) newChunk = chunk;
|
||||
else if (
|
||||
chunk.name &&
|
||||
chunk.name.length < newChunk.name.length
|
||||
)
|
||||
newChunk = chunk;
|
||||
else if (
|
||||
chunk.name &&
|
||||
chunk.name.length === newChunk.name.length &&
|
||||
chunk.name < newChunk.name
|
||||
)
|
||||
newChunk = chunk;
|
||||
chunkName = undefined;
|
||||
isReused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Walk through all chunks
|
||||
for (const chunk of item.chunks.keys()) {
|
||||
// skip if we address ourself
|
||||
if (chunk.name === chunkName || chunk === newChunk) continue;
|
||||
// respect max requests when not enforced
|
||||
const maxRequests = chunk.isOnlyInitial()
|
||||
? item.cacheGroup.maxInitialRequests
|
||||
: chunk.canBeInitial()
|
||||
? Math.min(
|
||||
item.cacheGroup.maxInitialRequests,
|
||||
item.cacheGroup.maxAsyncRequests
|
||||
)
|
||||
: item.cacheGroup.maxAsyncRequests;
|
||||
if (isFinite(maxRequests) && getRequests(chunk) >= maxRequests)
|
||||
continue;
|
||||
// Select chunks by configuration
|
||||
const selectedChunks = cacheGroup.chunks === "initial" ? Array.from(chunkCombination).filter(chunk => chunk.canBeInitial()) :
|
||||
cacheGroup.chunks === "async" ? Array.from(chunkCombination).filter(chunk => !chunk.canBeInitial()) :
|
||||
Array.from(chunkCombination);
|
||||
// Determine name for split chunk
|
||||
const name = cacheGroup.getName(module, selectedChunks, cacheGroup.key);
|
||||
// Create key for maps
|
||||
// When it has a name we use the name as key
|
||||
// Elsewise we create the key from chunks and cache group key
|
||||
// This automatically merges equal names
|
||||
const chunksKey = getKey(selectedChunks);
|
||||
const key = name && `name:${name}` ||
|
||||
`chunks:${chunksKey} key:${cacheGroup.key}`;
|
||||
// Add module to maps
|
||||
let info = chunksInfoMap.get(key);
|
||||
if(info === undefined) {
|
||||
chunksInfoMap.set(key, info = {
|
||||
modules: new SortableSet(undefined, sortByIdentifier),
|
||||
cacheGroup,
|
||||
name,
|
||||
chunks: new Map(),
|
||||
reusedableChunks: new Set(),
|
||||
chunksKeys: new Set()
|
||||
});
|
||||
if (newChunk === undefined) {
|
||||
// Create the new chunk
|
||||
newChunk = compilation.addChunk(chunkName);
|
||||
}
|
||||
info.modules.add(module);
|
||||
if(!info.chunksKeys.has(chunksKey)) {
|
||||
info.chunksKeys.add(chunksKey);
|
||||
for(const chunk of selectedChunks) {
|
||||
info.chunks.set(chunk, chunk.getNumberOfModules());
|
||||
// Add graph connections for splitted chunk
|
||||
chunk.split(newChunk);
|
||||
// Remove all selected modules from the chunk
|
||||
for (const module of item.modules) {
|
||||
chunk.removeModule(module);
|
||||
module.rewriteChunkInReasons(chunk, [newChunk]);
|
||||
}
|
||||
}
|
||||
// If we successfully created a new chunk or reused one
|
||||
if (newChunk) {
|
||||
// Add a note to the chunk
|
||||
newChunk.chunkReason = isReused
|
||||
? "reused as split chunk"
|
||||
: "split chunk";
|
||||
if (item.cacheGroup.key) {
|
||||
newChunk.chunkReason += ` (cache group: ${
|
||||
item.cacheGroup.key
|
||||
})`;
|
||||
}
|
||||
if (chunkName) {
|
||||
newChunk.chunkReason += ` (name: ${chunkName})`;
|
||||
// If the choosen name is already an entry point we remove the entry point
|
||||
const entrypoint = compilation.entrypoints.get(chunkName);
|
||||
if (entrypoint) {
|
||||
compilation.entrypoints.delete(chunkName);
|
||||
entrypoint.remove();
|
||||
newChunk.entryModule = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(const [key, info] of chunksInfoMap) {
|
||||
// Get size of module lists
|
||||
info.size = getModulesSize(info.modules);
|
||||
if(info.size < info.cacheGroup.minSize) {
|
||||
chunksInfoMap.delete(key);
|
||||
}
|
||||
}
|
||||
let changed = false;
|
||||
while(chunksInfoMap.size > 0) {
|
||||
// Find best matching entry
|
||||
let bestEntryKey;
|
||||
let bestEntry;
|
||||
for(const pair of chunksInfoMap) {
|
||||
const key = pair[0];
|
||||
const info = pair[1];
|
||||
if(bestEntry === undefined) {
|
||||
bestEntry = info;
|
||||
bestEntryKey = key;
|
||||
} else if(compareEntries(bestEntry, info) < 0) {
|
||||
bestEntry = info;
|
||||
bestEntryKey = key;
|
||||
}
|
||||
}
|
||||
|
||||
const item = bestEntry;
|
||||
chunksInfoMap.delete(bestEntryKey);
|
||||
|
||||
let chunkName = item.name;
|
||||
// Variable for the new chunk (lazy created)
|
||||
let newChunk;
|
||||
// When no chunk name, check if we can reuse a chunk instead of creating a new one
|
||||
let isReused = false;
|
||||
if(item.cacheGroup.reuseExistingChunk) {
|
||||
for(const pair of item.chunks) {
|
||||
if(pair[1] === item.modules.size) {
|
||||
const chunk = pair[0];
|
||||
if(chunk.hasEntryModule()) continue;
|
||||
if(!newChunk || !newChunk.name)
|
||||
newChunk = chunk;
|
||||
else if(chunk.name && chunk.name.length < newChunk.name.length)
|
||||
newChunk = chunk;
|
||||
else if(chunk.name && chunk.name.length === newChunk.name.length && chunk.name < newChunk.name)
|
||||
newChunk = chunk;
|
||||
chunkName = undefined;
|
||||
isReused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Walk through all chunks
|
||||
for(const chunk of item.chunks.keys()) {
|
||||
// skip if we address ourself
|
||||
if(chunk.name === chunkName || chunk === newChunk) continue;
|
||||
// respect max requests when not enforced
|
||||
const maxRequests = chunk.isOnlyInitial() ? item.cacheGroup.maxInitialRequests :
|
||||
chunk.canBeInitial() ? Math.min(item.cacheGroup.maxInitialRequests, item.cacheGroup.maxAsyncRequests) :
|
||||
item.cacheGroup.maxAsyncRequests;
|
||||
if(isFinite(maxRequests) && getRequests(chunk) >= maxRequests) continue;
|
||||
if(newChunk === undefined) {
|
||||
// Create the new chunk
|
||||
newChunk = compilation.addChunk(chunkName);
|
||||
}
|
||||
// Add graph connections for splitted chunk
|
||||
chunk.split(newChunk);
|
||||
// Remove all selected modules from the chunk
|
||||
for(const module of item.modules) {
|
||||
chunk.removeModule(module);
|
||||
module.rewriteChunkInReasons(chunk, [newChunk]);
|
||||
}
|
||||
}
|
||||
// If we successfully created a new chunk or reused one
|
||||
if(newChunk) {
|
||||
// Add a note to the chunk
|
||||
newChunk.chunkReason = isReused ? "reused as split chunk" : "split chunk";
|
||||
if(item.cacheGroup.key) {
|
||||
newChunk.chunkReason += ` (cache group: ${item.cacheGroup.key})`;
|
||||
}
|
||||
if(chunkName) {
|
||||
newChunk.chunkReason += ` (name: ${chunkName})`;
|
||||
// If the choosen name is already an entry point we remove the entry point
|
||||
const entrypoint = compilation.entrypoints.get(chunkName);
|
||||
if(entrypoint) {
|
||||
compilation.entrypoints.delete(chunkName);
|
||||
entrypoint.remove();
|
||||
newChunk.entryModule = undefined;
|
||||
}
|
||||
}
|
||||
if(!isReused) {
|
||||
// Add all modules to the new chunk
|
||||
for(const module of item.modules) {
|
||||
GraphHelpers.connectChunkAndModule(newChunk, module);
|
||||
}
|
||||
}
|
||||
// remove all modules from other entries and update size
|
||||
for(const [key, info] of chunksInfoMap) {
|
||||
if(isOverlap(info.chunks, item.chunks)) {
|
||||
const oldSize = info.modules.size;
|
||||
for(const module of item.modules) {
|
||||
info.modules.delete(module);
|
||||
if (!isReused) {
|
||||
// Add all modules to the new chunk
|
||||
for (const module of item.modules) {
|
||||
GraphHelpers.connectChunkAndModule(newChunk, module);
|
||||
}
|
||||
if(info.modules.size === 0) {
|
||||
chunksInfoMap.delete(key);
|
||||
continue;
|
||||
}
|
||||
if(info.modules.size !== oldSize) {
|
||||
info.size = getModulesSize(info.modules);
|
||||
if(info.size < info.cacheGroup.minSize)
|
||||
}
|
||||
// remove all modules from other entries and update size
|
||||
for (const [key, info] of chunksInfoMap) {
|
||||
if (isOverlap(info.chunks, item.chunks)) {
|
||||
const oldSize = info.modules.size;
|
||||
for (const module of item.modules) {
|
||||
info.modules.delete(module);
|
||||
}
|
||||
if (info.modules.size === 0) {
|
||||
chunksInfoMap.delete(key);
|
||||
continue;
|
||||
}
|
||||
if (info.modules.size !== oldSize) {
|
||||
info.size = getModulesSize(info.modules);
|
||||
if (info.size < info.cacheGroup.minSize)
|
||||
chunksInfoMap.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (changed) return true;
|
||||
}
|
||||
if(changed) return true;
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,8 +13,15 @@ module.exports = class AssetsOverSizeLimitWarning extends WebpackError {
|
|||
|
||||
this.name = "AssetsOverSizeLimitWarning";
|
||||
this.assets = assetsOverSizeLimit;
|
||||
const assetLists = this.assets.map(asset => `\n ${asset.name} (${SizeFormatHelpers.formatSize(asset.size)})`).join("");
|
||||
this.message = `asset size limit: The following asset(s) exceed the recommended size limit (${SizeFormatHelpers.formatSize(assetLimit)}).
|
||||
const assetLists = this.assets
|
||||
.map(
|
||||
asset =>
|
||||
`\n ${asset.name} (${SizeFormatHelpers.formatSize(asset.size)})`
|
||||
)
|
||||
.join("");
|
||||
this.message = `asset size limit: The following asset(s) exceed the recommended size limit (${SizeFormatHelpers.formatSize(
|
||||
assetLimit
|
||||
)}).
|
||||
This can impact web performance.
|
||||
Assets: ${assetLists}`;
|
||||
|
||||
|
|
|
@ -13,14 +13,17 @@ module.exports = class EntrypointsOverSizeLimitWarning extends WebpackError {
|
|||
|
||||
this.name = "EntrypointsOverSizeLimitWarning";
|
||||
this.entrypoints = entrypoints;
|
||||
const entrypointList = this.entrypoints.map(entrypoint => `\n ${
|
||||
entrypoint.name
|
||||
} (${
|
||||
SizeFormatHelpers.formatSize(entrypoint.size)
|
||||
})\n${
|
||||
entrypoint.files.map(asset => ` ${asset}`).join("\n")
|
||||
}`).join("");
|
||||
this.message = `entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (${SizeFormatHelpers.formatSize(entrypointLimit)}). This can impact web performance.
|
||||
const entrypointList = this.entrypoints
|
||||
.map(
|
||||
entrypoint =>
|
||||
`\n ${entrypoint.name} (${SizeFormatHelpers.formatSize(
|
||||
entrypoint.size
|
||||
)})\n${entrypoint.files.map(asset => ` ${asset}`).join("\n")}`
|
||||
)
|
||||
.join("");
|
||||
this.message = `entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (${SizeFormatHelpers.formatSize(
|
||||
entrypointLimit
|
||||
)}). This can impact web performance.
|
||||
Entrypoints:${entrypointList}\n`;
|
||||
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
|
|
|
@ -11,7 +11,8 @@ module.exports = class NoAsyncChunksWarning extends WebpackError {
|
|||
super();
|
||||
|
||||
this.name = "NoAsyncChunksWarning";
|
||||
this.message = "webpack performance recommendations: \n" +
|
||||
this.message =
|
||||
"webpack performance recommendations: \n" +
|
||||
"You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.\n" +
|
||||
"For more info visit https://webpack.js.org/guides/code-splitting/";
|
||||
|
||||
|
|
|
@ -18,15 +18,14 @@ module.exports = class SizeLimitsPlugin {
|
|||
const entrypointSizeLimit = this.maxEntrypointSize;
|
||||
const assetSizeLimit = this.maxAssetSize;
|
||||
const hints = this.hints;
|
||||
const assetFilter = this.assetFilter || (asset => !(asset.endsWith(".map")));
|
||||
const assetFilter = this.assetFilter || (asset => !asset.endsWith(".map"));
|
||||
|
||||
compiler.hooks.afterEmit.tap("SizeLimitsPlugin", (compilation) => {
|
||||
compiler.hooks.afterEmit.tap("SizeLimitsPlugin", compilation => {
|
||||
const warnings = [];
|
||||
|
||||
const getEntrypointSize = entrypoint =>
|
||||
entrypoint.getFiles()
|
||||
.reduce((currentSize, file) => {
|
||||
if(assetFilter(file) && compilation.assets[file]) {
|
||||
entrypoint.getFiles().reduce((currentSize, file) => {
|
||||
if (assetFilter(file) && compilation.assets[file]) {
|
||||
return currentSize + compilation.assets[file].size();
|
||||
}
|
||||
|
||||
|
@ -34,29 +33,29 @@ module.exports = class SizeLimitsPlugin {
|
|||
}, 0);
|
||||
|
||||
const assetsOverSizeLimit = [];
|
||||
for(const assetName of Object.keys(compilation.assets)) {
|
||||
if(!assetFilter(assetName)) {
|
||||
for (const assetName of Object.keys(compilation.assets)) {
|
||||
if (!assetFilter(assetName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const asset = compilation.assets[assetName];
|
||||
const size = asset.size();
|
||||
if(size > assetSizeLimit) {
|
||||
if (size > assetSizeLimit) {
|
||||
assetsOverSizeLimit.push({
|
||||
name: assetName,
|
||||
size: size,
|
||||
size: size
|
||||
});
|
||||
asset.isOverSizeLimit = true;
|
||||
}
|
||||
}
|
||||
|
||||
const entrypointsOverLimit = [];
|
||||
for(const pair of compilation.entrypoints) {
|
||||
for (const pair of compilation.entrypoints) {
|
||||
const name = pair[0];
|
||||
const entry = pair[1];
|
||||
const size = getEntrypointSize(entry, compilation);
|
||||
|
||||
if(size > entrypointSizeLimit) {
|
||||
if (size > entrypointSizeLimit) {
|
||||
entrypointsOverLimit.push({
|
||||
name: name,
|
||||
size: size,
|
||||
|
@ -66,32 +65,35 @@ module.exports = class SizeLimitsPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
if(hints) {
|
||||
if (hints) {
|
||||
// 1. Individual Chunk: Size < 250kb
|
||||
// 2. Collective Initial Chunks [entrypoint] (Each Set?): Size < 250kb
|
||||
// 3. No Async Chunks
|
||||
// if !1, then 2, if !2 return
|
||||
if(assetsOverSizeLimit.length > 0) {
|
||||
if (assetsOverSizeLimit.length > 0) {
|
||||
warnings.push(
|
||||
new AssetsOverSizeLimitWarning(
|
||||
assetsOverSizeLimit,
|
||||
assetSizeLimit));
|
||||
new AssetsOverSizeLimitWarning(assetsOverSizeLimit, assetSizeLimit)
|
||||
);
|
||||
}
|
||||
if(entrypointsOverLimit.length > 0) {
|
||||
if (entrypointsOverLimit.length > 0) {
|
||||
warnings.push(
|
||||
new EntrypointsOverSizeLimitWarning(
|
||||
entrypointsOverLimit,
|
||||
entrypointSizeLimit));
|
||||
entrypointSizeLimit
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if(warnings.length > 0) {
|
||||
const hasAsyncChunks = compilation.chunks.filter(chunk => !chunk.canBeInitial()).length > 0;
|
||||
if (warnings.length > 0) {
|
||||
const hasAsyncChunks =
|
||||
compilation.chunks.filter(chunk => !chunk.canBeInitial()).length >
|
||||
0;
|
||||
|
||||
if(!hasAsyncChunks) {
|
||||
if (!hasAsyncChunks) {
|
||||
warnings.push(new NoAsyncChunksWarning());
|
||||
}
|
||||
|
||||
if(hints === "error") {
|
||||
if (hints === "error") {
|
||||
compilation.errors.push(...warnings);
|
||||
} else {
|
||||
compilation.warnings.push(...warnings);
|
||||
|
|
|
@ -16,7 +16,7 @@ module.exports = class Queue {
|
|||
|
||||
dequeue() {
|
||||
const result = this.iterator.next();
|
||||
if(result.done) return undefined;
|
||||
if (result.done) return undefined;
|
||||
this.set.delete(result.value);
|
||||
return result.value;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ class Semaphore {
|
|||
}
|
||||
|
||||
acquire(callback) {
|
||||
if(this.available > 0) {
|
||||
if (this.available > 0) {
|
||||
this.available--;
|
||||
callback();
|
||||
} else {
|
||||
|
@ -20,7 +20,7 @@ class Semaphore {
|
|||
}
|
||||
|
||||
release() {
|
||||
if(this.waiters.length > 0) {
|
||||
if (this.waiters.length > 0) {
|
||||
const callback = this.waiters.pop();
|
||||
process.nextTick(callback);
|
||||
} else {
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
"use strict";
|
||||
|
||||
exports.intersect = sets => {
|
||||
if(sets.length === 0) return new Set();
|
||||
if(sets.length === 1) return new Set(sets[0]);
|
||||
if (sets.length === 0) return new Set();
|
||||
if (sets.length === 1) return new Set(sets[0]);
|
||||
let minSize = Infinity;
|
||||
let minIndex = -1;
|
||||
for(let i = 0; i < sets.length; i++) {
|
||||
for (let i = 0; i < sets.length; i++) {
|
||||
const size = sets[i].size;
|
||||
if(size < minSize) {
|
||||
if (size < minSize) {
|
||||
minIndex = i;
|
||||
minSize = size;
|
||||
}
|
||||
}
|
||||
const current = new Set(sets[minIndex]);
|
||||
for(let i = 0; i < sets.length; i++) {
|
||||
if(i === minIndex) continue;
|
||||
for (let i = 0; i < sets.length; i++) {
|
||||
if (i === minIndex) continue;
|
||||
const set = sets[i];
|
||||
for(const item of current) {
|
||||
if(!set.has(item)) {
|
||||
for (const item of current) {
|
||||
if (!set.has(item)) {
|
||||
current.delete(item);
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ exports.intersect = sets => {
|
|||
};
|
||||
|
||||
exports.isSubset = (bigSet, smallSet) => {
|
||||
if(bigSet.size < smallSet.size) return false;
|
||||
for(const item of smallSet) {
|
||||
if(!bigSet.has(item)) return false;
|
||||
if (bigSet.size < smallSet.size) return false;
|
||||
for (const item of smallSet) {
|
||||
if (!bigSet.has(item)) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
class SortableSet extends Set {
|
||||
|
||||
constructor(initialIterable, defaultSort) {
|
||||
super(initialIterable);
|
||||
this._sortFn = defaultSort;
|
||||
|
@ -39,14 +38,14 @@ class SortableSet extends Set {
|
|||
* @returns {void}
|
||||
*/
|
||||
sortWith(sortFn) {
|
||||
if(this.size === 0 || sortFn === this._lastActiveSortFn) {
|
||||
if (this.size === 0 || sortFn === this._lastActiveSortFn) {
|
||||
// already sorted - nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
const sortedArray = Array.from(this).sort(sortFn);
|
||||
super.clear();
|
||||
for(let i = 0; i < sortedArray.length; i += 1) {
|
||||
for (let i = 0; i < sortedArray.length; i += 1) {
|
||||
super.add(sortedArray[i]);
|
||||
}
|
||||
this._lastActiveSortFn = sortFn;
|
||||
|
@ -65,11 +64,11 @@ class SortableSet extends Set {
|
|||
* @returns {any} - returns result of fn(this), cached until set changes
|
||||
*/
|
||||
getFromCache(fn) {
|
||||
if(this._cache === undefined) {
|
||||
if (this._cache === undefined) {
|
||||
this._cache = new Map();
|
||||
} else {
|
||||
const data = this._cache.get(fn);
|
||||
if(data !== undefined) {
|
||||
if (data !== undefined) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -83,11 +82,11 @@ class SortableSet extends Set {
|
|||
* @returns {any} - returns result of fn(this), cached until set changes
|
||||
*/
|
||||
getFromUnorderedCache(fn) {
|
||||
if(this._cacheOrderIndependent === undefined) {
|
||||
if (this._cacheOrderIndependent === undefined) {
|
||||
this._cacheOrderIndependent = new Map();
|
||||
} else {
|
||||
const data = this._cacheOrderIndependent.get(fn);
|
||||
if(data !== undefined) {
|
||||
if (data !== undefined) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -97,12 +96,11 @@ class SortableSet extends Set {
|
|||
}
|
||||
|
||||
_invalidateCache() {
|
||||
if(this._cache !== undefined)
|
||||
this._cache.clear();
|
||||
if (this._cache !== undefined) this._cache.clear();
|
||||
}
|
||||
|
||||
_invalidateOrderedCache() {
|
||||
if(this._cacheOrderIndependent !== undefined)
|
||||
if (this._cacheOrderIndependent !== undefined)
|
||||
this._cacheOrderIndependent.clear();
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue