webpack/lib/dependencies/HarmonyExportImportedSpecif...

1046 lines
28 KiB
JavaScript
Raw Normal View History

/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2018-07-30 23:08:51 +08:00
"use strict";
2018-04-04 15:17:10 +08:00
const Dependency = require("../Dependency");
const { UsageState } = require("../ExportsInfo");
const HarmonyLinkingError = require("../HarmonyLinkingError");
const InitFragment = require("../InitFragment");
const RuntimeGlobals = require("../RuntimeGlobals");
2018-07-30 23:08:51 +08:00
const Template = require("../Template");
const makeSerializable = require("../util/makeSerializable");
const propertyAccess = require("../util/propertyAccess");
const HarmonyExportInitFragment = require("./HarmonyExportInitFragment");
const HarmonyImportDependency = require("./HarmonyImportDependency");
const processExportInfo = require("./processExportInfo");
2018-07-27 17:45:12 +08:00
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
2018-07-30 23:08:51 +08:00
/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
/** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../ExportsInfo")} ExportsInfo */
/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
/** @typedef {import("../Module")} Module */
2018-07-17 22:42:05 +08:00
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
2018-07-25 15:33:48 +08:00
/** @typedef {import("../WebpackError")} WebpackError */
2019-07-17 22:02:33 +08:00
/** @typedef {import("../util/Hash")} Hash */
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
/** @typedef {"missing"|"unused"|"empty-star"|"reexport-dynamic-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-fake-namespace-object"|"reexport-undefined"|"normal-reexport"|"dynamic-reexport"} ExportModeType */
const idsSymbol = Symbol("HarmonyExportImportedSpecifierDependency.ids");
2020-07-07 03:39:54 +08:00
class NormalReexportItem {
/**
* @param {string} name export name
* @param {string[]} ids reexported ids from other module
* @param {ExportInfo=} exportInfo export info from other module
* @param {boolean=} checked true, if it should be checked at runtime if this export exists
2020-07-07 03:39:54 +08:00
*/
constructor(name, ids, exportInfo, checked) {
this.name = name;
this.ids = ids;
this.exportInfo = exportInfo;
this.checked = checked;
}
}
2018-04-04 15:50:35 +08:00
class ExportMode {
/**
* @param {ExportModeType} type type of the mode
*/
2018-04-04 15:50:35 +08:00
constructor(type) {
/** @type {ExportModeType} */
2018-04-04 15:50:35 +08:00
this.type = type;
2020-07-07 03:39:54 +08:00
// for "normal-reexport":
/** @type {NormalReexportItem[] | null} */
this.items = null;
// for "reexport-named-default" | "reexport-fake-namespace-object" | "reexport-namespace-object"
/** @type {string|null} */
2018-04-04 15:50:35 +08:00
this.name = null;
2020-07-07 03:39:54 +08:00
/** @type {ExportInfo | null} */
this.partialNamespaceExportInfo = null;
// for "dynamic-reexport":
/** @type {Set<string> | null} */
this.ignored = null;
2020-07-07 03:39:54 +08:00
// for "missing":
/** @type {string | null} */
2018-04-04 15:50:35 +08:00
this.userRequest = null;
2020-07-07 03:39:54 +08:00
// for "reexport-fake-namespace-object":
/** @type {number} */
this.fakeType = 0;
2018-04-04 15:50:35 +08:00
}
}
class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
/**
* @param {string} request the request string
* @param {number} sourceOrder the order in the original source file
* @param {string[]} ids the requested export name of the imported module
* @param {string | null} name the export name of for this module
* @param {Set<string>} activeExports other named exports in the module
* @param {Iterable<HarmonyExportImportedSpecifierDependency>} otherStarExports other star exports in the module
* @param {boolean} strictExportPresence when true, missing exports in the imported module lead to errors instead of warnings
*/
2018-02-25 09:00:20 +08:00
constructor(
request,
sourceOrder,
ids,
2018-02-25 09:00:20 +08:00
name,
activeExports,
otherStarExports,
strictExportPresence
) {
super(request, sourceOrder);
this.ids = ids;
this.name = name;
this.activeExports = activeExports;
this.otherStarExports = otherStarExports;
this.strictExportPresence = strictExportPresence;
}
// TODO webpack 6 remove
get id() {
throw new Error("id was renamed to ids and type changed to string[]");
}
// TODO webpack 6 remove
getId() {
throw new Error("id was renamed to ids and type changed to string[]");
}
// TODO webpack 6 remove
setId() {
throw new Error("id was renamed to ids and type changed to string[]");
}
get type() {
return "harmony export imported specifier";
}
2019-05-20 20:46:31 +08:00
/**
* @param {ModuleGraph} moduleGraph the module graph
* @returns {string[]} the imported id
2019-05-20 20:46:31 +08:00
*/
getIds(moduleGraph) {
return moduleGraph.getMeta(this)[idsSymbol] || this.ids;
2019-05-20 20:46:31 +08:00
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @param {string[]} ids the imported ids
2019-05-20 20:46:31 +08:00
* @returns {void}
*/
setIds(moduleGraph, ids) {
moduleGraph.getMeta(this)[idsSymbol] = ids;
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @param {RuntimeSpec} runtime the runtime
* @returns {ExportMode} the export mode
*/
getMode(moduleGraph, runtime) {
const name = this.name;
const ids = this.getIds(moduleGraph);
const parentModule = moduleGraph.getParentModule(this);
const importedModule = moduleGraph.getModule(this);
const exportsInfo = moduleGraph.getExportsInfo(parentModule);
2018-02-25 09:00:20 +08:00
if (!importedModule) {
2018-04-04 15:50:35 +08:00
const mode = new ExportMode("missing");
2018-04-04 15:50:35 +08:00
mode.userRequest = this.userRequest;
2018-04-04 15:50:35 +08:00
return mode;
}
if (
name
? exportsInfo.getUsed(name, runtime) === UsageState.Unused
: exportsInfo.isUsed(runtime) === false
) {
2018-04-04 15:50:35 +08:00
const mode = new ExportMode("unused");
2018-04-04 15:50:35 +08:00
mode.name = name || "*";
2018-04-04 15:50:35 +08:00
return mode;
}
const importedExportsType = importedModule.getExportsType(
moduleGraph,
parentModule.buildMeta.strictHarmonyModule
);
// Special handling for reexporting the default export
// from non-namespace modules
if (name && ids.length > 0 && ids[0] === "default") {
switch (importedExportsType) {
case "dynamic": {
const mode = new ExportMode("reexport-dynamic-default");
mode.name = name;
return mode;
}
case "default-only":
case "default-with-named": {
const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
const mode = new ExportMode("reexport-named-default");
mode.name = name;
mode.partialNamespaceExportInfo = exportInfo;
return mode;
}
}
}
// reexporting with a fixed name
2018-02-25 09:00:20 +08:00
if (name) {
2018-04-04 15:50:35 +08:00
let mode;
const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
if (ids.length > 0) {
2018-04-04 15:50:35 +08:00
// export { name as name }
switch (importedExportsType) {
case "default-only":
mode = new ExportMode("reexport-undefined");
mode.name = name;
break;
default:
mode = new ExportMode("normal-reexport");
2020-07-07 03:39:54 +08:00
mode.items = [new NormalReexportItem(name, ids, exportInfo, false)];
break;
}
} else {
// export * as name
switch (importedExportsType) {
case "default-only":
mode = new ExportMode("reexport-fake-namespace-object");
mode.name = name;
mode.partialNamespaceExportInfo = exportInfo;
mode.fakeType = 0;
break;
case "default-with-named":
mode = new ExportMode("reexport-fake-namespace-object");
mode.name = name;
mode.partialNamespaceExportInfo = exportInfo;
mode.fakeType = 2;
break;
case "dynamic":
default:
mode = new ExportMode("reexport-namespace-object");
mode.name = name;
mode.partialNamespaceExportInfo = exportInfo;
2018-04-04 15:50:35 +08:00
}
}
2018-04-04 15:50:35 +08:00
return mode;
}
// Star reexporting
const { ignoredExports, exports, checked } = this.getStarReexports(
moduleGraph,
runtime,
exportsInfo,
importedModule
);
if (!exports) {
// We have too few info about the modules
// Delegate the logic to the runtime code
const mode = new ExportMode("dynamic-reexport");
mode.ignored = ignoredExports;
return mode;
}
if (exports.size === 0) {
const mode = new ExportMode("empty-star");
return mode;
}
const mode = new ExportMode("normal-reexport");
2020-07-07 03:39:54 +08:00
mode.items = Array.from(
exports,
exportName =>
new NormalReexportItem(
exportName,
[exportName],
exportsInfo.getReadOnlyExportInfo(exportName),
checked.has(exportName)
)
);
return mode;
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @param {RuntimeSpec} runtime the runtime
* @param {ExportsInfo} exportsInfo exports info about the current module (optional)
* @param {Module} importedModule the imported module (optional)
* @returns {{exports?: Set<string>, checked?: Set<string>, ignoredExports: Set<string>}} information
*/
getStarReexports(
moduleGraph,
runtime,
exportsInfo = moduleGraph.getExportsInfo(moduleGraph.getParentModule(this)),
importedModule = moduleGraph.getModule(this)
) {
const importedExportsInfo = moduleGraph.getExportsInfo(importedModule);
const noExtraExports =
importedExportsInfo.otherExportsInfo.provided === false;
const noExtraImports =
exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused;
const ignoredExports = new Set([
"default",
...this.activeExports,
...this._discoverActiveExportsFromOtherStarExports(moduleGraph).keys()
]);
if (!noExtraExports && !noExtraImports) {
return {
ignoredExports
};
}
/** @type {Set<string>} */
const exports = new Set();
/** @type {Set<string>} */
const checked = new Set();
if (noExtraImports) {
for (const exportInfo of exportsInfo.orderedExports) {
const name = exportInfo.name;
if (ignoredExports.has(name)) continue;
if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
const importedExportInfo = importedExportsInfo.getReadOnlyExportInfo(
name
);
if (importedExportInfo.provided === false) continue;
exports.add(name);
if (importedExportInfo.provided === true) continue;
checked.add(name);
}
} else if (noExtraExports) {
for (const importedExportInfo of importedExportsInfo.orderedExports) {
const name = importedExportInfo.name;
if (ignoredExports.has(name)) continue;
if (importedExportInfo.provided === false) continue;
const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
exports.add(name);
if (importedExportInfo.provided === true) continue;
checked.add(name);
}
}
return { ignoredExports, exports, checked };
}
/**
* @param {ModuleGraph} moduleGraph module graph
2021-01-27 20:32:09 +08:00
* @returns {null | false | function(ModuleGraphConnection, RuntimeSpec): ConnectionState} function to determine if the connection is active
*/
getCondition(moduleGraph) {
return (connection, runtime) => {
const mode = this.getMode(moduleGraph, runtime);
return mode.type !== "unused" && mode.type !== "empty-star";
};
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @returns {ConnectionState} how this dependency connects the module to referencing modules
*/
getModuleEvaluationSideEffectsState(moduleGraph) {
return false;
}
2018-07-25 15:33:48 +08:00
/**
* Returns list of exports referenced by this dependency
* @param {ModuleGraph} moduleGraph module graph
* @param {RuntimeSpec} runtime the runtime for which the module is analysed
* @returns {(string[] | ReferencedExport)[]} referenced exports
2018-07-25 15:33:48 +08:00
*/
getReferencedExports(moduleGraph, runtime) {
const mode = this.getMode(moduleGraph, runtime);
2018-02-25 09:00:20 +08:00
switch (mode.type) {
case "missing":
case "unused":
case "empty-star":
case "reexport-undefined":
2019-10-30 14:57:55 +08:00
return Dependency.NO_EXPORTS_REFERENCED;
case "reexport-dynamic-default":
return Dependency.EXPORTS_OBJECT_REFERENCED;
case "reexport-named-default": {
if (!mode.partialNamespaceExportInfo)
return Dependency.EXPORTS_OBJECT_REFERENCED;
/** @type {string[][]} */
const referencedExports = [];
processExportInfo(
runtime,
referencedExports,
[],
2020-07-04 18:24:16 +08:00
/** @type {ExportInfo} */ (mode.partialNamespaceExportInfo)
);
return referencedExports;
}
case "reexport-namespace-object":
case "reexport-fake-namespace-object": {
if (!mode.partialNamespaceExportInfo)
return Dependency.EXPORTS_OBJECT_REFERENCED;
/** @type {string[][]} */
const referencedExports = [];
processExportInfo(
runtime,
referencedExports,
[],
2020-07-04 18:24:16 +08:00
/** @type {ExportInfo} */ (mode.partialNamespaceExportInfo),
mode.type === "reexport-fake-namespace-object"
);
return referencedExports;
}
case "dynamic-reexport":
return Dependency.EXPORTS_OBJECT_REFERENCED;
2020-07-04 18:24:16 +08:00
case "normal-reexport": {
const referencedExports = [];
2020-07-07 03:39:54 +08:00
for (const { ids, exportInfo } of mode.items) {
processExportInfo(runtime, referencedExports, ids, exportInfo, false);
2020-07-04 18:24:16 +08:00
}
return referencedExports;
}
default:
throw new Error(`Unknown mode ${mode.type}`);
}
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @returns {Map<string, HarmonyExportImportedSpecifierDependency>} exported names and their origin dependency
*/
_discoverActiveExportsFromOtherStarExports(moduleGraph) {
if (!this.otherStarExports) {
return new Map();
}
const result = new Map();
// try to learn impossible exports from other star exports with provided exports
2018-02-25 09:00:20 +08:00
for (const otherStarExport of this.otherStarExports) {
const otherImportedModule = moduleGraph.getModule(otherStarExport);
if (otherImportedModule) {
const exportsInfo = moduleGraph.getExportsInfo(otherImportedModule);
for (const exportInfo of exportsInfo.exports) {
if (exportInfo.provided === true && !result.has(exportInfo.name)) {
result.set(exportInfo.name, otherStarExport);
}
}
}
}
return result;
}
2018-07-25 15:33:48 +08:00
/**
* Returns the exported names
2018-07-17 22:34:36 +08:00
* @param {ModuleGraph} moduleGraph module graph
2018-07-25 15:33:48 +08:00
* @returns {ExportsSpec | undefined} export names
*/
2018-07-17 22:34:36 +08:00
getExports(moduleGraph) {
const mode = this.getMode(moduleGraph, undefined);
switch (mode.type) {
case "missing":
return undefined;
case "dynamic-reexport": {
const from = moduleGraph.getConnection(this);
return {
exports: true,
from,
canMangle: false,
excludeExports: mode.ignored,
dependencies: [from.module]
};
}
case "empty-star":
return {
exports: [],
dependencies: [moduleGraph.getModule(this)]
};
2020-07-07 03:39:54 +08:00
case "normal-reexport": {
const from = moduleGraph.getConnection(this);
return {
2020-07-07 03:39:54 +08:00
exports: Array.from(mode.items, item => ({
name: item.name,
from,
export: item.ids
})),
dependencies: [from.module]
};
2020-07-07 03:39:54 +08:00
}
case "reexport-dynamic-default": {
{
const from = moduleGraph.getConnection(this);
return {
exports: [
{
name: mode.name,
from,
export: ["default"]
}
],
dependencies: [from.module]
};
}
}
case "reexport-undefined":
return {
exports: [mode.name],
dependencies: [moduleGraph.getModule(this)]
};
case "reexport-fake-namespace-object": {
const from = moduleGraph.getConnection(this);
return {
exports: [
{
name: mode.name,
from,
export: null,
exports: [
{
name: "default",
canMangle: false,
from,
export: null
}
]
}
],
dependencies: [from.module]
};
}
case "reexport-namespace-object": {
const from = moduleGraph.getConnection(this);
return {
exports: [
{
name: mode.name,
from,
export: null
}
],
dependencies: [from.module]
};
}
case "reexport-named-default": {
const from = moduleGraph.getConnection(this);
return {
exports: [
{
name: mode.name,
from,
export: ["default"]
}
],
dependencies: [from.module]
};
}
default:
throw new Error(`Unknown mode ${mode.type}`);
}
}
2018-07-25 15:33:48 +08:00
/**
* Returns warnings
* @param {ModuleGraph} moduleGraph module graph
2018-07-25 15:33:48 +08:00
* @returns {WebpackError[]} warnings
*/
getWarnings(moduleGraph) {
2018-02-25 09:00:20 +08:00
if (
this.strictExportPresence ||
moduleGraph.getParentModule(this).buildMeta.strictHarmonyModule
2018-02-25 09:00:20 +08:00
) {
return null;
}
return this._getErrors(moduleGraph);
}
2018-07-25 15:33:48 +08:00
/**
* Returns errors
* @param {ModuleGraph} moduleGraph module graph
2018-07-25 15:33:48 +08:00
* @returns {WebpackError[]} errors
*/
getErrors(moduleGraph) {
2018-02-25 09:00:20 +08:00
if (
this.strictExportPresence ||
moduleGraph.getParentModule(this).buildMeta.strictHarmonyModule
2018-02-25 09:00:20 +08:00
) {
return this._getErrors(moduleGraph);
}
return null;
}
/**
* @param {ModuleGraph} moduleGraph module graph
* @returns {WebpackError[] | undefined} errors
*/
_getErrors(moduleGraph) {
const ids = this.getIds(moduleGraph);
let errors = this.getLinkingErrors(
moduleGraph,
ids,
`(reexported as '${this.name}')`
);
if (ids.length === 0 && this.name === null) {
const potentialConflicts = this._discoverActiveExportsFromOtherStarExports(
moduleGraph
);
if (potentialConflicts.size > 0) {
const importedModule = moduleGraph.getModule(this);
if (importedModule) {
const exportsInfo = moduleGraph.getExportsInfo(importedModule);
const conflicts = new Map();
for (const exportInfo of exportsInfo.orderedExports) {
if (exportInfo.provided !== true) continue;
if (exportInfo.name === "default") continue;
if (this.activeExports.has(exportInfo.name)) continue;
const conflictingDependency = potentialConflicts.get(
exportInfo.name
);
if (!conflictingDependency) continue;
const target = exportInfo.getTerminalBinding(moduleGraph);
if (!target) continue;
const conflictingModule = moduleGraph.getModule(
conflictingDependency
);
if (conflictingModule === importedModule) continue;
const conflictingExportInfo = moduleGraph.getExportInfo(
conflictingModule,
exportInfo.name
);
const conflictingTarget = conflictingExportInfo.getTerminalBinding(
moduleGraph
);
if (!conflictingTarget) continue;
if (target === conflictingTarget) continue;
const list = conflicts.get(conflictingDependency.request);
if (list === undefined) {
conflicts.set(conflictingDependency.request, [exportInfo.name]);
} else {
list.push(exportInfo.name);
}
}
for (const [request, exports] of conflicts) {
if (!errors) errors = [];
errors.push(
new HarmonyLinkingError(
`The requested module '${
this.request
}' contains conflicting star exports for the ${
exports.length > 1 ? "names" : "name"
} ${exports
.map(e => `'${e}'`)
.join(", ")} with the previous requested module '${request}'`
)
);
}
}
}
}
return errors;
}
serialize(context) {
const { write } = context;
write(this.ids);
write(this.name);
write(this.activeExports);
write(this.otherStarExports);
write(this.strictExportPresence);
super.serialize(context);
}
deserialize(context) {
const { read } = context;
this.ids = read();
this.name = read();
this.activeExports = read();
this.otherStarExports = read();
this.strictExportPresence = read();
super.deserialize(context);
}
}
makeSerializable(
HarmonyExportImportedSpecifierDependency,
"webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency"
);
module.exports = HarmonyExportImportedSpecifierDependency;
2020-11-26 17:52:55 +08:00
HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate extends (
HarmonyImportDependency.Template
) {
2018-07-27 17:45:12 +08:00
/**
* @param {Dependency} dependency the dependency for which the template should be applied
* @param {ReplaceSource} source the current replace source which can be modified
* @param {DependencyTemplateContext} templateContext the context object
* @returns {void}
2018-07-27 17:45:12 +08:00
*/
apply(dependency, source, templateContext) {
const { moduleGraph, runtime, concatenationScope } = templateContext;
2018-07-27 17:45:12 +08:00
const dep = /** @type {HarmonyExportImportedSpecifierDependency} */ (dependency);
const mode = dep.getMode(moduleGraph, runtime);
if (concatenationScope) {
switch (mode.type) {
case "reexport-undefined":
concatenationScope.registerRawExport(
mode.name,
"/* reexport non-default export from non-harmony */ undefined"
);
}
return;
}
if (mode.type !== "unused" && mode.type !== "empty-star") {
super.apply(dependency, source, templateContext);
this._addExportFragments(
templateContext.initFragments,
dep,
mode,
templateContext.module,
moduleGraph,
runtime,
templateContext.runtimeTemplate,
2018-11-17 01:18:44 +08:00
templateContext.runtimeRequirements
);
}
}
/**
* @param {InitFragment[]} initFragments target array for init fragments
* @param {HarmonyExportImportedSpecifierDependency} dep dependency
* @param {ExportMode} mode the export mode
* @param {Module} module the current module
* @param {ModuleGraph} moduleGraph the module graph
* @param {RuntimeSpec} runtime the runtime
* @param {RuntimeTemplate} runtimeTemplate the runtime template
2018-11-17 01:18:44 +08:00
* @param {Set<string>} runtimeRequirements runtime requirements
* @returns {void}
*/
_addExportFragments(
initFragments,
dep,
mode,
module,
moduleGraph,
runtime,
runtimeTemplate,
runtimeRequirements
) {
const importedModule = moduleGraph.getModule(dep);
const importVar = dep.getImportVar(moduleGraph);
2018-02-25 09:00:20 +08:00
switch (mode.type) {
case "missing":
case "empty-star":
initFragments.push(
new InitFragment(
"/* empty/unused harmony star reexport */\n",
InitFragment.STAGE_HARMONY_EXPORTS,
1
)
);
break;
case "unused":
initFragments.push(
new InitFragment(
`${Template.toNormalComment(
`unused harmony reexport ${mode.name}`
)}\n`,
InitFragment.STAGE_HARMONY_EXPORTS,
1
)
);
break;
case "reexport-dynamic-default":
initFragments.push(
this.getReexportFragment(
module,
"reexport default from dynamic",
moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
importVar,
null,
runtimeRequirements
)
);
break;
case "reexport-fake-namespace-object":
initFragments.push(
...this.getReexportFakeNamespaceObjectFragments(
module,
moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
importVar,
mode.fakeType,
runtimeRequirements
)
);
break;
case "reexport-undefined":
initFragments.push(
this.getReexportFragment(
module,
"reexport non-default export from non-harmony",
moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
"undefined",
"",
runtimeRequirements
)
2018-02-25 09:00:20 +08:00
);
break;
case "reexport-named-default":
initFragments.push(
this.getReexportFragment(
module,
"reexport default export from named module",
moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
importVar,
"",
runtimeRequirements
)
2018-02-25 09:00:20 +08:00
);
break;
case "reexport-namespace-object":
initFragments.push(
this.getReexportFragment(
module,
"reexport module object",
moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
importVar,
"",
runtimeRequirements
)
);
break;
case "normal-reexport":
2020-07-07 03:39:54 +08:00
for (const { name, ids, checked } of mode.items) {
if (checked) {
initFragments.push(
new InitFragment(
"/* harmony reexport (checked) */ " +
this.getConditionalReexportStatement(
module,
2020-07-07 03:39:54 +08:00
name,
importVar,
2020-07-07 03:39:54 +08:00
ids,
runtimeRequirements
),
InitFragment.STAGE_HARMONY_IMPORTS,
dep.sourceOrder
)
);
} else {
initFragments.push(
this.getReexportFragment(
module,
"reexport safe",
moduleGraph.getExportsInfo(module).getUsedName(name, runtime),
importVar,
moduleGraph
.getExportsInfo(importedModule)
.getUsedName(ids, runtime),
runtimeRequirements
)
);
}
}
break;
2018-02-25 09:00:20 +08:00
case "dynamic-reexport": {
const ignored = mode.ignored;
const modern =
runtimeTemplate.supportsConst() &&
runtimeTemplate.supportsArrowFunction();
2018-02-25 09:00:20 +08:00
let content =
"/* harmony reexport (unknown) */ var __WEBPACK_REEXPORT_OBJECT__ = {};\n" +
`/* harmony reexport (unknown) */ for(${
modern ? "const" : "var"
} __WEBPACK_IMPORT_KEY__ in ${importVar}) `;
2018-02-25 09:00:20 +08:00
// Filter out exports which are defined by other exports
// and filter out default export because it cannot be reexported with *
if (ignored.size > 1) {
2018-02-25 09:00:20 +08:00
content +=
"if(" +
JSON.stringify(Array.from(ignored)) +
2018-02-25 09:00:20 +08:00
".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
} else if (ignored.size === 1) {
content += `if(__WEBPACK_IMPORT_KEY__ !== ${JSON.stringify(
ignored.values().next().value
)}) `;
}
content += `__WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = `;
if (modern) {
content += `() => ${importVar}[__WEBPACK_IMPORT_KEY__]`;
} else {
content += `function(key) { return ${importVar}[key]; }.bind(0, __WEBPACK_IMPORT_KEY__)`;
}
2018-11-17 01:18:44 +08:00
runtimeRequirements.add(RuntimeGlobals.exports);
runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
2018-11-17 01:18:44 +08:00
const exportsName = module.exportsArgument;
initFragments.push(
new InitFragment(
`${content}\n/* harmony reexport (unknown) */ ${RuntimeGlobals.definePropertyGetters}(${exportsName}, __WEBPACK_REEXPORT_OBJECT__);\n`,
InitFragment.STAGE_HARMONY_IMPORTS,
dep.sourceOrder
)
2018-02-25 09:00:20 +08:00
);
break;
2018-02-25 09:00:20 +08:00
}
default:
throw new Error(`Unknown mode ${mode.type}`);
}
}
getReexportFragment(
module,
comment,
key,
name,
valueKey,
runtimeRequirements
) {
const returnValue = this.getReturnValue(name, valueKey);
2018-11-17 01:18:44 +08:00
runtimeRequirements.add(RuntimeGlobals.exports);
runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
2018-11-17 01:18:44 +08:00
const map = new Map();
map.set(key, `/* ${comment} */ ${returnValue}`);
return new HarmonyExportInitFragment(module.exportsArgument, map);
}
getReexportFakeNamespaceObjectFragments(
2018-11-17 01:18:44 +08:00
module,
key,
name,
fakeType,
2018-11-17 01:18:44 +08:00
runtimeRequirements
) {
runtimeRequirements.add(RuntimeGlobals.exports);
runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
2018-11-17 01:18:44 +08:00
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)
];
}
2018-11-17 01:18:44 +08:00
getConditionalReexportStatement(
module,
key,
name,
valueKey,
runtimeRequirements
) {
2018-06-23 21:27:10 +08:00
if (valueKey === false) {
return "/* unused export */\n";
}
const exportsName = module.exportsArgument;
const returnValue = this.getReturnValue(name, valueKey);
2018-11-17 01:18:44 +08:00
runtimeRequirements.add(RuntimeGlobals.exports);
runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
2019-12-02 22:59:37 +08:00
runtimeRequirements.add(RuntimeGlobals.hasOwnProperty);
2018-11-17 01:18:44 +08:00
2019-12-02 22:59:37 +08:00
return `if(${RuntimeGlobals.hasOwnProperty}(${name}, ${JSON.stringify(
valueKey[0]
)})) ${
RuntimeGlobals.definePropertyGetters
}(${exportsName}, { ${JSON.stringify(
2018-02-25 09:00:20 +08:00
key
)}: function() { return ${returnValue}; } });\n`;
}
getReturnValue(name, valueKey) {
2018-02-25 09:00:20 +08:00
if (valueKey === null) {
return `${name}_default.a`;
}
if (valueKey === "") {
return name;
}
if (valueKey === false) {
return "/* unused export */ undefined";
}
return `${name}${propertyAccess(valueKey)}`;
}
2017-01-11 17:51:58 +08:00
};