consistency and bugfixes for reexporting json

This commit is contained in:
Tobias Koppers 2019-11-04 21:05:17 +01:00
parent 2f2125b4d1
commit 84b6817f60
19 changed files with 354 additions and 260 deletions

View File

@ -43,12 +43,6 @@ class FlagDependencyUsagePlugin {
const exportsInfo = moduleGraph.getExportsInfo(module);
if (usedExports.length > 0) {
for (let usedExport of usedExports) {
if (
module.buildMeta.exportsType === "named" &&
usedExport[0] === "default"
) {
usedExport = usedExport.slice(1);
}
if (usedExport.length === 0) {
if (exportsInfo.setUsedInUnknownWay()) {
queue.enqueue(module);

View File

@ -5,9 +5,31 @@
"use strict";
const { ConcatSource } = require("webpack-sources");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("./Generator").GenerateContext} GenerateContext */
/**
* @param {InitFragment} fragment the init fragment
* @param {number} index index
* @returns {[InitFragment, number]} tuple with both
*/
const extractFragmentIndex = (fragment, index) => [fragment, index];
/**
* @param {[InitFragment, number]} a first pair
* @param {[InitFragment, number]} b second pair
* @returns {number} sort value
*/
const sortFragmentWithIndex = ([a, i], [b, j]) => {
const stageCmp = a.stage - b.stage;
if (stageCmp !== 0) return stageCmp;
const positionCmp = a.position - b.position;
if (positionCmp !== 0) return positionCmp;
return i - j;
};
class InitFragment {
/**
* @param {string|Source} content the source code that will be included as initialization code
@ -39,6 +61,50 @@ class InitFragment {
getEndContent(generateContext) {
return this.endContent;
}
static addToSource(source, initFragments, generateContext) {
if (initFragments.length > 0) {
// Sort fragments by position. If 2 fragments have the same position,
// use their index.
const sortedFragments = initFragments
.map(extractFragmentIndex)
.sort(sortFragmentWithIndex);
// Deduplicate fragments. If a fragment has no key, it is always included.
const keyedFragments = new Map();
for (const [fragment] of sortedFragments) {
if (typeof fragment.merge === "function") {
const oldValue = keyedFragments.get(fragment.key);
if (oldValue !== undefined) {
keyedFragments.set(
fragment.key || Symbol(),
fragment.merge(oldValue)
);
continue;
}
}
keyedFragments.set(fragment.key || Symbol(), fragment);
}
const concatSource = new ConcatSource();
const endContents = [];
for (const fragment of keyedFragments.values()) {
concatSource.add(fragment.getContent(generateContext));
const endContent = fragment.getEndContent(generateContext);
if (endContent) {
endContents.push(endContent);
}
}
concatSource.add(source);
for (const content of endContents.reverse()) {
concatSource.add(content);
}
return concatSource;
} else {
return source;
}
}
}
InitFragment.prototype.merge = undefined;

View File

@ -42,6 +42,10 @@ class ExportsInfo {
this._redirectTo = undefined;
}
get ownedExports() {
return this._exports.values();
}
get exports() {
if (this._redirectTo) {
const map = new Map(this._redirectTo._exports);
@ -72,10 +76,6 @@ class ExportsInfo {
return this._exports.values();
}
get redirectedToDefault() {
return !!this._redirectTo;
}
get otherExportsInfo() {
if (this._redirectTo) return this._redirectTo.otherExportsInfo;
return this._otherExportsInfo;
@ -106,6 +106,8 @@ class ExportsInfo {
setRedirectToDefaultObject() {
const defaultInfo = this.getExportInfo("default");
defaultInfo.canMangleProvide = false;
defaultInfo.usedName = "";
const inner = defaultInfo.createNestedExportsInfo();
this._redirectTo = inner;
}
@ -427,17 +429,17 @@ class ExportsInfo {
if (name.length === 0) return name;
let info = this.getReadOnlyExportInfo(name[0]);
const x = info.getUsedName(name[0]);
if (!x) return false;
if (x === false) return false;
const arr = x === name[0] && name.length === 1 ? name : x ? [x] : [];
if (name.length === 1) {
if (x === name[0]) return name;
return [x];
return arr;
}
if (info.exportsInfo) {
const nested = info.exportsInfo.getUsedName(name.slice(1));
if (!nested) return false;
return [x].concat(nested);
return arr.concat(nested);
} else {
return [x].concat(name.slice(1));
return arr.concat(name.slice(1));
}
} else {
let info = this.getReadOnlyExportInfo(name);
@ -554,7 +556,8 @@ class ExportInfo {
getUsedName(fallbackName) {
if (this.used === UsageState.Unused) return false;
return this.usedName || this.name || fallbackName;
if (this.usedName !== null) return this.usedName;
return this.name || fallbackName;
}
createNestedExportsInfo() {
@ -598,6 +601,9 @@ class ExportInfo {
}
getRenameInfo() {
if (this.usedName !== null && this.usedName !== this.name) {
return this.usedName ? `renamed to ${this.usedName}` : "no name, virtual";
}
switch (this.canMangleProvide) {
case undefined:
switch (this.canMangleUse) {
@ -616,11 +622,7 @@ class ExportInfo {
case false:
return "usage prevents renaming";
case true:
if (this.usedName && this.usedName !== this.name) {
return `renamed to ${this.usedName}`;
} else {
return "can be renamed";
}
return "could be renamed";
}
break;
case false:

View File

@ -43,25 +43,15 @@ const printExportsInfoToSource = (source, indent, exportsInfo) => {
}
hasExports = true;
}
if (exportsInfo.redirectedToDefault) {
const otherExportsInfo = exportsInfo.otherExportsInfo;
if (otherExportsInfo.provided !== false || otherExportsInfo.used !== false) {
const title = hasExports ? "other exports" : "exports";
source.add(
Template.toComment(
`${indent}other exports redirect to default export children`
)
`${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]`
) + "\n"
);
} else {
const otherExportsInfo = exportsInfo.otherExportsInfo;
if (
otherExportsInfo.provided !== false ||
otherExportsInfo.used !== false
) {
const title = hasExports ? "other exports" : "exports";
source.add(
Template.toComment(
`${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]`
) + "\n"
);
}
}
};

View File

@ -5,6 +5,7 @@
"use strict";
const InitFragment = require("./InitFragment");
const RuntimeGlobals = require("./RuntimeGlobals");
const Template = require("./Template");
const propertyAccess = require("./util/propertyAccess");
@ -12,6 +13,7 @@ const propertyAccess = require("./util/propertyAccess");
/** @typedef {import("../declarations/WebpackOptions").OutputOptions} OutputOptions */
/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./InitFragment")} InitFragment */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./RequestShortener")} RequestShortener */
@ -518,14 +520,6 @@ class RuntimeTemplate {
runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
content += `/* harmony import */ ${optDeclaration}${importVar}_default = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${importVar});\n`;
}
if (exportsType === "named") {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
if (Array.isArray(chunkGraph.moduleGraph.getProvidedExports(module))) {
content += `${optDeclaration}${importVar}_namespace = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 1);\n`;
} else {
content += `${optDeclaration}${importVar}_namespace = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${moduleId});\n`;
}
}
return content;
}
@ -540,6 +534,7 @@ class RuntimeTemplate {
* @param {boolean} options.isCall true, if expression will be called
* @param {boolean} options.callContext when false, call context will not be preserved
* @param {string} options.importVar the identifier name of the import variable
* @param {InitFragment[]} options.initFragments init fragments will be added here
* @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
* @returns {string} expression
*/
@ -553,6 +548,7 @@ class RuntimeTemplate {
isCall,
callContext,
importVar,
initFragments,
runtimeRequirements
}) {
if (!module) {
@ -586,7 +582,15 @@ class RuntimeTemplate {
);
} else {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
return `/*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${importVar})`;
initFragments.push(
new InitFragment(
`var ${importVar}_namespace_cache;\n`,
InitFragment.STAGE_CONSTANTS,
-1,
`${importVar}_namespace_cache`
)
);
return `/*#__PURE__*/ (${importVar}_namespace_cache || (${importVar}_namespace_cache = ${RuntimeGlobals.createFakeNamespaceObject}(${importVar})))`;
}
}
}
@ -595,7 +599,16 @@ class RuntimeTemplate {
if (exportName.length > 0 && exportName[0] === "default") {
exportName = exportName.slice(1);
} else if (exportName.length === 0) {
return `${importVar}_namespace`;
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
initFragments.push(
new InitFragment(
`var ${importVar}_namespace_cache;\n`,
InitFragment.STAGE_CONSTANTS,
-1,
`${importVar}_namespace_cache`
)
);
return `/*#__PURE__*/ (${importVar}_namespace_cache || (${importVar}_namespace_cache = ${RuntimeGlobals.createFakeNamespaceObject}(${importVar}, 2)))`;
}
}

View File

@ -23,12 +23,13 @@ const HarmonyImportDependency = require("./HarmonyImportDependency");
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../ModuleGraph").ExportInfo} ExportInfo */
/** @typedef {import("../ModuleGraph").ExportsInfo} ExportsInfo */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("../WebpackError")} WebpackError */
/** @typedef {import("../util/Hash")} Hash */
/** @typedef {"missing"|"unused"|"empty-star"|"reexport-non-harmony-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-partial-namespace-object"|"reexport-non-harmony-default-strict"|"reexport-fake-namespace-object"|"reexport-non-harmony-undefined"|"normal-reexport"|"dynamic-reexport"} ExportModeType */
/** @typedef {"missing"|"unused"|"empty-star"|"reexport-non-harmony-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-fake-named-namespace-object"|"reexport-fake-namespace-object"|"reexport-non-harmony-undefined"|"normal-reexport"|"dynamic-reexport"} ExportModeType */
const idsSymbol = Symbol("HarmonyExportImportedSpecifierDependency.ids");
@ -38,6 +39,36 @@ const EMPTY_MAP = new Map();
/** @type {Set<string>} */
const EMPTY_SET = new Set();
/**
*
* @param {string[][]} referencedExports list of referenced exports, will be added to
* @param {string[]} prefix export prefix
* @param {ExportInfo} exportInfo the export info
*/
const processExportInfo = (referencedExports, prefix, exportInfo) => {
if (!exportInfo) {
referencedExports.push(prefix);
return;
}
if (exportInfo.used === UsageState.Unused) return;
if (
exportInfo.used !== UsageState.OnlyPropertiesUsed ||
!exportInfo.exportsInfo ||
exportInfo.exportsInfo.otherExportsInfo.used !== UsageState.Unused
) {
referencedExports.push(prefix);
return;
}
const exportsInfo = exportInfo.exportsInfo;
for (const exportInfo of exportsInfo.orderedExports) {
processExportInfo(
referencedExports,
prefix.concat(exportInfo.name),
exportInfo
);
}
};
class ExportMode {
/**
* @param {ExportModeType} type type of the mode
@ -49,14 +80,16 @@ class ExportMode {
this.name = null;
/** @type {Map<string, string[]>} */
this.map = EMPTY_MAP;
/** @type {ExportsInfo} */
this.partialNamespaceExportsInfo = undefined;
/** @type {ExportInfo} */
this.partialNamespaceExportInfo = undefined;
/** @type {Set<string>|null} */
this.ignored = null;
/** @type {Set<string>|null} */
this.checked = null;
/** @type {string|null} */
this.userRequest = null;
/** @type {number} */
this.fakeType = 0;
}
}
@ -159,36 +192,32 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
const strictHarmonyModule = parentModule.buildMeta.strictHarmonyModule;
const isNotAHarmonyModule =
importedModule.buildMeta && !importedModule.buildMeta.exportsType;
const isNamedModule =
importedModule.buildMeta &&
importedModule.buildMeta.exportsType === "named";
// Special handling for reexporting the default export
// from non-harmony modules
if (
name &&
ids.length > 0 &&
ids[0] === "default" &&
importedModule.buildMeta
) {
if (!importedModule.buildMeta.exportsType) {
const mode = new ExportMode(
strictHarmonyModule
? "reexport-non-harmony-default-strict"
: "reexport-non-harmony-default"
);
if (name && ids.length > 0 && ids[0] === "default") {
if (isNotAHarmonyModule) {
const mode = new ExportMode("reexport-non-harmony-default");
mode.name = name;
return mode;
} else if (importedModule.buildMeta.exportsType === "named") {
} else if (isNamedModule) {
const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
const mode = new ExportMode("reexport-named-default");
mode.name = name;
mode.partialNamespaceExportInfo = exportInfo;
return mode;
}
}
const isNotAHarmonyModule =
importedModule.buildMeta && !importedModule.buildMeta.exportsType;
// reexporting with a fixed name
if (name) {
let mode;
@ -209,17 +238,15 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
if (isNotAHarmonyModule && strictHarmonyModule) {
mode = new ExportMode("reexport-fake-namespace-object");
mode.name = name;
} else if (
exportInfo.used === UsageState.OnlyPropertiesUsed &&
exportInfo.exportsInfo &&
exportInfo.exportsInfo.otherExportsInfo.used === UsageState.Unused
) {
mode = new ExportMode("reexport-partial-namespace-object");
} else if (isNamedModule) {
mode = new ExportMode("reexport-fake-named-namespace-object");
mode.name = name;
mode.partialNamespaceExportsInfo = exportInfo.exportsInfo;
mode.partialNamespaceExportInfo = exportInfo;
mode.fakeType = 2;
} else {
mode = new ExportMode("reexport-namespace-object");
mode.name = name;
mode.partialNamespaceExportInfo = exportInfo;
}
}
@ -336,39 +363,40 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
case "missing":
case "unused":
case "empty-star":
case "reexport-non-harmony-undefined":
return Dependency.NO_EXPORTS_REFERENCED;
case "reexport-non-harmony-default":
case "reexport-named-default":
return Dependency.DEFAULT_EXPORT_REFERENCED;
case "reexport-partial-namespace-object": {
case "reexport-named-default": {
if (!mode.partialNamespaceExportInfo)
return Dependency.DEFAULT_EXPORT_REFERENCED;
/** @type {string[][]} */
const referencedExports = [];
const processExportsInfo = (prefix, exportsInfo) => {
for (const exportInfo of exportsInfo.orderedExports) {
if (
exportInfo.used === UsageState.OnlyPropertiesUsed &&
exportInfo.exportsInfo &&
exportInfo.exportsInfo.otherExportsInfo.used === UsageState.Unused
) {
processExportsInfo(
prefix.concat(exportInfo.name),
exportInfo.exportsInfo
);
} else if (exportInfo.used !== UsageState.Unused) {
referencedExports.push(prefix.concat(exportInfo.name));
}
}
};
processExportsInfo([], mode.partialNamespaceExportsInfo);
processExportInfo(
referencedExports,
["default"],
mode.partialNamespaceExportInfo
);
return referencedExports;
}
case "reexport-namespace-object":
case "reexport-non-harmony-default-strict":
case "reexport-fake-named-namespace-object": {
if (!mode.partialNamespaceExportInfo)
return Dependency.NS_OBJECT_REFERENCED;
/** @type {string[][]} */
const referencedExports = [];
processExportInfo(
referencedExports,
[],
mode.partialNamespaceExportInfo
);
return referencedExports;
}
case "reexport-fake-namespace-object":
case "reexport-non-harmony-undefined":
case "dynamic-reexport":
return Dependency.NS_OBJECT_REFERENCED;
@ -442,15 +470,13 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
};
case "reexport-fake-namespace-object":
case "reexport-non-harmony-default":
case "reexport-non-harmony-default-strict":
case "reexport-non-harmony-undefined":
case "reexport-named-default":
return {
exports: [mode.name],
dependencies: [moduleGraph.getModule(this)]
};
case "reexport-fake-named-namespace-object":
case "reexport-namespace-object":
case "reexport-partial-namespace-object":
return {
exports: [
{
@ -461,6 +487,17 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
],
dependencies: [moduleGraph.getModule(this)]
};
case "reexport-named-default":
return {
exports: [
{
name: mode.name,
from: moduleGraph.getModule(this),
export: ["default"]
}
],
dependencies: [moduleGraph.getModule(this)]
};
default:
throw new Error(`Unknown mode ${mode.type}`);
}
@ -648,37 +685,23 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
"reexport default from non-harmony",
module.getUsedName(moduleGraph, mode.name),
importVar,
null,
runtimeRequirements
)
);
break;
case "reexport-named-default":
initFragments.push(
this.getReexportFragment(
module,
"reexport default from named exports",
module.getUsedName(moduleGraph, mode.name),
importVar,
"",
module.buildMeta && module.buildMeta.strictHarmonyModule
? ""
: null,
runtimeRequirements
)
);
break;
case "reexport-fake-namespace-object":
case "reexport-fake-named-namespace-object":
initFragments.push(
new InitFragment(
"/* harmony reexport (fake namespace object from non-harmony) */ " +
this.getReexportFakeNamespaceObjectStatement(
module,
module.getUsedName(moduleGraph, mode.name),
importVar,
runtimeRequirements
),
InitFragment.STAGE_HARMONY_EXPORTS,
1
...this.getReexportFakeNamespaceObjectFragments(
module,
module.getUsedName(moduleGraph, mode.name),
importVar,
mode.fakeType,
runtimeRequirements
)
);
break;
@ -696,11 +719,11 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
);
break;
case "reexport-non-harmony-default-strict":
case "reexport-named-default":
initFragments.push(
this.getReexportFragment(
module,
"reexport default from non-harmony",
"reexport default export from named module",
module.getUsedName(moduleGraph, mode.name),
importVar,
"",
@ -710,7 +733,6 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
break;
case "reexport-namespace-object":
case "reexport-partial-namespace-object":
initFragments.push(
this.getReexportFragment(
module,
@ -824,23 +846,34 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
return new HarmonyExportInitFragment(module.exportsArgument, map);
}
getReexportFakeNamespaceObjectStatement(
getReexportFakeNamespaceObjectFragments(
module,
key,
name,
fakeType,
runtimeRequirements
) {
const exportsName = module.exportsArgument;
runtimeRequirements.add(RuntimeGlobals.exports);
runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
return `${
RuntimeGlobals.definePropertyGetters
}(${exportsName}, { ${JSON.stringify(key)}: function() { return ${
RuntimeGlobals.createFakeNamespaceObject
}(${name}); } });\n`;
const map = new Map();
map.set(
key,
`/* reexport fake namespace object from non-harmony */ ${name}_namespace_cache || (${name}_namespace_cache = ${
RuntimeGlobals.createFakeNamespaceObject
}(${name}${fakeType ? `, ${fakeType}` : ""}))`
);
return [
new InitFragment(
`var ${name}_namespace_cache;\n`,
InitFragment.STAGE_CONSTANTS,
-1,
`${name}_namespace_cache`
),
new HarmonyExportInitFragment(module.exportsArgument, map)
];
}
getConditionalReexportStatement(

View File

@ -229,7 +229,13 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
super.apply(dependency, source, templateContext);
const { runtimeTemplate, module, runtimeRequirements } = templateContext;
const {
runtimeTemplate,
module,
initFragments,
runtimeRequirements
} = templateContext;
const ids = dep.getIds(moduleGraph);
const exportExpr = runtimeTemplate.exportFromImport({
moduleGraph,
@ -241,6 +247,7 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
isCall: dep.call,
callContext: !dep.directImport,
importVar: dep.getImportVar(moduleGraph),
initFragments,
runtimeRequirements
});
if (dep.shorthand) {

View File

@ -59,7 +59,12 @@ class JsonExportsDependency extends NullDependency {
*/
getExports(moduleGraph) {
return {
exports: this.exports,
exports: [
{
name: "default",
exports: this.exports
}
],
dependencies: undefined
};
}

View File

@ -6,15 +6,15 @@
"use strict";
const util = require("util");
const { ConcatSource, RawSource, ReplaceSource } = require("webpack-sources");
const { RawSource, ReplaceSource } = require("webpack-sources");
const Generator = require("../Generator");
const InitFragment = require("../InitFragment");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../DependenciesBlock")} DependenciesBlock */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
/** @typedef {import("../InitFragment")} InitFragment */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
@ -28,26 +28,6 @@ const deprecatedGetInitFragments = util.deprecate(
"DependencyTemplate.getInitFragment is deprecated (use apply(dep, source, { initFragments }) instead)"
);
/**
* @param {InitFragment} fragment the init fragment
* @param {number} index index
* @returns {[InitFragment, number]} tuple with both
*/
const extractFragmentIndex = (fragment, index) => [fragment, index];
/**
* @param {[InitFragment, number]} a first pair
* @param {[InitFragment, number]} b second pair
* @returns {number} sort value
*/
const sortFragmentWithIndex = ([a, i], [b, j]) => {
const stageCmp = a.stage - b.stage;
if (stageCmp !== 0) return stageCmp;
const positionCmp = a.position - b.position;
if (positionCmp !== 0) return positionCmp;
return i - j;
};
const TYPES = new Set(["javascript"]);
class JavascriptGenerator extends Generator {
@ -87,47 +67,7 @@ class JavascriptGenerator extends Generator {
this.sourceModule(module, initFragments, source, generateContext);
if (initFragments.length > 0) {
// Sort fragments by position. If 2 fragments have the same position,
// use their index.
const sortedFragments = initFragments
.map(extractFragmentIndex)
.sort(sortFragmentWithIndex);
// Deduplicate fragments. If a fragment has no key, it is always included.
const keyedFragments = new Map();
for (const [fragment] of sortedFragments) {
if (typeof fragment.merge === "function") {
const oldValue = keyedFragments.get(fragment.key);
if (oldValue !== undefined) {
keyedFragments.set(
fragment.key || Symbol(),
fragment.merge(oldValue)
);
continue;
}
}
keyedFragments.set(fragment.key || Symbol(), fragment);
}
const concatSource = new ConcatSource();
const endContents = [];
for (const fragment of keyedFragments.values()) {
concatSource.add(fragment.getContent(generateContext));
const endContent = fragment.getEndContent(generateContext);
if (endContent) {
endContents.push(endContent);
}
}
concatSource.add(source);
for (const content of endContents.reverse()) {
concatSource.add(content);
}
return concatSource;
} else {
return source;
}
return InitFragment.addToSource(source, initFragments, generateContext);
}
/**

View File

@ -109,9 +109,14 @@ class JsonGenerator extends Generator {
}
runtimeRequirements.add(RuntimeGlobals.module);
const exportsInfo = moduleGraph.getExportsInfo(module);
const defaultExportInfo = exportsInfo.getExportInfo("default");
let finalJson =
typeof data === "object" && data
? createObjectForExportsInfo(data, exportsInfo)
typeof data === "object" &&
data &&
exportsInfo.otherExportsInfo.used === UsageState.Unused &&
(defaultExportInfo.used === UsageState.Unused ||
defaultExportInfo.used === UsageState.OnlyPropertiesUsed)
? createObjectForExportsInfo(data, defaultExportInfo.exportsInfo)
: data;
// Use JSON because JSON.parse() is much faster than JavaScript evaluation
const jsonStr = stringifySafe(finalJson);

View File

@ -57,7 +57,7 @@ const mangleExportsInfo = (exportsInfo, canBeArray) => {
const usedNames = new Set();
const mangleableExports = [];
// Don't rename 1-2 char exports or exports that can't be mangled
for (const exportInfo of exportsInfo.exports) {
for (const exportInfo of exportsInfo.ownedExports) {
const name = exportInfo.name;
if (
exportInfo.canMangle !== true ||

View File

@ -36,16 +36,18 @@ class CreateFakeNamespaceObjectRuntimeModule extends HelperRuntimeModule {
"if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;",
"var ns = Object.create(null);",
`${RuntimeGlobals.makeNamespaceObject}(ns);`,
"Object.defineProperty(ns, 'default', { enumerable: true, value: value });",
"if(mode & 2 && typeof value != 'string') {",
"var def = {};",
"if(mode & 2 && typeof value == 'object' && value) {",
Template.indent([
"var def = {};",
modern
? `for(const key in value) def[key] = () => value[key];`
: `for(var key in value) def[key] = function(key) { return value[key]; }.bind(null, key);`,
`${RuntimeGlobals.definePropertyGetters}(ns, def);`
: `for(var key in value) def[key] = function(key) { return value[key]; }.bind(null, key);`
]),
"}",
modern
? "def['default'] = () => value;"
: "def['default'] = function() { return value; };",
`${RuntimeGlobals.definePropertyGetters}(ns, def);`,
"return ns;"
]),
"};"

View File

@ -7,6 +7,7 @@
const { RawSource } = require("webpack-sources");
const Generator = require("../Generator");
const InitFragment = require("../InitFragment");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
@ -46,13 +47,18 @@ class AsyncWebAssemblyJavascriptGenerator extends Generator {
* @param {GenerateContext} generateContext context for generate
* @returns {Source} generated code
*/
generate(
module,
{ runtimeTemplate, chunkGraph, moduleGraph, runtimeRequirements }
) {
generate(module, generateContext) {
const {
runtimeTemplate,
chunkGraph,
moduleGraph,
runtimeRequirements
} = generateContext;
runtimeRequirements.add(RuntimeGlobals.module);
runtimeRequirements.add(RuntimeGlobals.exports);
runtimeRequirements.add(RuntimeGlobals.instantiateWasm);
/** @type {InitFragment[]} */
const initFragments = [];
/** @type {Map<Module, { request: string, importVar: string }>} */
const depModules = new Map();
/** @type {Map<string, WebAssemblyImportDependency[]>} */
@ -113,6 +119,7 @@ class AsyncWebAssemblyJavascriptGenerator extends Generator {
isCall: false,
callContext: false,
importVar,
initFragments,
runtimeRequirements
})}`;
});
@ -137,7 +144,7 @@ class AsyncWebAssemblyJavascriptGenerator extends Generator {
`${RuntimeGlobals.instantiateWasm}(${module.exportsArgument}, ${module.moduleArgument}.i` +
(importsObj ? `, ${importsObj})` : `)`);
return new RawSource(
const source = new RawSource(
Template.asString([
...importStatements,
promises.length > 1
@ -153,6 +160,7 @@ class AsyncWebAssemblyJavascriptGenerator extends Generator {
: `${module.moduleArgument}.exports = ${instantiateCall}`
])
);
return InitFragment.addToSource(source, initFragments, generateContext);
}
}

View File

@ -7,6 +7,7 @@
const { RawSource } = require("webpack-sources");
const Generator = require("../Generator");
const InitFragment = require("../InitFragment");
const { UsageState } = require("../ModuleGraph");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
@ -43,10 +44,16 @@ class WebAssemblyJavascriptGenerator extends Generator {
* @param {GenerateContext} generateContext context for generate
* @returns {Source} generated code
*/
generate(
module,
{ runtimeTemplate, moduleGraph, chunkGraph, runtimeRequirements }
) {
generate(module, generateContext) {
const {
runtimeTemplate,
moduleGraph,
chunkGraph,
runtimeRequirements
} = generateContext;
/** @type {InitFragment[]} */
const initFragments = [];
const exportsInfo = moduleGraph.getExportsInfo(module);
let needExportsCopy = false;
@ -92,6 +99,7 @@ class WebAssemblyJavascriptGenerator extends Generator {
asiSafe: true,
isCall: false,
callContext: null,
initFragments,
runtimeRequirements
})
);
@ -118,6 +126,7 @@ class WebAssemblyJavascriptGenerator extends Generator {
asiSafe: true,
isCall: false,
callContext: null,
initFragments,
runtimeRequirements
})};`,
`if(WebAssembly.Global) ${exportProp} = ` +
@ -188,7 +197,7 @@ class WebAssemblyJavascriptGenerator extends Generator {
`wasmExports[""](${initParams.join(", ")})`
].join("\n")
);
return source;
return InitFragment.addToSource(source, initFragments, generateContext);
}
}

View File

@ -217,10 +217,10 @@ describe("Stats", () => {
"comparedForEmit": false,
"emitted": true,
"info": Object {
"size": 2085,
"size": 2044,
},
"name": "entryB.js",
"size": 2085,
"size": 2044,
},
],
"assetsByChunkName": Object {

View File

@ -1,19 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StatsTestCases should print correct stats for aggressive-splitting-entry 1`] = `
"Hash: 21902312560238912c7e45ec1b9983d1c74bd8c5
"Hash: dcb48044a6d829f78b2f94bb5baec139b60ce84b
Child fitting:
Hash: 21902312560238912c7e
Hash: dcb48044a6d829f78b2f
Time: Xms
Built at: 1970-04-20 12:42:42
PublicPath: (none)
Asset Size
fitting-07302ed1a3c05122e3f9.js 13 KiB [emitted] [immutable]
fitting-35bda92cf5ea05aff412.js 1.91 KiB [emitted] [immutable]
fitting-3e4894c38178f8515f2a.js 1.91 KiB [emitted] [immutable]
fitting-b8fb2489c906e1a6d3ea.js 12.9 KiB [emitted] [immutable]
fitting-dc9eb8f6a8dc6829a3ce.js 1.08 KiB [emitted] [immutable]
Entrypoint main = fitting-35bda92cf5ea05aff412.js fitting-3e4894c38178f8515f2a.js fitting-07302ed1a3c05122e3f9.js
chunk fitting-07302ed1a3c05122e3f9.js 1.87 KiB (javascript) 6.51 KiB (runtime) [entry] [rendered]
Entrypoint main = fitting-35bda92cf5ea05aff412.js fitting-3e4894c38178f8515f2a.js fitting-b8fb2489c906e1a6d3ea.js
chunk fitting-b8fb2489c906e1a6d3ea.js 1.87 KiB (javascript) 6.47 KiB (runtime) [entry] [rendered]
> ./index main
./e.js 899 bytes [built]
./f.js 900 bytes [built]
@ -31,17 +31,17 @@ Child fitting:
> ./g ./index.js 7:0-13
./g.js 916 bytes [built]
Child content-change:
Hash: 45ec1b9983d1c74bd8c5
Hash: 94bb5baec139b60ce84b
Time: Xms
Built at: 1970-04-20 12:42:42
PublicPath: (none)
Asset Size
content-change-35bda92cf5ea05aff412.js 1.91 KiB [emitted] [immutable]
content-change-3e4894c38178f8515f2a.js 1.91 KiB [emitted] [immutable]
content-change-d60032b193fdb4bf4c38.js 13 KiB [emitted] [immutable]
content-change-7060932af3a1be0512be.js 12.9 KiB [emitted] [immutable]
content-change-dc9eb8f6a8dc6829a3ce.js 1.08 KiB [emitted] [immutable]
Entrypoint main = content-change-35bda92cf5ea05aff412.js content-change-3e4894c38178f8515f2a.js content-change-d60032b193fdb4bf4c38.js
chunk content-change-d60032b193fdb4bf4c38.js 1.87 KiB (javascript) 6.51 KiB (runtime) [entry] [rendered]
Entrypoint main = content-change-35bda92cf5ea05aff412.js content-change-3e4894c38178f8515f2a.js content-change-7060932af3a1be0512be.js
chunk content-change-7060932af3a1be0512be.js 1.87 KiB (javascript) 6.48 KiB (runtime) [entry] [rendered]
> ./index main
./e.js 899 bytes [built]
./f.js 900 bytes [built]
@ -559,7 +559,7 @@ exports[`StatsTestCases should print correct stats for circular-correctness 1`]
"Entrypoint main = bundle.js
chunk 128.bundle.js (b) 49 bytes <{179}> <{459}> >{459}< [rendered]
./module-b.js 49 bytes [built]
chunk bundle.js (main) 98 bytes (javascript) 5.54 KiB (runtime) >{128}< >{786}< [entry] [rendered]
chunk bundle.js (main) 98 bytes (javascript) 5.51 KiB (runtime) >{128}< >{786}< [entry] [rendered]
./index.js 98 bytes [built]
+ 7 hidden chunk modules
chunk 459.bundle.js (c) 98 bytes <{128}> <{786}> >{128}< >{786}< [rendered]
@ -1014,7 +1014,7 @@ Entrypoint e2 = e2.js
chunk b.js (b) 49 bytes <{786}> >{459}< [rendered]
./module-b.js 49 bytes [built]
import() ./module-b ./module-a.js 1:0-47
chunk e1.js (e1) 49 bytes (javascript) 5.57 KiB (runtime) >{786}< [entry] [rendered]
chunk e1.js (e1) 49 bytes (javascript) 5.53 KiB (runtime) >{786}< [entry] [rendered]
./e1.js 49 bytes [built]
entry ./e1 e1
+ 7 hidden chunk modules
@ -1022,7 +1022,7 @@ chunk c.js (c) 49 bytes <{128}> <{621}> >{786}< [rendered]
./module-c.js 49 bytes [built]
import() ./module-c ./e2.js 1:0-47
import() ./module-c ./module-b.js 1:0-47
chunk e2.js (e2) 49 bytes (javascript) 5.57 KiB (runtime) >{459}< [entry] [rendered]
chunk e2.js (e2) 49 bytes (javascript) 5.53 KiB (runtime) >{459}< [entry] [rendered]
./e2.js 49 bytes [built]
entry ./e2 e2
+ 7 hidden chunk modules
@ -1038,7 +1038,7 @@ Entrypoint e2 = e2.js
chunk b.js (b) 179 bytes <{786}> >{459}< [rendered]
./module-b.js 179 bytes [built]
import() ./module-b ./module-a.js 1:0-47
chunk e1.js (e1) 119 bytes (javascript) 5.83 KiB (runtime) >{786}< >{892}< [entry] [rendered]
chunk e1.js (e1) 119 bytes (javascript) 5.8 KiB (runtime) >{786}< >{892}< [entry] [rendered]
./e1.js 70 bytes [built]
entry ./e1 e1
./module-x.js 49 bytes [built]
@ -1050,7 +1050,7 @@ chunk c.js (c) 49 bytes <{128}> <{621}> >{786}< [rendered]
./module-c.js 49 bytes [built]
import() ./module-c ./e2.js 2:0-47
import() ./module-c ./module-b.js 1:0-47
chunk e2.js (e2) 119 bytes (javascript) 5.83 KiB (runtime) >{459}< >{892}< [entry] [rendered]
chunk e2.js (e2) 119 bytes (javascript) 5.8 KiB (runtime) >{459}< >{892}< [entry] [rendered]
./e2.js 70 bytes [built]
entry ./e2 e2
./module-x.js 49 bytes [built]
@ -1088,7 +1088,7 @@ chunk id-equals-name_js0.js 1 bytes [rendered]
./id-equals-name.js 1 bytes [built]
chunk id-equals-name_js_3.js 1 bytes [rendered]
./id-equals-name.js?3 1 bytes [built]
chunk main.js (main) 639 bytes (javascript) 5.79 KiB (runtime) [entry] [rendered]
chunk main.js (main) 639 bytes (javascript) 5.76 KiB (runtime) [entry] [rendered]
./index.js 639 bytes [built]
+ 8 hidden root modules
chunk tree.js (tree) 43 bytes [rendered]
@ -1104,7 +1104,7 @@ chunk trees.js (trees) 71 bytes [rendered]
exports[`StatsTestCases should print correct stats for immutable 1`] = `
" Asset Size
73f0dbd7f9b6bc12ec24.js 346 bytes [emitted] [immutable]
81de2a32c0bb38e2e74d.js 9.84 KiB [emitted] [immutable] [name: main]"
81de2a32c0bb38e2e74d.js 9.8 KiB [emitted] [immutable] [name: main]"
`;
exports[`StatsTestCases should print correct stats for import-context-filter 1`] = `
@ -1126,7 +1126,7 @@ Entrypoint entry = entry.js
`;
exports[`StatsTestCases should print correct stats for import-weak 1`] = `
"Hash: 331add5bed128b8485a0
"Hash: 8415d4493647c97a7e9c
Time: Xms
Built at: 1970-04-20 12:42:42
Asset Size
@ -1206,15 +1206,15 @@ Child
`;
exports[`StatsTestCases should print correct stats for limit-chunk-count-plugin 1`] = `
"Hash: c7ab81b382a08cbcc14a48d656dd0e4d092385e82f44f1ecdeec3f687c76b6d99d39e209345b04bb
"Hash: f5c099d74f0077345675321508a5123dcef8960d572596c9eac20b26c30a21f15bbd6226ddb32d62
Child 1 chunks:
Hash: c7ab81b382a08cbcc14a
Hash: f5c099d74f0077345675
Time: Xms
Built at: 1970-04-20 12:42:42
Asset Size
bundle1.js 4.1 KiB [emitted] [name: main]
Asset Size
bundle1.js 4.07 KiB [emitted] [name: main]
Entrypoint main = bundle1.js
chunk bundle1.js (main) 219 bytes (javascript) 1.32 KiB (runtime) <{179}> >{179}< [entry] [rendered]
chunk bundle1.js (main) 219 bytes (javascript) 1.28 KiB (runtime) <{179}> >{179}< [entry] [rendered]
./a.js 22 bytes [built]
./b.js 22 bytes [built]
./c.js 30 bytes [built]
@ -1223,14 +1223,14 @@ Child 1 chunks:
./index.js 101 bytes [built]
+ 3 hidden chunk modules
Child 2 chunks:
Hash: 48d656dd0e4d092385e8
Hash: 321508a5123dcef8960d
Time: Xms
Built at: 1970-04-20 12:42:42
Asset Size
459.bundle2.js 666 bytes [emitted] [name: c]
bundle2.js 9.77 KiB [emitted] [name: main]
bundle2.js 9.74 KiB [emitted] [name: main]
Entrypoint main = bundle2.js
chunk bundle2.js (main) 101 bytes (javascript) 5.54 KiB (runtime) >{459}< [entry] [rendered]
chunk bundle2.js (main) 101 bytes (javascript) 5.51 KiB (runtime) >{459}< [entry] [rendered]
./index.js 101 bytes [built]
+ 7 hidden chunk modules
chunk 459.bundle2.js (c) 118 bytes <{179}> <{459}> >{459}< [rendered]
@ -1240,15 +1240,15 @@ Child 2 chunks:
./d.js 22 bytes [built]
./e.js 22 bytes [built]
Child 3 chunks:
Hash: 2f44f1ecdeec3f687c76
Hash: 572596c9eac20b26c30a
Time: Xms
Built at: 1970-04-20 12:42:42
Asset Size
459.bundle3.js 530 bytes [emitted] [name: c]
524.bundle3.js 210 bytes [emitted]
bundle3.js 9.77 KiB [emitted] [name: main]
bundle3.js 9.74 KiB [emitted] [name: main]
Entrypoint main = bundle3.js
chunk bundle3.js (main) 101 bytes (javascript) 5.54 KiB (runtime) >{459}< [entry] [rendered]
chunk bundle3.js (main) 101 bytes (javascript) 5.51 KiB (runtime) >{459}< [entry] [rendered]
./index.js 101 bytes [built]
+ 7 hidden chunk modules
chunk 459.bundle3.js (c) 74 bytes <{179}> >{524}< [rendered]
@ -1259,16 +1259,16 @@ Child 3 chunks:
./d.js 22 bytes [built]
./e.js 22 bytes [built]
Child 4 chunks:
Hash: b6d99d39e209345b04bb
Hash: 21f15bbd6226ddb32d62
Time: Xms
Built at: 1970-04-20 12:42:42
Asset Size
394.bundle4.js 210 bytes [emitted]
459.bundle4.js 394 bytes [emitted] [name: c]
524.bundle4.js 210 bytes [emitted]
bundle4.js 9.77 KiB [emitted] [name: main]
bundle4.js 9.74 KiB [emitted] [name: main]
Entrypoint main = bundle4.js
chunk bundle4.js (main) 101 bytes (javascript) 5.54 KiB (runtime) >{394}< >{459}< [entry] [rendered]
chunk bundle4.js (main) 101 bytes (javascript) 5.51 KiB (runtime) >{394}< >{459}< [entry] [rendered]
./index.js 101 bytes [built]
+ 7 hidden chunk modules
chunk 394.bundle4.js 44 bytes <{179}> [rendered]
@ -1666,11 +1666,11 @@ Entrypoint entry = vendor.js entry.js
`;
exports[`StatsTestCases should print correct stats for named-chunks-plugin-async 1`] = `
"Hash: 36e5f0124c21277a1478
"Hash: b099e52fe30f7dabb228
Time: Xms
Built at: 1970-04-20 12:42:42
Asset Size
entry.js 9.64 KiB [emitted] [name: entry]
entry.js 9.6 KiB [emitted] [name: entry]
modules_a_js.js 316 bytes [emitted]
modules_b_js.js 153 bytes [emitted]
Entrypoint entry = entry.js
@ -2001,14 +2001,14 @@ exports[`StatsTestCases should print correct stats for prefetch 1`] = `
" Asset Size
inner.js 114 bytes [emitted] [name: inner]
inner2.js 154 bytes [emitted] [name: inner2]
main.js 12.3 KiB [emitted] [name: main]
main.js 12.2 KiB [emitted] [name: main]
normal.js 113 bytes [emitted] [name: normal]
prefetched.js 572 bytes [emitted] [name: prefetched]
prefetched2.js 114 bytes [emitted] [name: prefetched2]
prefetched3.js 114 bytes [emitted] [name: prefetched3]
Entrypoint main = main.js (prefetch: prefetched2.js prefetched.js prefetched3.js)
chunk normal.js (normal) 1 bytes <{179}> [rendered]
chunk main.js (main) 436 bytes (javascript) 6.63 KiB (runtime) >{30}< >{220}< >{379}< >{505}< (prefetch: {379} {505} {220}) [entry] [rendered]
chunk main.js (main) 436 bytes (javascript) 6.59 KiB (runtime) >{30}< >{220}< >{379}< >{505}< (prefetch: {379} {505} {220}) [entry] [rendered]
chunk prefetched3.js (prefetched3) 1 bytes <{179}> [rendered]
chunk prefetched2.js (prefetched2) 1 bytes <{179}> [rendered]
chunk prefetched.js (prefetched) 228 bytes <{179}> >{641}< >{746}< (prefetch: {641} {746}) [rendered]
@ -2023,7 +2023,7 @@ chunk c1.js (c1) 1 bytes <{459}> [rendered]
chunk b.js (b) 203 bytes <{179}> >{132}< >{751}< >{978}< (prefetch: {751} {132}) (preload: {978}) [rendered]
chunk b3.js (b3) 1 bytes <{128}> [rendered]
chunk a2.js (a2) 1 bytes <{786}> [rendered]
chunk main.js (main) 195 bytes (javascript) 7.06 KiB (runtime) >{128}< >{459}< >{786}< (prefetch: {786} {128} {459}) [entry] [rendered]
chunk main.js (main) 195 bytes (javascript) 7.02 KiB (runtime) >{128}< >{459}< >{786}< (prefetch: {786} {128} {459}) [entry] [rendered]
chunk c.js (c) 134 bytes <{179}> >{3}< >{76}< (preload: {76} {3}) [rendered]
chunk b1.js (b1) 1 bytes <{128}> [rendered]
chunk a.js (a) 136 bytes <{179}> >{74}< >{178}< (prefetch: {74} {178}) [rendered]
@ -2034,14 +2034,14 @@ exports[`StatsTestCases should print correct stats for preload 1`] = `
" Asset Size
inner.js 114 bytes [emitted] [name: inner]
inner2.js 154 bytes [emitted] [name: inner2]
main.js 11.9 KiB [emitted] [name: main]
main.js 11.8 KiB [emitted] [name: main]
normal.js 113 bytes [emitted] [name: normal]
preloaded.js 557 bytes [emitted] [name: preloaded]
preloaded2.js 113 bytes [emitted] [name: preloaded2]
preloaded3.js 112 bytes [emitted] [name: preloaded3]
Entrypoint main = main.js (preload: preloaded2.js preloaded.js preloaded3.js)
chunk normal.js (normal) 1 bytes [rendered]
chunk main.js (main) 424 bytes (javascript) 6.56 KiB (runtime) (preload: {363} {851} {355}) [entry] [rendered]
chunk main.js (main) 424 bytes (javascript) 6.53 KiB (runtime) (preload: {363} {851} {355}) [entry] [rendered]
chunk preloaded3.js (preloaded3) 1 bytes [rendered]
chunk preloaded2.js (preloaded2) 1 bytes [rendered]
chunk inner2.js (inner2) 2 bytes [rendered]

View File

@ -1,7 +1,4 @@
import { e, f } from "./reexport";
import { e as e2, f as f2 } from "./reexport?1";
import("./reexport?1");
import { e, f, fNamed, fStar, fStarPartial, fStarPartial2 } from "./reexport";
it("should be possible to reexport json data", function() {
expect(e.aa).toBe(1);
@ -11,4 +8,15 @@ it("should be possible to reexport json data", function() {
default: "default",
__esModule: true
});
expect(fNamed).toBe("named");
const _fStar = fStar;
expect(_fStar).toEqual(
nsObj({
named: "named",
default: { named: "named", default: "default", __esModule: true }
})
);
expect(_fStar.__esModule).toBe(true);
expect(fStarPartial.default.named).toBe("named");
expect(fStarPartial2.named).toBe("named");
});

View File

@ -1,2 +1,9 @@
export { default as e } from "../data/e.json";
export { default as f } from "../data/f.json";
export { default as f } from "../data/f.json?default-exported";
export { named as fNamed } from "../data/f.json?only-named-exported";
import * as fStar from "../data/f.json?namespace-object-exported";
export { fStar };
import * as fStarPartial from "../data/f.json?namespace-object-exported-but-only-default-named-used";
export { fStarPartial };
import * as fStarPartial2 from "../data/f.json?namespace-object-exported-but-only-named-used";
export { fStarPartial2 };

View File

@ -0,0 +1,5 @@
module.exports = [
[
/Can't import the named export 'named' \(reexported as 'fNamed'\) from JSON module \(only default export is available\)/
]
];