Merge pull request #7869 from webpack/bugfix/reexport-position
ConcatenatedModule and reexport optimizations
This commit is contained in:
commit
e7757a53c4
|
@ -306,7 +306,7 @@ class Module extends DependenciesBlock {
|
|||
* @param {Module} otherModule some other module
|
||||
* @returns {boolean} true, if modules are in the same chunks
|
||||
*/
|
||||
hasEqualsChunks(otherModule) {
|
||||
hasEqualChunks(otherModule) {
|
||||
if (this._chunks.size !== otherModule._chunks.size) return false;
|
||||
this._chunks.sortWith(sortByDebugId);
|
||||
otherModule._chunks.sortWith(sortByDebugId);
|
||||
|
@ -593,6 +593,14 @@ class Module extends DependenciesBlock {
|
|||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(Module.prototype, "hasEqualsChunks", {
|
||||
get() {
|
||||
throw new Error(
|
||||
"Module.hasEqualsChunks was renamed (use hasEqualChunks instead)"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Module.prototype, "isUsed", {
|
||||
get() {
|
||||
throw new Error(
|
||||
|
|
|
@ -320,8 +320,8 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
otherImportedModule &&
|
||||
Array.isArray(otherImportedModule.buildMeta.providedExports)
|
||||
) {
|
||||
for (const exportName of otherImportedModule.buildMeta
|
||||
.providedExports) {
|
||||
const providedExports = otherImportedModule.buildMeta.providedExports;
|
||||
for (const exportName of providedExports) {
|
||||
result.add(exportName);
|
||||
}
|
||||
}
|
||||
|
@ -469,14 +469,10 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
const dep = /** @type {HarmonyExportImportedSpecifierDependency} */ (dependency);
|
||||
if (this.isUsed(dep, templateContext)) {
|
||||
const importFragments = super.getInitFragments(dep, templateContext);
|
||||
const exportFragment = new InitFragment(
|
||||
this.getContent(
|
||||
dep,
|
||||
templateContext.module,
|
||||
templateContext.moduleGraph
|
||||
),
|
||||
InitFragment.STAGE_HARMONY_IMPORTS,
|
||||
dep.sourceOrder
|
||||
const exportFragment = this._getExportFragment(
|
||||
dep,
|
||||
templateContext.module,
|
||||
templateContext.moduleGraph
|
||||
);
|
||||
return importFragments
|
||||
? importFragments.concat(exportFragment)
|
||||
|
@ -533,122 +529,152 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
* @param {HarmonyExportImportedSpecifierDependency} dep dependency
|
||||
* @param {Module} module the current module
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @returns {string} the generated code
|
||||
* @returns {InitFragment} the generated init fragment
|
||||
*/
|
||||
getContent(dep, module, moduleGraph) {
|
||||
_getExportFragment(dep, module, moduleGraph) {
|
||||
const mode = dep.getMode(moduleGraph, false);
|
||||
const importedModule = moduleGraph.getModule(dep);
|
||||
const importVar = dep.getImportVar(moduleGraph);
|
||||
|
||||
switch (mode.type) {
|
||||
case "missing":
|
||||
return `throw new Error(${JSON.stringify(
|
||||
`Cannot find module '${mode.userRequest}'`
|
||||
)});\n`;
|
||||
return new InitFragment(
|
||||
"/* empty/unused harmony star reexport */\n",
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "unused":
|
||||
return `${Template.toNormalComment(
|
||||
`unused harmony reexport ${mode.name}`
|
||||
)}\n`;
|
||||
return new InitFragment(
|
||||
`${Template.toNormalComment(
|
||||
`unused harmony reexport ${mode.name}`
|
||||
)}\n`,
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "reexport-non-harmony-default":
|
||||
return (
|
||||
return new InitFragment(
|
||||
"/* harmony reexport (default from non-harmony) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
null
|
||||
)
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
null
|
||||
),
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "reexport-named-default":
|
||||
return (
|
||||
return new InitFragment(
|
||||
"/* harmony reexport (default from named exports) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
""
|
||||
)
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
""
|
||||
),
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "reexport-fake-namespace-object":
|
||||
return (
|
||||
return new InitFragment(
|
||||
"/* harmony reexport (fake namespace object from non-harmony) */ " +
|
||||
this.getReexportFakeNamespaceObjectStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar
|
||||
)
|
||||
this.getReexportFakeNamespaceObjectStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar
|
||||
),
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "rexport-non-harmony-undefined":
|
||||
return (
|
||||
return new InitFragment(
|
||||
"/* harmony reexport (non default export from non-harmony) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
"undefined",
|
||||
""
|
||||
)
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
"undefined",
|
||||
""
|
||||
),
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "reexport-non-harmony-default-strict":
|
||||
return (
|
||||
return new InitFragment(
|
||||
"/* harmony reexport (default from non-harmony) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
""
|
||||
)
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
""
|
||||
),
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "reexport-namespace-object":
|
||||
return (
|
||||
return new InitFragment(
|
||||
"/* harmony reexport (module object) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
""
|
||||
)
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, mode.name),
|
||||
importVar,
|
||||
""
|
||||
),
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "empty-star":
|
||||
return "/* empty/unused harmony star reexport */";
|
||||
return new InitFragment(
|
||||
"/* empty/unused harmony star reexport */",
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
case "safe-reexport":
|
||||
return Array.from(mode.map.entries())
|
||||
.map(item => {
|
||||
return (
|
||||
"/* harmony reexport (safe) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, item[0]),
|
||||
importVar,
|
||||
importedModule.getUsedName(moduleGraph, item[1])
|
||||
)
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
return new InitFragment(
|
||||
Array.from(mode.map.entries())
|
||||
.map(item => {
|
||||
return (
|
||||
"/* harmony reexport (safe) */ " +
|
||||
this.getReexportStatement(
|
||||
module,
|
||||
module.getUsedName(moduleGraph, item[0]),
|
||||
importVar,
|
||||
importedModule.getUsedName(moduleGraph, item[1])
|
||||
)
|
||||
);
|
||||
})
|
||||
.join(""),
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
|
||||
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 new InitFragment(
|
||||
Array.from(mode.map.entries())
|
||||
.map(item => {
|
||||
return (
|
||||
"/* harmony reexport (checked) */ " +
|
||||
this.getConditionalReexportStatement(
|
||||
module,
|
||||
item[0],
|
||||
importVar,
|
||||
item[1]
|
||||
) +
|
||||
"\n"
|
||||
);
|
||||
})
|
||||
.join(""),
|
||||
InitFragment.STAGE_HARMONY_IMPORTS,
|
||||
dep.sourceOrder
|
||||
);
|
||||
|
||||
case "dynamic-reexport": {
|
||||
const activeExports = new Set([
|
||||
|
@ -671,9 +697,11 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') ";
|
||||
}
|
||||
const exportsName = module.exportsArgument;
|
||||
return (
|
||||
return new InitFragment(
|
||||
content +
|
||||
`(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${importVar}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`
|
||||
`(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${importVar}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`,
|
||||
InitFragment.STAGE_HARMONY_IMPORTS,
|
||||
dep.sourceOrder
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
const eslintScope = require("eslint-scope");
|
||||
const { ConcatSource, ReplaceSource } = require("webpack-sources");
|
||||
const DependencyTemplate = require("../DependencyTemplate");
|
||||
const InitFragment = require("../InitFragment");
|
||||
const JavascriptParser = require("../JavascriptParser");
|
||||
const Module = require("../Module");
|
||||
const Template = require("../Template");
|
||||
|
@ -26,7 +27,6 @@ const createHash = require("../util/createHash");
|
|||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
|
||||
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
|
||||
/** @typedef {import("../InitFragment")} InitFragment */
|
||||
/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
|
||||
/** @typedef {import("../Module").SourceContext} SourceContext */
|
||||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
|
@ -1398,6 +1398,28 @@ class HarmonyExportExpressionDependencyConcatenatedTemplate extends DependencyTe
|
|||
this.rootModule = rootModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Dependency} dependency the dependency for which the template should be applied
|
||||
* @param {DependencyTemplateContext} templateContext the template context
|
||||
* @returns {InitFragment[]|null} the init fragments
|
||||
*/
|
||||
getInitFragments(dependency, templateContext) {
|
||||
const { moduleGraph, module } = templateContext;
|
||||
if (module === this.rootModule) {
|
||||
const used = module.getUsedName(moduleGraph, "default");
|
||||
const exportsName = module.exportsArgument;
|
||||
return [
|
||||
new InitFragment(
|
||||
`/* harmony export export */ ` +
|
||||
`__webpack_require__.d(${exportsName}, ${JSON.stringify(used)}, ` +
|
||||
`function() { return __WEBPACK_MODULE_DEFAULT_EXPORT__; });\n`,
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Dependency} dependency the dependency for which the template should be applied
|
||||
* @param {ReplaceSource} source the current replace source which can be modified
|
||||
|
@ -1406,15 +1428,8 @@ class HarmonyExportExpressionDependencyConcatenatedTemplate extends DependencyTe
|
|||
*/
|
||||
apply(dependency, source, { module, moduleGraph }) {
|
||||
const dep = /** @type {HarmonyExportExpressionDependency} */ (dependency);
|
||||
let content =
|
||||
const content =
|
||||
"/* harmony default export */ var __WEBPACK_MODULE_DEFAULT_EXPORT__ = ";
|
||||
if (module === this.rootModule) {
|
||||
const used = module.getUsedName(moduleGraph, "default");
|
||||
const exportsName = module.exportsArgument;
|
||||
if (used) {
|
||||
content += `${exportsName}[${JSON.stringify(used)}] = `;
|
||||
}
|
||||
}
|
||||
|
||||
if (dep.range) {
|
||||
source.replace(dep.rangeStatement[0], dep.range[0] - 1, content + "(");
|
||||
|
@ -1434,6 +1449,17 @@ class HarmonyExportImportedSpecifierDependencyConcatenatedTemplate extends Depen
|
|||
this.modulesMap = modulesMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} GetExportsResultItem
|
||||
* @property {string} name
|
||||
* @property {string | true} id
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {HarmonyExportImportedSpecifierDependency} dep dependency
|
||||
* @param {DependencyTemplateContext} templateContext template context
|
||||
* @returns {GetExportsResultItem[]} exports
|
||||
*/
|
||||
getExports(dep, { moduleGraph }) {
|
||||
const importModule = moduleGraph.getModule(dep);
|
||||
if (dep.id) {
|
||||
|
@ -1441,8 +1467,7 @@ class HarmonyExportImportedSpecifierDependencyConcatenatedTemplate extends Depen
|
|||
return [
|
||||
{
|
||||
name: dep.name,
|
||||
id: dep.id,
|
||||
module: importModule
|
||||
id: dep.id
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -1451,21 +1476,24 @@ class HarmonyExportImportedSpecifierDependencyConcatenatedTemplate extends Depen
|
|||
return [
|
||||
{
|
||||
name: dep.name,
|
||||
id: true,
|
||||
module: importModule
|
||||
id: true
|
||||
}
|
||||
];
|
||||
}
|
||||
// export * from "module"
|
||||
return importModule.buildMeta.providedExports
|
||||
.filter(exp => exp !== "default" && !dep.activeExports.has(exp))
|
||||
.map(exp => {
|
||||
return {
|
||||
name: exp,
|
||||
id: exp,
|
||||
module: importModule
|
||||
};
|
||||
});
|
||||
if (Array.isArray(importModule.buildMeta.providedExports)) {
|
||||
return importModule.buildMeta.providedExports
|
||||
.filter(exp => exp !== "default" && !dep.activeExports.has(exp))
|
||||
.map(exp => {
|
||||
return {
|
||||
name: exp,
|
||||
id: exp
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// unknown, should not happen
|
||||
throw new Error("ConcatenatedModule: unknown exports");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1475,13 +1503,43 @@ class HarmonyExportImportedSpecifierDependencyConcatenatedTemplate extends Depen
|
|||
*/
|
||||
getInitFragments(dependency, templateContext) {
|
||||
const dep = /** @type {HarmonyExportImportedSpecifierDependency} */ (dependency);
|
||||
const { moduleGraph } = templateContext;
|
||||
const module = moduleGraph.getModule(dep);
|
||||
const info = this.modulesMap.get(module);
|
||||
const { moduleGraph, module } = templateContext;
|
||||
const importedModule = moduleGraph.getModule(dep);
|
||||
const info = this.modulesMap.get(importedModule);
|
||||
if (!info) {
|
||||
return this.originalTemplate.getInitFragments(dep, templateContext);
|
||||
} else {
|
||||
return null;
|
||||
} else if (module === this.rootModule) {
|
||||
const exportDefs = this.getExports(dep, templateContext);
|
||||
return exportDefs.map(def => {
|
||||
const used = module.getUsedName(moduleGraph, def.name);
|
||||
if (!used) {
|
||||
return new InitFragment(
|
||||
`/* unused concated harmony import ${dep.name} */\n`,
|
||||
InitFragment.STAGE_HARMONY_EXPORTS,
|
||||
1
|
||||
);
|
||||
}
|
||||
let finalName;
|
||||
const strictFlag = module.buildMeta.strictHarmonyModule
|
||||
? "_strict"
|
||||
: "";
|
||||
if (def.id === true) {
|
||||
finalName = `__WEBPACK_MODULE_REFERENCE__${
|
||||
info.index
|
||||
}_ns${strictFlag}__`;
|
||||
} else {
|
||||
const exportData = Buffer.from(def.id, "utf-8").toString("hex");
|
||||
finalName = `__WEBPACK_MODULE_REFERENCE__${
|
||||
info.index
|
||||
}_${exportData}${strictFlag}__`;
|
||||
}
|
||||
const exportsName = this.rootModule.exportsArgument;
|
||||
const content =
|
||||
"/* concated harmony reexport */ __webpack_require__.d(" +
|
||||
`${exportsName}, ${JSON.stringify(used)}, ` +
|
||||
`function() { return ${finalName}; });\n`;
|
||||
return new InitFragment(content, InitFragment.STAGE_HARMONY_EXPORTS, 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1492,43 +1550,13 @@ class HarmonyExportImportedSpecifierDependencyConcatenatedTemplate extends Depen
|
|||
* @returns {void}
|
||||
*/
|
||||
apply(dependency, source, templateContext) {
|
||||
const { moduleGraph, module } = templateContext;
|
||||
const { moduleGraph } = templateContext;
|
||||
const dep = /** @type {HarmonyExportImportedSpecifierDependency} */ (dependency);
|
||||
if (module === this.rootModule) {
|
||||
if (this.modulesMap.get(moduleGraph.getModule(dep))) {
|
||||
const exportDefs = this.getExports(dep, { moduleGraph });
|
||||
for (const def of exportDefs) {
|
||||
const info = this.modulesMap.get(def.module);
|
||||
const used = module.getUsedName(moduleGraph, def.name);
|
||||
if (!used) {
|
||||
source.insert(
|
||||
-1,
|
||||
`/* unused concated harmony import ${dep.name} */\n`
|
||||
);
|
||||
}
|
||||
let finalName;
|
||||
const strictFlag = module.buildMeta.strictHarmonyModule
|
||||
? "_strict"
|
||||
: "";
|
||||
if (def.id === true) {
|
||||
finalName = `__WEBPACK_MODULE_REFERENCE__${
|
||||
info.index
|
||||
}_ns${strictFlag}__`;
|
||||
} else {
|
||||
const exportData = Buffer.from(def.id, "utf-8").toString("hex");
|
||||
finalName = `__WEBPACK_MODULE_REFERENCE__${
|
||||
info.index
|
||||
}_${exportData}${strictFlag}__`;
|
||||
}
|
||||
const exportsName = this.rootModule.exportsArgument;
|
||||
const content = `/* concated harmony reexport */__webpack_require__.d(${exportsName}, ${JSON.stringify(
|
||||
used
|
||||
)}, function() { return ${finalName}; });\n`;
|
||||
source.insert(-1, content);
|
||||
}
|
||||
} else {
|
||||
this.originalTemplate.apply(dependency, source, templateContext);
|
||||
}
|
||||
const module = moduleGraph.getModule(dep);
|
||||
const info = this.modulesMap.get(module);
|
||||
if (!info) {
|
||||
this.originalTemplate.apply(dependency, source, templateContext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ class ModuleConcatenationPlugin {
|
|||
const bailoutReasonMap = new Map();
|
||||
|
||||
const setBailoutReason = (module, reason) => {
|
||||
bailoutReasonMap.set(module, reason);
|
||||
setInnerBailoutReason(module, reason);
|
||||
module
|
||||
.getOptimizationBailout(moduleGraph)
|
||||
.push(
|
||||
|
@ -66,12 +66,36 @@ class ModuleConcatenationPlugin {
|
|||
);
|
||||
};
|
||||
|
||||
const getBailoutReason = (module, requestShortener) => {
|
||||
const setInnerBailoutReason = (module, reason) => {
|
||||
bailoutReasonMap.set(module, reason);
|
||||
};
|
||||
|
||||
const getInnerBailoutReason = (module, requestShortener) => {
|
||||
const reason = bailoutReasonMap.get(module);
|
||||
if (typeof reason === "function") return reason(requestShortener);
|
||||
return reason;
|
||||
};
|
||||
|
||||
const formatBailoutWarning = (module, problem) => requestShortener => {
|
||||
const reason = getInnerBailoutReason(module, requestShortener);
|
||||
const reasonWithPrefix = reason ? ` (<- ${reason})` : "";
|
||||
if (module === problem) {
|
||||
return formatBailoutReason(
|
||||
`Cannot concat with ${module.readableIdentifier(
|
||||
requestShortener
|
||||
)}${reasonWithPrefix}`
|
||||
);
|
||||
} else {
|
||||
return formatBailoutReason(
|
||||
`Cannot concat with ${module.readableIdentifier(
|
||||
requestShortener
|
||||
)} because of ${problem.readableIdentifier(
|
||||
requestShortener
|
||||
)}${reasonWithPrefix}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
compilation.hooks.optimizeChunkModules.tap(
|
||||
"ModuleConcatenationPlugin",
|
||||
(chunks, modules) => {
|
||||
|
@ -122,49 +146,60 @@ class ModuleConcatenationPlugin {
|
|||
continue;
|
||||
}
|
||||
|
||||
relevantModules.push(module);
|
||||
|
||||
// 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 only be used by Harmony Imports
|
||||
const nonHarmonyConnections = moduleGraph
|
||||
relevantModules.push(module);
|
||||
|
||||
// Module must not be the entry points
|
||||
if (module.isEntryModule()) {
|
||||
setInnerBailoutReason(module, "Module is an entry point");
|
||||
continue;
|
||||
}
|
||||
|
||||
const incomingConnections = moduleGraph
|
||||
.getIncomingConnections(module)
|
||||
.filter(
|
||||
connection =>
|
||||
!connection.dependency ||
|
||||
!(connection.dependency instanceof HarmonyImportDependency)
|
||||
);
|
||||
.filter(connection => {
|
||||
return (
|
||||
!connection.originModule ||
|
||||
connection.originModule.isModuleUsed(moduleGraph)
|
||||
);
|
||||
});
|
||||
|
||||
// Module must only be used by Harmony Imports
|
||||
const nonHarmonyConnections = incomingConnections.filter(
|
||||
connection =>
|
||||
!connection.dependency ||
|
||||
!(connection.dependency instanceof HarmonyImportDependency)
|
||||
);
|
||||
if (nonHarmonyConnections.length > 0) {
|
||||
const importingModules = new Set(
|
||||
nonHarmonyConnections.map(c => c.originModule).filter(Boolean)
|
||||
);
|
||||
const importingExplanations = new Set(
|
||||
nonHarmonyConnections.map(c => c.explanation).filter(Boolean)
|
||||
);
|
||||
const importingModuleTypes = new Map(
|
||||
Array.from(importingModules).map(
|
||||
m => /** @type {[Module, Set<string>]} */ ([
|
||||
m,
|
||||
new Set(
|
||||
nonHarmonyConnections
|
||||
.filter(c => c.originModule === m)
|
||||
.map(c => c.dependency.type)
|
||||
.sort()
|
||||
)
|
||||
])
|
||||
)
|
||||
);
|
||||
setBailoutReason(module, requestShortener => {
|
||||
setInnerBailoutReason(module, requestShortener => {
|
||||
const importingModules = new Set(
|
||||
nonHarmonyConnections
|
||||
.map(c => c.originModule)
|
||||
.filter(Boolean)
|
||||
);
|
||||
const importingExplanations = new Set(
|
||||
nonHarmonyConnections
|
||||
.map(c => c.explanation)
|
||||
.filter(Boolean)
|
||||
);
|
||||
const importingModuleTypes = new Map(
|
||||
Array.from(importingModules).map(
|
||||
m => /** @type {[Module, Set<string>]} */ ([
|
||||
m,
|
||||
new Set(
|
||||
nonHarmonyConnections
|
||||
.filter(c => c.originModule === m)
|
||||
.map(c => c.dependency.type)
|
||||
.sort()
|
||||
)
|
||||
])
|
||||
)
|
||||
);
|
||||
const names = Array.from(importingModules)
|
||||
.map(
|
||||
m =>
|
||||
|
@ -195,6 +230,32 @@ class ModuleConcatenationPlugin {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Module must be in the same chunks like the referencing module
|
||||
const otherChunkConnections = incomingConnections.filter(
|
||||
connection => {
|
||||
return (
|
||||
connection.originModule &&
|
||||
!connection.originModule.hasEqualChunks(module)
|
||||
);
|
||||
}
|
||||
);
|
||||
if (otherChunkConnections.length > 0) {
|
||||
setInnerBailoutReason(module, requestShortener => {
|
||||
const importingModules = new Set(
|
||||
otherChunkConnections
|
||||
.map(c => c.originModule)
|
||||
.filter(Boolean)
|
||||
);
|
||||
const names = Array.from(importingModules)
|
||||
.map(m => m.readableIdentifier(requestShortener))
|
||||
.sort();
|
||||
return `Module is referenced from different chunks by these modules: ${names.join(
|
||||
", "
|
||||
)}`;
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
possibleInners.add(module);
|
||||
}
|
||||
// sort by depth
|
||||
|
@ -237,6 +298,12 @@ class ModuleConcatenationPlugin {
|
|||
usedAsInner.add(module);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const warning of currentConfiguration.getWarningsSorted()) {
|
||||
currentRoot
|
||||
.getOptimizationBailout(moduleGraph)
|
||||
.push(formatBailoutWarning(warning[0], warning[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
// HACK: Sort configurations by length and start with the longest one
|
||||
|
@ -259,28 +326,7 @@ class ModuleConcatenationPlugin {
|
|||
for (const warning of concatConfiguration.getWarningsSorted()) {
|
||||
newModule
|
||||
.getOptimizationBailout(moduleGraph)
|
||||
.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}`
|
||||
);
|
||||
}
|
||||
});
|
||||
.push(formatBailoutWarning(warning[0], warning[1]));
|
||||
}
|
||||
const chunks = concatConfiguration.rootModule.getChunks();
|
||||
for (const m of modules) {
|
||||
|
@ -369,12 +415,6 @@ class ModuleConcatenationPlugin {
|
|||
return module;
|
||||
}
|
||||
|
||||
// module must be in the same chunks
|
||||
if (!config.rootModule.hasEqualsChunks(module)) {
|
||||
failureCache.set(module, module); // cache failures for performance
|
||||
return module;
|
||||
}
|
||||
|
||||
// Clone config to make experimental changes
|
||||
const testConfig = config.clone();
|
||||
|
||||
|
@ -386,11 +426,7 @@ class ModuleConcatenationPlugin {
|
|||
// Every module which depends on the added module must be in the configuration too.
|
||||
for (const connection of moduleGraph.getIncomingConnections(module)) {
|
||||
// Modules that are not used can be ignored
|
||||
if (
|
||||
connection.originModule.factoryMeta.sideEffectFree &&
|
||||
!connection.originModule.isModuleUsed(moduleGraph)
|
||||
)
|
||||
continue;
|
||||
if (!connection.originModule.isModuleUsed(moduleGraph)) continue;
|
||||
|
||||
const problem = this._tryToAdd(
|
||||
compilation,
|
||||
|
|
|
@ -677,7 +677,6 @@ Child
|
|||
exports[`StatsTestCases should print correct stats for concat-and-sideeffects 1`] = `
|
||||
"[0] ./index.js + 2 modules 119 bytes {0} [built]
|
||||
| ./index.js 46 bytes [built]
|
||||
| ModuleConcatenation bailout: Module is an entry point
|
||||
| ./node_modules/pmodule/a.js 49 bytes [built]
|
||||
| ./node_modules/pmodule/aa.js 24 bytes [built]
|
||||
./node_modules/pmodule/index.js 63 bytes [built]
|
||||
|
@ -2146,13 +2145,15 @@ Built at: Thu Jan 01 1970 00:00:00 GMT
|
|||
Entrypoint index = index.js
|
||||
Entrypoint entry = entry.js
|
||||
[0] ./index.js 150 bytes {0} [built]
|
||||
ModuleConcatenation bailout: Module is an entry point
|
||||
ModuleConcatenation bailout: Cannot concat with ./entry.js (<- Module is an entry point)
|
||||
ModuleConcatenation bailout: Cannot concat with ./eval.js (<- Module uses eval())
|
||||
ModuleConcatenation bailout: Cannot concat with ./module-id.js (<- Module uses module.id)
|
||||
ModuleConcatenation bailout: Cannot concat with ./module-loaded.js (<- Module uses module.loaded)
|
||||
ModuleConcatenation bailout: Cannot concat with ./ref-from-cjs.js (<- Module is referenced from these modules with unsupported syntax: ./cjs.js (referenced with cjs require))
|
||||
[1] ./cjs.js 59 bytes {0} [built]
|
||||
ModuleConcatenation bailout: Module is not an ECMAScript module
|
||||
[2] ./ref-from-cjs.js 45 bytes {0} [built]
|
||||
ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./cjs.js (referenced with cjs require)
|
||||
[3] ./entry.js 32 bytes {0} {1} [built]
|
||||
ModuleConcatenation bailout: Module is an entry point
|
||||
[4] ./eval.js 35 bytes {0} [built]
|
||||
ModuleConcatenation bailout: Module uses eval()
|
||||
[5] ./module-id.js 26 bytes {0} [built]
|
||||
|
@ -2164,7 +2165,6 @@ Entrypoint entry = entry.js
|
|||
[8] ./concatenated.js + 2 modules 116 bytes {2} [built]
|
||||
ModuleConcatenation bailout: Cannot concat with external \\"external\\" (<- Module is not an ECMAScript module)
|
||||
| ./concatenated.js 26 bytes [built]
|
||||
| ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./index.js (referenced with import())
|
||||
| ./concatenated1.js 37 bytes [built]
|
||||
| ./concatenated2.js 48 bytes [built]"
|
||||
`;
|
||||
|
@ -2196,20 +2196,22 @@ Child
|
|||
Entrypoint second = vendor.js second.js
|
||||
[0] ./vendor.js 25 bytes {0} [built]
|
||||
[1] ./second.js 177 bytes {1} [built]
|
||||
ModuleConcatenation bailout: Module is an entry point
|
||||
ModuleConcatenation bailout: Cannot concat with ./common.js (<- Module is referenced from different chunks by these modules: ./first.js + 1 modules, ./second.js)
|
||||
ModuleConcatenation bailout: Cannot concat with ./vendor.js (<- Module is referenced from different chunks by these modules: ./first.js + 1 modules, ./second.js)
|
||||
[2] ./lazy_first.js 55 bytes {2} [built]
|
||||
ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./first.js (referenced with import())
|
||||
ModuleConcatenation bailout: Cannot concat with ./common_lazy.js (<- Module is referenced from different chunks by these modules: ./lazy_first.js, ./lazy_second.js)
|
||||
ModuleConcatenation bailout: Cannot concat with ./common_lazy_shared.js (<- Module is referenced from different chunks by these modules: ./lazy_first.js, ./lazy_second.js, ./lazy_shared.js)
|
||||
[3] ./common_lazy.js 25 bytes {2} {3} [built]
|
||||
[4] ./common_lazy_shared.js 25 bytes {2} {3} {4} [built]
|
||||
[5] ./lazy_shared.js 31 bytes {4} [built]
|
||||
ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./first.js (referenced with import()), ./second.js (referenced with import())
|
||||
ModuleConcatenation bailout: Cannot concat with ./common_lazy_shared.js (<- Module is referenced from different chunks by these modules: ./lazy_first.js, ./lazy_second.js, ./lazy_shared.js)
|
||||
[6] ./lazy_second.js 55 bytes {3} [built]
|
||||
ModuleConcatenation bailout: Module is referenced from these modules with unsupported syntax: ./second.js (referenced with import())
|
||||
ModuleConcatenation bailout: Cannot concat with ./common_lazy.js (<- Module is referenced from different chunks by these modules: ./lazy_first.js, ./lazy_second.js)
|
||||
ModuleConcatenation bailout: Cannot concat with ./common_lazy_shared.js (<- Module is referenced from different chunks by these modules: ./lazy_first.js, ./lazy_second.js, ./lazy_shared.js)
|
||||
[7] ./first.js + 1 modules 248 bytes {5} [built]
|
||||
ModuleConcatenation bailout: Cannot concat with ./common.js
|
||||
ModuleConcatenation bailout: Cannot concat with ./vendor.js
|
||||
ModuleConcatenation bailout: Cannot concat with ./common.js (<- Module is referenced from different chunks by these modules: ./first.js + 1 modules, ./second.js)
|
||||
ModuleConcatenation bailout: Cannot concat with ./vendor.js (<- Module is referenced from different chunks by these modules: ./first.js + 1 modules, ./second.js)
|
||||
| ./first.js 207 bytes [built]
|
||||
| ModuleConcatenation bailout: Module is an entry point
|
||||
| ./module_first.js 31 bytes [built]
|
||||
[8] ./common.js + 1 modules 62 bytes {1} {5} [built]
|
||||
| ./common.js 37 bytes [built]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import { B } from "./cycle";
|
||||
|
||||
export const A = B;
|
|
@ -0,0 +1,3 @@
|
|||
import { A } from "./cycle";
|
||||
|
||||
export const B = A;
|
|
@ -0,0 +1,2 @@
|
|||
export { A } from "./a";
|
||||
export { B } from "./b";
|
|
@ -0,0 +1,5 @@
|
|||
it("should fail with a ReferenceError", () => {
|
||||
expect(() => {
|
||||
require("./cycle");
|
||||
}).toThrow();
|
||||
});
|
|
@ -1,2 +1,2 @@
|
|||
export var x = "1";
|
||||
export * from "./a";
|
||||
export * from "./a?1";
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export * from "./a";
|
||||
export * from "./a?2";
|
||||
export var x = "1";
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from "./a";
|
||||
export * from "./b";
|
||||
// TODO: Technically this should lead to an error
|
||||
export * from "./a?3";
|
||||
export * from "./b?3";
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from "./b";
|
||||
export * from "./a";
|
||||
// TODO: Technically this should lead to an error
|
||||
export * from "./b?4";
|
||||
export * from "./a?4";
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
export * from "./c";
|
||||
export * from "./d";
|
||||
// Theoretically this should lead to an error
|
||||
// but in this dynamic case it's impossible to detect it
|
||||
export * from "./c?5";
|
||||
export * from "./d?5";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export * from "./a";
|
||||
export * from "./b";
|
||||
export * from "./c";
|
||||
export * from "./d";
|
||||
// TODO: Technically this should lead to an error
|
||||
export * from "./a?6";
|
||||
export * from "./b?6";
|
||||
export * from "./c?6";
|
||||
export * from "./d?6";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export * from "./d";
|
||||
export * from "./b";
|
||||
export * from "./c";
|
||||
export * from "./a";
|
||||
// TODO: Technically this should lead to an error
|
||||
export * from "./d?7";
|
||||
export * from "./b?7";
|
||||
export * from "./c?7";
|
||||
export * from "./a?7";
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
export var x = "1";
|
||||
export * from "./a?1";
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./a?2";
|
||||
export var x = "1";
|
|
@ -0,0 +1,3 @@
|
|||
// TODO: Technically this should lead to an error
|
||||
export * from "./a?3";
|
||||
export * from "./b?3";
|
|
@ -0,0 +1,3 @@
|
|||
// TODO: Technically this should lead to an error
|
||||
export * from "./b?4";
|
||||
export * from "./a?4";
|
|
@ -0,0 +1,4 @@
|
|||
// Theoretically this should lead to an error
|
||||
// but in this dynamic case it's impossible to detect it
|
||||
export * from "./c?5";
|
||||
export * from "./d?5";
|
|
@ -0,0 +1,5 @@
|
|||
// TODO: Technically this should lead to an error
|
||||
export * from "./a?6";
|
||||
export * from "./b?6";
|
||||
export * from "./c?6";
|
||||
export * from "./d?6";
|
|
@ -0,0 +1,5 @@
|
|||
// TODO: Technically this should lead to an error
|
||||
export * from "./d?7";
|
||||
export * from "./b?7";
|
||||
export * from "./c?7";
|
||||
export * from "./a?7";
|
|
@ -0,0 +1 @@
|
|||
export var x = "a";
|
|
@ -0,0 +1 @@
|
|||
export var x = "b";
|
|
@ -0,0 +1 @@
|
|||
exports.x = "c";
|
|
@ -0,0 +1 @@
|
|||
exports.x = "d";
|
|
@ -1,18 +1,18 @@
|
|||
import { x as x1 } from "./1?a";
|
||||
import { x as x2 } from "./2?a";
|
||||
import { x as x3 } from "./3?a";
|
||||
import { x as x4 } from "./4?a";
|
||||
import { x as x5 } from "./5?a";
|
||||
import { x as x6 } from "./6?a";
|
||||
import { x as x7 } from "./7?a";
|
||||
import { x as x1 } from "./1";
|
||||
import { x as x2 } from "./2";
|
||||
import { x as x3 } from "./3";
|
||||
import { x as x4 } from "./4";
|
||||
import { x as x5 } from "./5";
|
||||
import { x as x6 } from "./6";
|
||||
import { x as x7 } from "./7";
|
||||
|
||||
var y1 = require("./1?b").x;
|
||||
var y2 = require("./2?b").x;
|
||||
var y3 = require("./3?b").x;
|
||||
var y4 = require("./4?b").x;
|
||||
var y5 = require("./5?b").x;
|
||||
var y6 = require("./6?b").x;
|
||||
var y7 = require("./7?b").x;
|
||||
var y1 = require("./cjs/1").x;
|
||||
var y2 = require("./cjs/2").x;
|
||||
var y3 = require("./cjs/3").x;
|
||||
var y4 = require("./cjs/4").x;
|
||||
var y5 = require("./cjs/5").x;
|
||||
var y6 = require("./cjs/6").x;
|
||||
var y7 = require("./cjs/7").x;
|
||||
|
||||
it("should not overwrite when using star export (known exports)", function() {
|
||||
expect(x1).toBe("1");
|
||||
|
@ -21,7 +21,7 @@ it("should not overwrite when using star export (known exports)", function() {
|
|||
expect(x4).toBe("b");
|
||||
expect(x5).toBe("c");
|
||||
expect(x6).toBe("a");
|
||||
expect(x7).toBe("d");
|
||||
expect(x7).toBe("b"); // Looks wrong, but is irrelevant as this should be an error anyway
|
||||
});
|
||||
|
||||
it("should not overwrite when using star export (unknown exports)", function() {
|
||||
|
@ -31,5 +31,5 @@ it("should not overwrite when using star export (unknown exports)", function() {
|
|||
expect(y4).toBe("b");
|
||||
expect(y5).toBe("c");
|
||||
expect(y6).toBe("a");
|
||||
expect(y7).toBe("d");
|
||||
expect(y7).toBe("b"); // Looks wrong, but is irrelevant as this should be an error anyway
|
||||
});
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
exports.named = "named";
|
|
@ -0,0 +1 @@
|
|||
export { named } from "./a";
|
|
@ -0,0 +1 @@
|
|||
export * from "./b";
|
|
@ -0,0 +1,5 @@
|
|||
var c = require("./c");
|
||||
|
||||
it("should have the correct values", function() {
|
||||
expect(c.named).toBe("named");
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
exports.named = "named";
|
|
@ -0,0 +1 @@
|
|||
export var other = "other";
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./a";
|
||||
export * from "./b";
|
|
@ -0,0 +1,5 @@
|
|||
var c = require("./c");
|
||||
|
||||
it("should have the correct values", function() {
|
||||
expect(c.named).toBe("named");
|
||||
});
|
Loading…
Reference in New Issue