Merge pull request #7869 from webpack/bugfix/reexport-position

ConcatenatedModule and reexport optimizations
This commit is contained in:
Tobias Koppers 2018-08-09 16:43:25 +02:00 committed by GitHub
commit e7757a53c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 433 additions and 267 deletions

View File

@ -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(

View File

@ -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
);
}

View File

@ -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;
}
}
}

View File

@ -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,

View File

@ -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]

View File

@ -0,0 +1,3 @@
import { B } from "./cycle";
export const A = B;

View File

@ -0,0 +1,3 @@
import { A } from "./cycle";
export const B = A;

View File

@ -0,0 +1,2 @@
export { A } from "./a";
export { B } from "./b";

View File

@ -0,0 +1,5 @@
it("should fail with a ReferenceError", () => {
expect(() => {
require("./cycle");
}).toThrow();
});

View File

@ -1,2 +1,2 @@
export var x = "1";
export * from "./a";
export * from "./a?1";

View File

@ -1,2 +1,2 @@
export * from "./a";
export * from "./a?2";
export var x = "1";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -0,0 +1,2 @@
export var x = "1";
export * from "./a?1";

View File

@ -0,0 +1,2 @@
export * from "./a?2";
export var x = "1";

View File

@ -0,0 +1,3 @@
// TODO: Technically this should lead to an error
export * from "./a?3";
export * from "./b?3";

View File

@ -0,0 +1,3 @@
// TODO: Technically this should lead to an error
export * from "./b?4";
export * from "./a?4";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -0,0 +1 @@
export var x = "a";

View File

@ -0,0 +1 @@
export var x = "b";

View File

@ -0,0 +1 @@
exports.x = "c";

View File

@ -0,0 +1 @@
exports.x = "d";

View File

@ -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
});

View File

@ -0,0 +1 @@
exports.named = "named";

View File

@ -0,0 +1 @@
export { named } from "./a";

View File

@ -0,0 +1 @@
export * from "./b";

View File

@ -0,0 +1,5 @@
var c = require("./c");
it("should have the correct values", function() {
expect(c.named).toBe("named");
});

View File

@ -0,0 +1 @@
exports.named = "named";

View File

@ -0,0 +1 @@
export var other = "other";

View File

@ -0,0 +1,2 @@
export * from "./a";
export * from "./b";

View File

@ -0,0 +1,5 @@
var c = require("./c");
it("should have the correct values", function() {
expect(c.named).toBe("named");
});