add support for reexporting in CommonJS

and necessary refactoring + fixes for that
This commit is contained in:
Tobias Koppers 2020-08-17 21:32:47 +02:00
parent 0090eb941c
commit 71cf7f4dc8
25 changed files with 941 additions and 246 deletions

View File

@ -490,6 +490,7 @@ class ContextModule extends Module {
const fakeMap = Object.create(null); const fakeMap = Object.create(null);
for (const module of sortedModules) { for (const module of sortedModules) {
const exportsType = module.getExportsType( const exportsType = module.getExportsType(
moduleGraph,
this.options.namespaceObject === "strict" this.options.namespaceObject === "strict"
); );
const id = chunkGraph.getModuleId(module); const id = chunkGraph.getModuleId(module);

View File

@ -425,9 +425,6 @@ class ExportsInfo {
return true; return true;
} }
} }
if (this._sideEffectsOnlyInfo.getUsed(runtime) !== UsageState.Unused) {
return true;
}
for (const exportInfo of this._exports.values()) { for (const exportInfo of this._exports.values()) {
if (exportInfo.getUsed(runtime) !== UsageState.Unused) { if (exportInfo.getUsed(runtime) !== UsageState.Unused) {
return true; return true;
@ -641,7 +638,10 @@ class ExportsInfo {
getUsedName(name, runtime) { getUsedName(name, runtime) {
if (Array.isArray(name)) { if (Array.isArray(name)) {
// TODO improve this // TODO improve this
if (name.length === 0) return name; if (name.length === 0) {
if (!this.isUsed(runtime)) return false;
return name;
}
let info = this.getReadOnlyExportInfo(name[0]); let info = this.getReadOnlyExportInfo(name[0]);
const x = info.getUsedName(name[0], runtime); const x = info.getUsedName(name[0], runtime);
if (x === false) return false; if (x === false) return false;

View File

@ -71,7 +71,7 @@ const makeSerializable = require("./util/makeSerializable");
* @property {string=} exportsArgument * @property {string=} exportsArgument
* @property {boolean=} strict * @property {boolean=} strict
* @property {string=} moduleConcatenationBailout * @property {string=} moduleConcatenationBailout
* @property {("default" | "namespace" | "flagged")=} exportsType * @property {("default" | "namespace" | "flagged" | "dynamic")=} exportsType
* @property {(false | "redirect" | "redirect-warn")=} defaultObject * @property {(false | "redirect" | "redirect-warn")=} defaultObject
* @property {boolean=} strictHarmonyModule * @property {boolean=} strictHarmonyModule
* @property {boolean=} async * @property {boolean=} async
@ -263,6 +263,10 @@ class Module extends DependenciesBlock {
).getUsedExports(this, undefined); ).getUsedExports(this, undefined);
} }
/**
* @deprecated
* @returns {(string | OptimizationBailoutFunction)[]} list
*/
get optimizationBailout() { get optimizationBailout() {
return ModuleGraph.getModuleGraphForModule( return ModuleGraph.getModuleGraphForModule(
this, this,
@ -372,6 +376,7 @@ class Module extends DependenciesBlock {
} }
/** /**
* @param {ModuleGraph} moduleGraph the module graph
* @param {boolean} strict the importing module is strict * @param {boolean} strict the importing module is strict
* @returns {"namespace" | "default-only" | "default-with-named" | "dynamic"} export type * @returns {"namespace" | "default-only" | "default-with-named" | "dynamic"} export type
* "namespace": Exports is already a namespace object. namespace = exports. * "namespace": Exports is already a namespace object. namespace = exports.
@ -379,7 +384,7 @@ class Module extends DependenciesBlock {
* "default-only": Provide a namespace object with only default export. namespace = { default: exports } * "default-only": Provide a namespace object with only default export. namespace = { default: exports }
* "default-with-named": Provide a namespace object with named and default export. namespace = { ...exports, default: exports } * "default-with-named": Provide a namespace object with named and default export. namespace = { ...exports, default: exports }
*/ */
getExportsType(strict) { getExportsType(moduleGraph, strict) {
switch (this.buildMeta && this.buildMeta.exportsType) { switch (this.buildMeta && this.buildMeta.exportsType) {
case "flagged": case "flagged":
return strict ? "default-only" : "namespace"; return strict ? "default-only" : "namespace";
@ -393,6 +398,44 @@ class Module extends DependenciesBlock {
default: default:
return "default-only"; return "default-only";
} }
case "dynamic": {
if (strict) return "default-only";
// Try to figure out value of __esModule by following reexports
const handleDefault = () => {
switch (this.buildMeta.defaultObject) {
case "redirect":
case "redirect-warn":
return "default-with-named";
default:
return "default-only";
}
};
const exportInfo = moduleGraph.getExportInfo(this, "__esModule");
if (exportInfo.provided === false) {
return handleDefault();
}
const target = exportInfo.getTarget(moduleGraph);
if (
!target ||
!target.export ||
target.export.length !== 1 ||
target.export[0] !== "__esModule"
) {
return "dynamic";
}
switch (
target.module.buildMeta &&
target.module.buildMeta.exportsType
) {
case "flagged":
case "namespace":
return "namespace";
case "default":
return handleDefault();
default:
return "dynamic";
}
}
default: default:
return strict ? "default-only" : "dynamic"; return strict ? "default-only" : "dynamic";
} }

View File

@ -26,7 +26,7 @@ exports.exports = "__webpack_exports__";
exports.thisAsExports = "top-level-this-exports"; exports.thisAsExports = "top-level-this-exports";
/** /**
* top-level this need to be the exports object * runtime need to return the exports of the last entry module
*/ */
exports.returnExportsFromRuntime = "return-exports-from-runtime"; exports.returnExportsFromRuntime = "return-exports-from-runtime";

View File

@ -357,7 +357,7 @@ class RuntimeTemplate {
request, request,
weak weak
}); });
const exportsType = module.getExportsType(strict); const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
switch (exportsType) { switch (exportsType) {
case "namespace": case "namespace":
return this.moduleRaw({ return this.moduleRaw({
@ -461,7 +461,7 @@ class RuntimeTemplate {
request, request,
weak weak
}); });
const exportsType = module.getExportsType(strict); const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
let fakeType = 0; let fakeType = 0;
switch (exportsType) { switch (exportsType) {
case "namespace": case "namespace":
@ -590,6 +590,7 @@ class RuntimeTemplate {
const optDeclaration = update ? "" : "var "; const optDeclaration = update ? "" : "var ";
const exportsType = module.getExportsType( const exportsType = module.getExportsType(
chunkGraph.moduleGraph,
originModule.buildMeta.strictHarmonyModule originModule.buildMeta.strictHarmonyModule
); );
runtimeRequirements.add(RuntimeGlobals.require); runtimeRequirements.add(RuntimeGlobals.require);
@ -646,6 +647,7 @@ class RuntimeTemplate {
exportName = exportName ? [exportName] : []; exportName = exportName ? [exportName] : [];
} }
const exportsType = module.getExportsType( const exportsType = module.getExportsType(
moduleGraph,
originModule.buildMeta.strictHarmonyModule originModule.buildMeta.strictHarmonyModule
); );

View File

@ -680,7 +680,13 @@ const applyOptimizationDefaults = (
apply: compiler => { apply: compiler => {
// Lazy load the Terser plugin // Lazy load the Terser plugin
const TerserPlugin = require("terser-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin");
new TerserPlugin().apply(compiler); new TerserPlugin({
terserOptions: {
compress: {
passes: 2
}
}
}).apply(compiler);
} }
} }
]); ]);

View File

@ -0,0 +1,49 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
exports.handleDependencyBase = (depBase, module, runtimeRequirements) => {
let base = undefined;
let type;
switch (depBase) {
case "exports":
runtimeRequirements.add(RuntimeGlobals.exports);
base = module.exportsArgument;
type = "expression";
break;
case "module.exports":
runtimeRequirements.add(RuntimeGlobals.module);
base = `${module.moduleArgument}.exports`;
type = "expression";
break;
case "this":
runtimeRequirements.add(RuntimeGlobals.thisAsExports);
base = "this";
type = "expression";
break;
case "Object.defineProperty(exports)":
runtimeRequirements.add(RuntimeGlobals.exports);
base = module.exportsArgument;
type = "Object.defineProperty";
break;
case "Object.defineProperty(module.exports)":
runtimeRequirements.add(RuntimeGlobals.module);
base = `${module.moduleArgument}.exports`;
type = "Object.defineProperty";
break;
case "Object.defineProperty(this)":
runtimeRequirements.add(RuntimeGlobals.thisAsExports);
base = "this";
type = "Object.defineProperty";
break;
default:
throw new Error(`Unsupported base ${depBase}`);
}
return [type, base];
};

View File

@ -0,0 +1,356 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Dependency = require("../Dependency");
const { UsageState } = require("../ExportsInfo");
const Template = require("../Template");
const { equals } = require("../util/ArrayHelpers");
const makeSerializable = require("../util/makeSerializable");
const propertyAccess = require("../util/propertyAccess");
const { handleDependencyBase } = require("./CommonJsDependencyHelpers");
const ModuleDependency = require("./ModuleDependency");
const processExportInfo = require("./processExportInfo");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
/** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
const idsSymbol = Symbol("CommonJsExportRequireDependency.ids");
const EMPTY_OBJECT = {};
class CommonJsExportRequireDependency extends ModuleDependency {
constructor(range, valueRange, base, names, request, ids, resultUsed) {
super(request);
this.range = range;
this.valueRange = valueRange;
this.base = base;
this.names = names;
this.ids = ids;
this.resultUsed = resultUsed;
this.asiSafe = false;
}
get type() {
return "cjs export require";
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @returns {string[]} the imported id
*/
getIds(moduleGraph) {
return moduleGraph.getMeta(this)[idsSymbol] || this.ids;
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @param {string[]} ids the imported ids
* @returns {void}
*/
setIds(moduleGraph, ids) {
moduleGraph.getMeta(this)[idsSymbol] = ids;
}
/**
* 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
*/
getReferencedExports(moduleGraph, runtime) {
const ids = this.getIds(moduleGraph);
const getFullResult = () => {
if (ids.length === 0) {
return Dependency.EXPORTS_OBJECT_REFERENCED;
} else {
return [
{
name: ids,
canMangle: false
}
];
}
};
if (this.resultUsed) return getFullResult();
let exportsInfo = moduleGraph.getExportsInfo(
moduleGraph.getParentModule(this)
);
for (const name of this.names) {
const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
const used = exportInfo.getUsed(runtime);
if (used === UsageState.Unused) return Dependency.NO_EXPORTS_REFERENCED;
if (used !== UsageState.OnlyPropertiesUsed) return getFullResult();
exportsInfo = exportInfo.exportsInfo;
if (!exportsInfo) return getFullResult();
}
if (exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused) {
return getFullResult();
}
/** @type {string[][]} */
const referencedExports = [];
for (const exportInfo of exportsInfo.orderedExports) {
processExportInfo(
runtime,
referencedExports,
ids.concat(exportInfo.name),
exportInfo,
false
);
}
return referencedExports.map(name => ({
name,
canMangle: false
}));
}
/**
* Returns the exported names
* @param {ModuleGraph} moduleGraph module graph
* @returns {ExportsSpec | undefined} export names
*/
getExports(moduleGraph) {
const ids = this.getIds(moduleGraph);
if (this.names.length === 1) {
const name = this.names[0];
const from = moduleGraph.getModule(this);
return {
exports: [
{
name,
from,
export: ids.length === 0 ? null : ids,
// we can't mangle names that are in an empty object
// because one could access the prototype property
// when export isn't set yet
canMangle: !(name in EMPTY_OBJECT) && false
}
],
dependencies: [from]
};
} else if (this.names.length > 0) {
const name = this.names[0];
return {
exports: [
{
name,
// we can't mangle names that are in an empty object
// because one could access the prototype property
// when export isn't set yet
canMangle: !(name in EMPTY_OBJECT) && false
}
],
dependencies: undefined
};
} else {
const from = moduleGraph.getModule(this);
const reexportInfo = this.getStarReexports(moduleGraph, undefined, from);
if (reexportInfo) {
return {
exports: Array.from(reexportInfo.exports, name => {
return {
name,
from,
export: ids.concat(name),
canMangle: !(name in EMPTY_OBJECT) && false
};
}),
// TODO handle deep reexports
dependencies: [from]
};
} else {
return {
exports: true,
from: ids.length === 0 ? from : undefined,
canMangle: false,
dependencies: [from]
};
}
}
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @param {RuntimeSpec} runtime the runtime
* @param {Module} importedModule the imported module (optional)
* @returns {{exports?: Set<string>, checked?: Set<string>}} information
*/
getStarReexports(
moduleGraph,
runtime,
importedModule = moduleGraph.getModule(this)
) {
let importedExportsInfo = moduleGraph.getExportsInfo(importedModule);
const ids = this.getIds(moduleGraph);
if (ids.length > 0)
importedExportsInfo = importedExportsInfo.getNestedExportsInfo(ids);
let exportsInfo = moduleGraph.getExportsInfo(
moduleGraph.getParentModule(this)
);
if (this.names.length > 0)
exportsInfo = exportsInfo.getNestedExportsInfo(this.names);
const noExtraExports =
importedExportsInfo &&
importedExportsInfo.otherExportsInfo.provided === false;
const noExtraImports =
exportsInfo &&
exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused;
if (!noExtraExports && !noExtraImports) {
return;
}
const isNamespaceImport =
importedModule.getExportsType(moduleGraph, false) === "namespace";
/** @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 (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
if (name === "__esModule" && isNamespaceImport) {
exports.add(name);
} else if (importedExportsInfo) {
const importedExportInfo = importedExportsInfo.getReadOnlyExportInfo(
name
);
if (importedExportInfo.provided === false) continue;
exports.add(name);
if (importedExportInfo.provided === true) continue;
checked.add(name);
} else {
exports.add(name);
checked.add(name);
}
}
} else if (noExtraExports) {
for (const importedExportInfo of importedExportsInfo.orderedExports) {
const name = importedExportInfo.name;
if (importedExportInfo.provided === false) continue;
if (exportsInfo) {
const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
}
exports.add(name);
if (importedExportInfo.provided === true) continue;
checked.add(name);
}
if (isNamespaceImport) {
exports.add("__esModule");
checked.delete("__esModule");
}
}
return { exports, checked };
}
serialize(context) {
const { write } = context;
write(this.range);
write(this.valueRange);
write(this.base);
write(this.names);
write(this.ids);
write(this.resultUsed);
super.serialize(context);
}
deserialize(context) {
const { read } = context;
this.range = read();
this.valueRange = read();
this.base = read();
this.names = read();
this.ids = read();
this.resultUsed = read();
super.deserialize(context);
}
}
makeSerializable(
CommonJsExportRequireDependency,
"webpack/lib/dependencies/CommonJsExportRequireDependency"
);
CommonJsExportRequireDependency.Template = class CommonJsExportRequireDependencyTemplate extends ModuleDependency.Template {
/**
* @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}
*/
apply(
dependency,
source,
{
module,
runtimeTemplate,
chunkGraph,
moduleGraph,
runtimeRequirements,
runtime
}
) {
const dep = /** @type {CommonJsExportRequireDependency} */ (dependency);
const used = moduleGraph
.getExportsInfo(module)
.getUsedName(dep.names, runtime);
const [type, base] = handleDependencyBase(
dep.base,
module,
runtimeRequirements
);
const importedModule = moduleGraph.getModule(dep);
let requireExpr = runtimeTemplate.moduleExports({
module: importedModule,
chunkGraph,
request: dep.request,
weak: dep.weak,
runtimeRequirements
});
const ids = dep.getIds(moduleGraph);
const usedImported = moduleGraph
.getExportsInfo(importedModule)
.getUsedName(ids, runtime);
if (usedImported) {
const comment = equals(usedImported, ids)
? ""
: Template.toNormalComment(propertyAccess(ids)) + " ";
requireExpr += `${comment}${propertyAccess(usedImported)}`;
}
switch (type) {
case "expression":
source.replace(
dep.range[0],
dep.range[1] - 1,
used
? `${base}${propertyAccess(used)} = ${requireExpr}`
: `/* unused reexport */ ${requireExpr}`
);
return;
case "Object.defineProperty":
throw new Error("TODO");
default:
throw new Error("Unexpected type");
}
}
};
module.exports = CommonJsExportRequireDependency;

View File

@ -6,9 +6,9 @@
"use strict"; "use strict";
const InitFragment = require("../InitFragment"); const InitFragment = require("../InitFragment");
const RuntimeGlobals = require("../RuntimeGlobals");
const makeSerializable = require("../util/makeSerializable"); const makeSerializable = require("../util/makeSerializable");
const propertyAccess = require("../util/propertyAccess"); const propertyAccess = require("../util/propertyAccess");
const { handleDependencyBase } = require("./CommonJsDependencyHelpers");
const NullDependency = require("./NullDependency"); const NullDependency = require("./NullDependency");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
@ -94,42 +94,11 @@ CommonJsExportsDependency.Template = class CommonJsExportsDependencyTemplate ext
.getExportsInfo(module) .getExportsInfo(module)
.getUsedName(dep.names, runtime); .getUsedName(dep.names, runtime);
let base = undefined; const [type, base] = handleDependencyBase(
let type; dep.base,
switch (dep.base) { module,
case "exports": runtimeRequirements
runtimeRequirements.add(RuntimeGlobals.exports); );
base = module.exportsArgument;
type = "expression";
break;
case "module.exports":
runtimeRequirements.add(RuntimeGlobals.module);
base = `${module.moduleArgument}.exports`;
type = "expression";
break;
case "this":
runtimeRequirements.add(RuntimeGlobals.thisAsExports);
base = "this";
type = "expression";
break;
case "Object.defineProperty(exports)":
runtimeRequirements.add(RuntimeGlobals.exports);
base = module.exportsArgument;
type = "Object.defineProperty";
break;
case "Object.defineProperty(module.exports)":
runtimeRequirements.add(RuntimeGlobals.module);
base = `${module.moduleArgument}.exports`;
type = "Object.defineProperty";
break;
case "Object.defineProperty(this)":
runtimeRequirements.add(RuntimeGlobals.thisAsExports);
base = "this";
type = "Object.defineProperty";
break;
default:
throw new Error(`Unsupported base ${dep.base}`);
}
switch (type) { switch (type) {
case "expression": case "expression":

View File

@ -6,19 +6,21 @@
"use strict"; "use strict";
const RuntimeGlobals = require("../RuntimeGlobals"); const RuntimeGlobals = require("../RuntimeGlobals");
const formatLocation = require("../formatLocation");
const { evaluateToString } = require("../javascript/JavascriptParserHelpers"); const { evaluateToString } = require("../javascript/JavascriptParserHelpers");
const propertyAccess = require("../util/propertyAccess");
const CommonJsExportRequireDependency = require("./CommonJsExportRequireDependency");
const CommonJsExportsDependency = require("./CommonJsExportsDependency"); const CommonJsExportsDependency = require("./CommonJsExportsDependency");
const CommonJsSelfReferenceDependency = require("./CommonJsSelfReferenceDependency"); const CommonJsSelfReferenceDependency = require("./CommonJsSelfReferenceDependency");
const DynamicExports = require("./DynamicExports"); const DynamicExports = require("./DynamicExports");
const HarmonyExports = require("./HarmonyExports"); const HarmonyExports = require("./HarmonyExports");
const ModuleDecoratorDependency = require("./ModuleDecoratorDependency"); const ModuleDecoratorDependency = require("./ModuleDecoratorDependency");
/** @typedef {import("estree").Expression} ExpressionNode */
/** @typedef {import("../NormalModule")} NormalModule */ /** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
/** @type {WeakMap<NormalModule, boolean>} */
const moduleExportsState = new WeakMap();
const getValueOfPropertyDescription = expr => { const getValueOfPropertyDescription = expr => {
if (expr.type !== "ObjectExpression") return; if (expr.type !== "ObjectExpression") return;
for (const property of expr.properties) { for (const property of expr.properties) {
@ -49,14 +51,43 @@ const isFalsyLiteral = expr => {
return false; return false;
}; };
class CommonJsExportsParserPlugin { /**
static bailout(module) { * @param {JavascriptParser} parser the parser
const value = moduleExportsState.get(module); * @param {ExpressionNode} expr expression
moduleExportsState.set(module, false); * @returns {{ argument: BasicEvaluatedExpression, ids: string[] } | undefined} parsed call
if (value === true) { */
module.buildMeta.exportsType = undefined; const parseRequireCall = (parser, expr) => {
module.buildMeta.defaultObject = false; const ids = [];
while (expr.type === "MemberExpression") {
if (expr.object.type === "Super") return;
if (!expr.property) return;
const prop = expr.property;
if (expr.computed) {
if (prop.type !== "Literal") return;
ids.push(`${prop.value}`);
} else {
if (prop.type !== "Identifier") return;
ids.push(prop.name);
} }
expr = expr.object;
}
if (expr.type !== "CallExpression" || expr.arguments.length !== 1) return;
const callee = expr.callee;
if (
callee.type !== "Identifier" ||
parser.getVariableInfo(callee.name) !== "require"
) {
return;
}
const arg = expr.arguments[0];
if (arg.type === "SpreadElement") return;
const argValue = parser.evaluateExpression(arg);
return { argument: argValue, ids: ids.reverse() };
};
class CommonJsExportsParserPlugin {
constructor(moduleGraph) {
this.moduleGraph = moduleGraph;
} }
/** /**
@ -66,18 +97,24 @@ class CommonJsExportsParserPlugin {
const enableStructuredExports = () => { const enableStructuredExports = () => {
DynamicExports.enable(parser.state); DynamicExports.enable(parser.state);
}; };
const checkNamespace = (members, valueExpr) => { const checkNamespace = (topLevel, members, valueExpr) => {
if (!DynamicExports.isEnabled(parser.state)) return; if (!DynamicExports.isEnabled(parser.state)) return;
if (members.length > 0 && members[0] === "__esModule") { if (members.length > 0 && members[0] === "__esModule") {
if (isTruthyLiteral(valueExpr)) { if (isTruthyLiteral(valueExpr) && topLevel) {
DynamicExports.setFlagged(parser.state); DynamicExports.setFlagged(parser.state);
} else { } else {
DynamicExports.bailout(parser.state); DynamicExports.setDynamic(parser.state);
} }
} }
}; };
const bailout = () => { const bailout = reason => {
DynamicExports.bailout(parser.state); DynamicExports.bailout(parser.state);
if (reason) bailoutHint(reason);
};
const bailoutHint = reason => {
this.moduleGraph
.getOptimizationBailout(parser.state.module)
.push(`CommonJS bailout: ${reason}`);
}; };
// metadata // // metadata //
@ -89,60 +126,74 @@ class CommonJsExportsParserPlugin {
.tap("CommonJsPlugin", evaluateToString("object")); .tap("CommonJsPlugin", evaluateToString("object"));
// exporting // // exporting //
const handleAssignExport = (expr, base, members) => {
if (HarmonyExports.isEnabled(parser.state)) return;
// Handle reexporting
const requireCall = parseRequireCall(parser, expr.right);
if (
requireCall &&
requireCall.argument.isString() &&
(members.length === 0 || members[0] !== "__esModule")
) {
enableStructuredExports();
// It's possible to reexport __esModule, so we must convert to a dynamic module
if (members.length === 0) DynamicExports.setDynamic(parser.state);
const dep = new CommonJsExportRequireDependency(
expr.range,
null,
base,
members,
requireCall.argument.string,
requireCall.ids,
!parser.isStatementLevelExpression(expr)
);
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.module.addDependency(dep);
return true;
}
if (members.length === 0) return;
enableStructuredExports();
const remainingMembers = members;
checkNamespace(
parser.statementPath.length === 1 &&
parser.isStatementLevelExpression(expr),
remainingMembers,
expr.right
);
const dep = new CommonJsExportsDependency(
expr.left.range,
null,
base,
remainingMembers
);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
parser.walkExpression(expr.right);
return true;
};
parser.hooks.assignMemberChain parser.hooks.assignMemberChain
.for("exports") .for("exports")
.tap("CommonJsExportsParserPlugin", (expr, members) => { .tap("CommonJsExportsParserPlugin", (expr, members) => {
if (HarmonyExports.isEnabled(parser.state)) return; return handleAssignExport(expr, "exports", members);
enableStructuredExports();
checkNamespace(members, expr.right);
const dep = new CommonJsExportsDependency(
expr.left.range,
null,
"exports",
members
);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return true;
}); });
parser.hooks.assignMemberChain parser.hooks.assignMemberChain
.for("this") .for("this")
.tap("CommonJsExportsParserPlugin", (expr, members) => { .tap("CommonJsExportsParserPlugin", (expr, members) => {
if (HarmonyExports.isEnabled(parser.state)) return;
if (!parser.scope.topLevelScope) return; if (!parser.scope.topLevelScope) return;
enableStructuredExports(); return handleAssignExport(expr, "this", members);
checkNamespace(members, expr.right);
const dep = new CommonJsExportsDependency(
expr.left.range,
null,
"this",
members
);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return true;
}); });
parser.hooks.assignMemberChain parser.hooks.assignMemberChain
.for("module") .for("module")
.tap("CommonJsExportsParserPlugin", (expr, members) => { .tap("CommonJsExportsParserPlugin", (expr, members) => {
if (HarmonyExports.isEnabled(parser.state)) return; if (members[0] !== "exports") return;
if (members[0] !== "exports" || members.length <= 1) return; return handleAssignExport(expr, "module.exports", members.slice(1));
enableStructuredExports();
checkNamespace(members, expr.right);
const dep = new CommonJsExportsDependency(
expr.left.range,
null,
"module.exports",
members.slice(1)
);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return true;
}); });
parser.hooks.call parser.hooks.call
.for("Object.defineProperty") .for("Object.defineProperty")
.tap("CommonJsExportsParserPlugin", expression => { .tap("CommonJsExportsParserPlugin", expression => {
const expr = /** @type {import("estree").CallExpression} */ (expression); const expr = /** @type {import("estree").CallExpression} */ (expression);
if (!parser.isStatementLevelExpression(expr)) return;
if (expr.arguments.length !== 3) return; if (expr.arguments.length !== 3) return;
if (expr.arguments[0].type === "SpreadElement") return; if (expr.arguments[0].type === "SpreadElement") return;
if (expr.arguments[1].type === "SpreadElement") return; if (expr.arguments[1].type === "SpreadElement") return;
@ -162,7 +213,11 @@ class CommonJsExportsParserPlugin {
if (typeof property !== "string") return; if (typeof property !== "string") return;
enableStructuredExports(); enableStructuredExports();
const descArg = expr.arguments[2]; const descArg = expr.arguments[2];
checkNamespace([property], getValueOfPropertyDescription(descArg)); checkNamespace(
parser.statementPath.length === 1,
[property],
getValueOfPropertyDescription(descArg)
);
const dep = new CommonJsExportsDependency( const dep = new CommonJsExportsDependency(
expr.range, expr.range,
expr.arguments[2].range, expr.arguments[2].range,
@ -177,44 +232,87 @@ class CommonJsExportsParserPlugin {
}); });
// Self reference // // Self reference //
const handleAccessExport = (expr, base, members, call = undefined) => {
if (HarmonyExports.isEnabled(parser.state)) return;
if (members.length === 0) {
bailout(`${base} is used directly at ${formatLocation(expr.loc)}`);
}
if (call && members.length === 1) {
bailoutHint(
`${base}${propertyAccess(
members
)}(...) prevents optimization as ${base} is passed as call context as ${formatLocation(
expr.loc
)}`
);
}
const dep = new CommonJsSelfReferenceDependency(
expr.range,
base,
members,
call
);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
if (call) {
parser.walkExpressions(call.arguments);
}
return true;
};
parser.hooks.callMemberChain
.for("exports")
.tap("CommonJsExportsParserPlugin", (expr, members) => {
return handleAccessExport(expr.callee, "exports", members, expr);
});
parser.hooks.expressionMemberChain
.for("exports")
.tap("CommonJsExportsParserPlugin", (expr, members) => {
return handleAccessExport(expr, "exports", members);
});
parser.hooks.expression parser.hooks.expression
.for("exports") .for("exports")
.tap("CommonJsExportsParserPlugin", expr => { .tap("CommonJsExportsParserPlugin", expr => {
if (HarmonyExports.isEnabled(parser.state)) return; return handleAccessExport(expr, "exports", []);
bailout(); });
const dep = new CommonJsSelfReferenceDependency( parser.hooks.callMemberChain
expr.range, .for("module")
"exports", .tap("CommonJsExportsParserPlugin", (expr, members) => {
[] if (members[0] !== "exports") return;
return handleAccessExport(
expr.callee,
"module.exports",
members.slice(1),
expr
); );
dep.loc = expr.loc; });
parser.state.module.addDependency(dep); parser.hooks.expressionMemberChain
return true; .for("module")
.tap("CommonJsExportsParserPlugin", (expr, members) => {
if (members[0] !== "exports") return;
return handleAccessExport(expr, "module.exports", members.slice(1));
}); });
parser.hooks.expression parser.hooks.expression
.for("module.exports") .for("module.exports")
.tap("CommonJsExportsParserPlugin", expr => { .tap("CommonJsExportsParserPlugin", expr => {
if (HarmonyExports.isEnabled(parser.state)) return; return handleAccessExport(expr, "module.exports", []);
bailout(); });
const dep = new CommonJsSelfReferenceDependency( parser.hooks.callMemberChain
expr.range, .for("this")
"module.exports", .tap("CommonJsExportsParserPlugin", (expr, members) => {
[] if (!parser.scope.topLevelScope) return;
); return handleAccessExport(expr.callee, "this", members, expr);
dep.loc = expr.loc; });
parser.state.module.addDependency(dep); parser.hooks.expressionMemberChain
return true; .for("this")
.tap("CommonJsExportsParserPlugin", (expr, members) => {
if (!parser.scope.topLevelScope) return;
return handleAccessExport(expr, "this", members);
}); });
parser.hooks.expression parser.hooks.expression
.for("this") .for("this")
.tap("CommonJsExportsParserPlugin", expr => { .tap("CommonJsExportsParserPlugin", expr => {
if (HarmonyExports.isEnabled(parser.state)) return;
if (!parser.scope.topLevelScope) return; if (!parser.scope.topLevelScope) return;
bailout(); return handleAccessExport(expr, "this", []);
const dep = new CommonJsSelfReferenceDependency(expr.range, "this", []);
dep.loc = expr.loc;
parser.state.module.addDependency(dep);
return true;
}); });
// Bailouts // // Bailouts //

View File

@ -5,7 +5,10 @@
"use strict"; "use strict";
const Template = require("../Template");
const { equals } = require("../util/ArrayHelpers");
const makeSerializable = require("../util/makeSerializable"); const makeSerializable = require("../util/makeSerializable");
const propertyAccess = require("../util/propertyAccess");
const ModuleDependency = require("./ModuleDependency"); const ModuleDependency = require("./ModuleDependency");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
@ -40,7 +43,7 @@ class CommonJsFullRequireDependency extends ModuleDependency {
const importedModule = moduleGraph.getModule(this); const importedModule = moduleGraph.getModule(this);
if ( if (
!importedModule || !importedModule ||
importedModule.getExportsType(false) !== "namespace" importedModule.getExportsType(moduleGraph, false) !== "namespace"
) { ) {
return [this.names.slice(0, -1)]; return [this.names.slice(0, -1)];
} }
@ -96,29 +99,24 @@ CommonJsFullRequireDependency.Template = class CommonJsFullRequireDependencyTemp
const dep = /** @type {CommonJsFullRequireDependency} */ (dependency); const dep = /** @type {CommonJsFullRequireDependency} */ (dependency);
if (!dep.range) return; if (!dep.range) return;
const importedModule = moduleGraph.getModule(dep); const importedModule = moduleGraph.getModule(dep);
const exports = runtimeTemplate.moduleExports({ let requireExpr = runtimeTemplate.moduleExports({
module: importedModule, module: importedModule,
chunkGraph, chunkGraph,
request: dep.request, request: dep.request,
weak: dep.weak, weak: dep.weak,
runtimeRequirements runtimeRequirements
}); });
const exportExpr = runtimeTemplate.exportFromImport({ const ids = dep.names;
moduleGraph, const usedImported = moduleGraph
module: importedModule, .getExportsInfo(importedModule)
request: dep.request, .getUsedName(ids, runtime);
exportName: dep.names, if (usedImported) {
originModule: module, const comment = equals(usedImported, ids)
asiSafe: dep.asiSafe, ? ""
isCall: dep.call, : Template.toNormalComment(propertyAccess(ids)) + " ";
callContext: undefined, requireExpr += `${comment}${propertyAccess(usedImported)}`;
defaultInterop: false, }
importVar: exports, source.replace(dep.range[0], dep.range[1] - 1, requireExpr);
initFragments,
runtime,
runtimeRequirements
});
source.replace(dep.range[0], dep.range[1] - 1, exportExpr);
} }
}; };

View File

@ -28,6 +28,7 @@ const {
evaluateToIdentifier, evaluateToIdentifier,
toConstantDependency toConstantDependency
} = require("../javascript/JavascriptParserHelpers"); } = require("../javascript/JavascriptParserHelpers");
const CommonJsExportRequireDependency = require("./CommonJsExportRequireDependency");
class CommonJsPlugin { class CommonJsPlugin {
constructor(options) { constructor(options) {
@ -99,6 +100,15 @@ class CommonJsPlugin {
new CommonJsExportsDependency.Template() new CommonJsExportsDependency.Template()
); );
compilation.dependencyFactories.set(
CommonJsExportRequireDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
CommonJsExportRequireDependency,
new CommonJsExportRequireDependency.Template()
);
const selfFactory = new SelfModuleFactory(compilation.moduleGraph); const selfFactory = new SelfModuleFactory(compilation.moduleGraph);
compilation.dependencyFactories.set( compilation.dependencyFactories.set(
@ -203,7 +213,9 @@ class CommonJsPlugin {
); );
new CommonJsImportsParserPlugin(options).apply(parser); new CommonJsImportsParserPlugin(options).apply(parser);
new CommonJsExportsParserPlugin().apply(parser); new CommonJsExportsParserPlugin(compilation.moduleGraph).apply(
parser
);
}; };
normalModuleFactory.hooks.parser normalModuleFactory.hooks.parser

View File

@ -5,8 +5,8 @@
"use strict"; "use strict";
const { UsageState } = require("../ExportsInfo");
const RuntimeGlobals = require("../RuntimeGlobals"); const RuntimeGlobals = require("../RuntimeGlobals");
const { equals } = require("../util/ArrayHelpers");
const makeSerializable = require("../util/makeSerializable"); const makeSerializable = require("../util/makeSerializable");
const propertyAccess = require("../util/propertyAccess"); const propertyAccess = require("../util/propertyAccess");
const NullDependency = require("./NullDependency"); const NullDependency = require("./NullDependency");
@ -20,11 +20,12 @@ const NullDependency = require("./NullDependency");
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
class CommonJsSelfReferenceDependency extends NullDependency { class CommonJsSelfReferenceDependency extends NullDependency {
constructor(range, base, names) { constructor(range, base, names, call) {
super(); super();
this.range = range; this.range = range;
this.base = base; this.base = base;
this.names = names; this.names = names;
this.call = call;
} }
get type() { get type() {
@ -49,7 +50,7 @@ class CommonJsSelfReferenceDependency extends NullDependency {
* @returns {(string[] | ReferencedExport)[]} referenced exports * @returns {(string[] | ReferencedExport)[]} referenced exports
*/ */
getReferencedExports(moduleGraph, runtime) { getReferencedExports(moduleGraph, runtime) {
return [this.names]; return [this.call ? this.names.slice(0, -1) : this.names];
} }
serialize(context) { serialize(context) {
@ -57,6 +58,7 @@ class CommonJsSelfReferenceDependency extends NullDependency {
write(this.range); write(this.range);
write(this.base); write(this.base);
write(this.names); write(this.names);
write(this.call);
super.serialize(context); super.serialize(context);
} }
@ -65,6 +67,7 @@ class CommonJsSelfReferenceDependency extends NullDependency {
this.range = read(); this.range = read();
this.base = read(); this.base = read();
this.names = read(); this.names = read();
this.call = read();
super.deserialize(context); super.deserialize(context);
} }
} }
@ -90,13 +93,6 @@ CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependency
let used; let used;
if (dep.names.length === 0) { if (dep.names.length === 0) {
used = dep.names; used = dep.names;
} else if (module.buildMeta && module.buildMeta.exportsType === "default") {
const defaultInfo = moduleGraph.getExportInfo(module, "default");
if (defaultInfo.getUsed(runtime) === UsageState.Used) {
used = dep.names;
} else {
used = defaultInfo.exportsInfo.getUsedName(dep.names, runtime);
}
} else { } else {
used = moduleGraph.getExportsInfo(module).getUsedName(dep.names, runtime); used = moduleGraph.getExportsInfo(module).getUsedName(dep.names, runtime);
} }
@ -124,7 +120,7 @@ CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependency
throw new Error(`Unsupported base ${dep.base}`); throw new Error(`Unsupported base ${dep.base}`);
} }
if (base === dep.base && used.join() === dep.names.join()) { if (base === dep.base && equals(used, dep.names)) {
// Nothing has to be changed // Nothing has to be changed
// We don't use a replacement for compat reasons // We don't use a replacement for compat reasons
// for plugins that update `module._source` which they // for plugins that update `module._source` which they
@ -135,7 +131,7 @@ CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependency
source.replace( source.replace(
dep.range[0], dep.range[0],
dep.range[1] - 1, dep.range[1] - 1,
`/* self exports access */ ${base}${propertyAccess(used)}` `${base}${propertyAccess(used)}`
); );
} }
}; };

View File

@ -44,7 +44,19 @@ exports.enable = parserState => {
exports.setFlagged = parserState => { exports.setFlagged = parserState => {
const value = parserStateExportsState.get(parserState); const value = parserStateExportsState.get(parserState);
if (value !== true) return; if (value !== true) return;
parserState.module.buildMeta.exportsType = "flagged"; const buildMeta = parserState.module.buildMeta;
if (buildMeta.exportsType === "dynamic") return;
buildMeta.exportsType = "flagged";
};
/**
* @param {ParserState} parserState parser state
* @returns {void}
*/
exports.setDynamic = parserState => {
const value = parserStateExportsState.get(parserState);
if (value !== true) return;
parserState.module.buildMeta.exportsType = "dynamic";
}; };
/** /**

View File

@ -5,6 +5,7 @@
"use strict"; "use strict";
const { UsageState } = require("../ExportsInfo");
const InitFragment = require("../InitFragment"); const InitFragment = require("../InitFragment");
const RuntimeGlobals = require("../RuntimeGlobals"); const RuntimeGlobals = require("../RuntimeGlobals");
const makeSerializable = require("../util/makeSerializable"); const makeSerializable = require("../util/makeSerializable");
@ -45,9 +46,11 @@ HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate
runtime runtime
} }
) { ) {
// TODO avoid getUsedExports const exportsInfo = moduleGraph.getExportsInfo(module);
const usedExports = moduleGraph.getUsedExports(module, runtime); if (
if (usedExports === true || usedExports === null) { exportsInfo.getReadOnlyExportInfo("__esModule").getUsed(runtime) !==
UsageState.Unused
) {
const content = runtimeTemplate.defineEsModuleFlagStatement({ const content = runtimeTemplate.defineEsModuleFlagStatement({
exportsArgument: module.exportsArgument, exportsArgument: module.exportsArgument,
runtimeRequirements runtimeRequirements
@ -63,17 +66,15 @@ HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate
} }
if (moduleGraph.isAsync(module)) { if (moduleGraph.isAsync(module)) {
runtimeRequirements.add(RuntimeGlobals.module); runtimeRequirements.add(RuntimeGlobals.module);
if (usedExports !== false) const used = exportsInfo.isUsed(runtime);
runtimeRequirements.add(RuntimeGlobals.exports); if (used) runtimeRequirements.add(RuntimeGlobals.exports);
initFragments.push( initFragments.push(
new InitFragment( new InitFragment(
`${module.moduleArgument}.exports = (async () => {\n`, `${module.moduleArgument}.exports = (async () => {\n`,
InitFragment.STAGE_ASYNC_BOUNDARY, InitFragment.STAGE_ASYNC_BOUNDARY,
0, 0,
undefined, undefined,
usedExports !== false used ? `\nreturn ${module.exportsArgument};\n})();` : "\n})();"
? `\nreturn ${module.exportsArgument};\n})();`
: "\n})();"
) )
); );
} }

View File

@ -15,6 +15,7 @@ const makeSerializable = require("../util/makeSerializable");
const propertyAccess = require("../util/propertyAccess"); const propertyAccess = require("../util/propertyAccess");
const HarmonyExportInitFragment = require("./HarmonyExportInitFragment"); const HarmonyExportInitFragment = require("./HarmonyExportInitFragment");
const HarmonyImportDependency = require("./HarmonyImportDependency"); const HarmonyImportDependency = require("./HarmonyImportDependency");
const processExportInfo = require("./processExportInfo");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../ChunkGraph")} ChunkGraph */ /** @typedef {import("../ChunkGraph")} ChunkGraph */
@ -37,54 +38,6 @@ const HarmonyImportDependency = require("./HarmonyImportDependency");
const idsSymbol = Symbol("HarmonyExportImportedSpecifierDependency.ids"); const idsSymbol = Symbol("HarmonyExportImportedSpecifierDependency.ids");
/**
* @param {RuntimeSpec} runtime the runtime
* @param {string[][]} referencedExports list of referenced exports, will be added to
* @param {string[]} prefix export prefix
* @param {ExportInfo=} exportInfo the export info
* @param {boolean} defaultPointsToSelf when true, using default will reference itself
* @param {Set<ExportInfo>} alreadyVisited already visited export info (to handle circular reexports)
*/
const processExportInfo = (
runtime,
referencedExports,
prefix,
exportInfo,
defaultPointsToSelf = false,
alreadyVisited = new Set()
) => {
if (!exportInfo) {
referencedExports.push(prefix);
return;
}
if (alreadyVisited.has(exportInfo)) return;
alreadyVisited.add(exportInfo);
const used = exportInfo.getUsed(runtime);
if (used === UsageState.Unused) return;
if (
used !== UsageState.OnlyPropertiesUsed ||
!exportInfo.exportsInfo ||
exportInfo.exportsInfo.otherExportsInfo.getUsed(runtime) !==
UsageState.Unused
) {
referencedExports.push(prefix);
return;
}
const exportsInfo = exportInfo.exportsInfo;
for (const exportInfo of exportsInfo.orderedExports) {
processExportInfo(
runtime,
referencedExports,
defaultPointsToSelf && exportInfo.name === "default"
? prefix
: prefix.concat(exportInfo.name),
exportInfo,
false,
alreadyVisited
);
}
};
class NormalReexportItem { class NormalReexportItem {
/** /**
* @param {string} name export name * @param {string} name export name
@ -229,6 +182,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
} }
const importedExportsType = importedModule.getExportsType( const importedExportsType = importedModule.getExportsType(
moduleGraph,
parentModule.buildMeta.strictHarmonyModule parentModule.buildMeta.strictHarmonyModule
); );
@ -403,7 +357,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
if (exportInfo.getUsed(runtime) === UsageState.Unused) continue; if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
exports.add(name); exports.add(name);
if (importedExportInfo.provided === true) continue; if (importedExportInfo.provided === true) continue;
checked.add(exportInfo.name); checked.add(name);
} }
} }

View File

@ -104,6 +104,7 @@ class HarmonyImportDependency extends ModuleDependency {
const parentModule = moduleGraph.getParentModule(this); const parentModule = moduleGraph.getParentModule(this);
const exportsType = importedModule.getExportsType( const exportsType = importedModule.getExportsType(
moduleGraph,
parentModule.buildMeta.strictHarmonyModule parentModule.buildMeta.strictHarmonyModule
); );
switch (exportsType) { switch (exportsType) {
@ -199,16 +200,18 @@ class HarmonyImportDependency extends ModuleDependency {
*/ */
updateHash(hash, context) { updateHash(hash, context) {
const { chunkGraph } = context; const { chunkGraph } = context;
const { moduleGraph } = chunkGraph;
super.updateHash(hash, context); super.updateHash(hash, context);
const importedModule = chunkGraph.moduleGraph.getModule(this); const importedModule = moduleGraph.getModule(this);
if (importedModule) { if (importedModule) {
const parentModule = chunkGraph.moduleGraph.getParentModule(this); const parentModule = moduleGraph.getParentModule(this);
hash.update( hash.update(
importedModule.getExportsType( importedModule.getExportsType(
moduleGraph,
parentModule.buildMeta && parentModule.buildMeta.strictHarmonyModule parentModule.buildMeta && parentModule.buildMeta.strictHarmonyModule
) )
); );
if (chunkGraph.moduleGraph.isAsync(importedModule)) hash.update("async"); if (moduleGraph.isAsync(importedModule)) hash.update("async");
} }
hash.update(`${this.sourceOrder}`); hash.update(`${this.sourceOrder}`);
} }

View File

@ -113,7 +113,10 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
const selfModule = moduleGraph.getParentModule(this); const selfModule = moduleGraph.getParentModule(this);
const importedModule = moduleGraph.getModule(this); const importedModule = moduleGraph.getModule(this);
switch ( switch (
importedModule.getExportsType(selfModule.buildMeta.strictHarmonyModule) importedModule.getExportsType(
moduleGraph,
selfModule.buildMeta.strictHarmonyModule
)
) { ) {
case "default-only": case "default-only":
case "default-with-named": case "default-with-named":

View File

@ -0,0 +1,65 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { UsageState } = require("../ExportsInfo");
/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
/**
* @param {RuntimeSpec} runtime the runtime
* @param {string[][]} referencedExports list of referenced exports, will be added to
* @param {string[]} prefix export prefix
* @param {ExportInfo=} exportInfo the export info
* @param {boolean} defaultPointsToSelf when true, using default will reference itself
* @param {Set<ExportInfo>} alreadyVisited already visited export info (to handle circular reexports)
*/
const processExportInfo = (
runtime,
referencedExports,
prefix,
exportInfo,
defaultPointsToSelf = false,
alreadyVisited = new Set()
) => {
if (!exportInfo) {
referencedExports.push(prefix);
return;
}
const used = exportInfo.getUsed(runtime);
if (used === UsageState.Unused) return;
if (alreadyVisited.has(exportInfo)) {
referencedExports.push(prefix);
return;
}
alreadyVisited.add(exportInfo);
if (
used !== UsageState.OnlyPropertiesUsed ||
!exportInfo.exportsInfo ||
exportInfo.exportsInfo.otherExportsInfo.getUsed(runtime) !==
UsageState.Unused
) {
alreadyVisited.delete(exportInfo);
referencedExports.push(prefix);
return;
}
const exportsInfo = exportInfo.exportsInfo;
for (const exportInfo of exportsInfo.orderedExports) {
processExportInfo(
runtime,
referencedExports,
defaultPointsToSelf && exportInfo.name === "default"
? prefix
: prefix.concat(exportInfo.name),
exportInfo,
false,
alreadyVisited
);
}
alreadyVisited.delete(exportInfo);
};
module.exports = processExportInfo;

View File

@ -17,6 +17,7 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
/** @typedef {import("estree").ArrayExpression} ArrayExpressionNode */ /** @typedef {import("estree").ArrayExpression} ArrayExpressionNode */
/** @typedef {import("estree").BinaryExpression} BinaryExpressionNode */ /** @typedef {import("estree").BinaryExpression} BinaryExpressionNode */
/** @typedef {import("estree").BlockStatement} BlockStatementNode */ /** @typedef {import("estree").BlockStatement} BlockStatementNode */
/** @typedef {import("estree").SequenceExpression} SequenceExpressionNode */
/** @typedef {import("estree").CallExpression} CallExpressionNode */ /** @typedef {import("estree").CallExpression} CallExpressionNode */
/** @typedef {import("estree").ClassDeclaration} ClassDeclarationNode */ /** @typedef {import("estree").ClassDeclaration} ClassDeclarationNode */
/** @typedef {import("estree").ClassExpression} ClassExpressionNode */ /** @typedef {import("estree").ClassExpression} ClassExpressionNode */
@ -235,7 +236,7 @@ class JavascriptParser extends Parser {
/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */ /** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */
call: new HookMap(() => new SyncBailHook(["expression"])), call: new HookMap(() => new SyncBailHook(["expression"])),
/** Something like "a.b()" */ /** Something like "a.b()" */
/** @type {HookMap<SyncBailHook<[ExpressionNode, string[]], boolean | void>>} */ /** @type {HookMap<SyncBailHook<[CallExpressionNode, string[]], boolean | void>>} */
callMemberChain: new HookMap( callMemberChain: new HookMap(
() => new SyncBailHook(["expression", "members"]) () => new SyncBailHook(["expression", "members"])
), ),
@ -294,6 +295,7 @@ class JavascriptParser extends Parser {
this.state = undefined; this.state = undefined;
this.comments = undefined; this.comments = undefined;
this.semicolons = undefined; this.semicolons = undefined;
/** @type {(StatementNode|ExpressionNode)[]} */
this.statementPath = undefined; this.statementPath = undefined;
this.prevStatement = undefined; this.prevStatement = undefined;
this.currentTagData = undefined; this.currentTagData = undefined;
@ -983,7 +985,7 @@ class JavascriptParser extends Parser {
.setSideEffects(param.couldHaveSideEffects()) .setSideEffects(param.couldHaveSideEffects())
.setRange(expr.range); .setRange(expr.range);
}); });
["substr", "substring"].forEach(fn => { ["substr", "substring", "slice"].forEach(fn => {
this.hooks.evaluateCallExpressionMember this.hooks.evaluateCallExpressionMember
.for(fn) .for(fn)
.tap("JavascriptParser", (expr, param) => { .tap("JavascriptParser", (expr, param) => {
@ -2242,8 +2244,29 @@ class JavascriptParser extends Parser {
this.scope.topLevelScope = wasTopLevel; this.scope.topLevelScope = wasTopLevel;
} }
/**
* @param {SequenceExpressionNode} expression the sequence
*/
walkSequenceExpression(expression) { walkSequenceExpression(expression) {
if (expression.expressions) this.walkExpressions(expression.expressions); if (!expression.expressions) return;
// We treat sequence expressions like statements when they are one statement level
// This has some benefits for optimizations that only work on statement level
const currentStatement = this.statementPath[this.statementPath.length - 1];
if (
currentStatement === expression ||
(currentStatement.type === "ExpressionStatement" &&
currentStatement.expression === expression)
) {
const old = this.statementPath.pop();
for (const expr of expression.expressions) {
this.statementPath.push(expr);
this.walkExpression(expr);
this.statementPath.pop();
}
this.statementPath.push(old);
} else {
this.walkExpressions(expression.expressions);
}
} }
walkUpdateExpression(expression) { walkUpdateExpression(expression) {
@ -2325,8 +2348,8 @@ class JavascriptParser extends Parser {
}); });
return; return;
} }
this.walkExpression(expression.right);
if (expression.left.type.endsWith("Pattern")) { if (expression.left.type.endsWith("Pattern")) {
this.walkExpression(expression.right);
this.enterPattern(expression.left, (name, decl) => { this.enterPattern(expression.left, (name, decl) => {
if (!this.callHooksForName(this.hooks.assign, name, expression)) { if (!this.callHooksForName(this.hooks.assign, name, expression)) {
this.defineVariable(name); this.defineVariable(name);
@ -2349,8 +2372,10 @@ class JavascriptParser extends Parser {
return; return;
} }
} }
this.walkExpression(expression.right);
this.walkExpression(expression.left); this.walkExpression(expression.left);
} else { } else {
this.walkExpression(expression.right);
this.walkExpression(expression.left); this.walkExpression(expression.left);
} }
} }
@ -2565,14 +2590,20 @@ class JavascriptParser extends Parser {
if (exprInfo) { if (exprInfo) {
switch (exprInfo.type) { switch (exprInfo.type) {
case "expression": { case "expression": {
const result1 = this.callHooksForInfo(
this.hooks.expression,
exprInfo.name,
expression
);
if (result1 === true) return;
const members = exprInfo.getMembers(); const members = exprInfo.getMembers();
const result = this.callHooksForInfo( const result2 = this.callHooksForInfo(
this.hooks.expressionMemberChain, this.hooks.expressionMemberChain,
exprInfo.rootInfo, exprInfo.rootInfo,
expression, expression,
members members
); );
if (result === true) return; if (result2 === true) return;
this.walkMemberExpressionWithExpressionName( this.walkMemberExpressionWithExpressionName(
expression, expression,
exprInfo.name, exprInfo.name,
@ -2616,12 +2647,6 @@ class JavascriptParser extends Parser {
members, members,
onUnhandled onUnhandled
) { ) {
const result = this.callHooksForInfo(
this.hooks.expression,
name,
expression
);
if (result === true) return;
if (expression.object.type === "MemberExpression") { if (expression.object.type === "MemberExpression") {
// optimize the case where expression.object is a MemberExpression too. // optimize the case where expression.object is a MemberExpression too.
// we can keep info here when calling walkMemberExpression directly // we can keep info here when calling walkMemberExpression directly
@ -2629,6 +2654,12 @@ class JavascriptParser extends Parser {
expression.property.name || `${expression.property.value}`; expression.property.name || `${expression.property.value}`;
name = name.slice(0, -property.length - 1); name = name.slice(0, -property.length - 1);
members.pop(); members.pop();
const result = this.callHooksForInfo(
this.hooks.expression,
name,
expression.object
);
if (result === true) return;
this.walkMemberExpressionWithExpressionName( this.walkMemberExpressionWithExpressionName(
expression.object, expression.object,
name, name,
@ -3170,6 +3201,15 @@ class JavascriptParser extends Parser {
); );
} }
isStatementLevelExpression(expr) {
const currentStatement = this.statementPath[this.statementPath.length - 1];
return (
expr === currentStatement ||
(currentStatement.type === "ExpressionStatement" &&
currentStatement.expression === expr)
);
}
getTagData(name, tag) { getTagData(name, tag) {
const info = this.scope.definitions.get(name); const info = this.scope.definitions.get(name);
if (info instanceof VariableInfo) { if (info instanceof VariableInfo) {

View File

@ -256,7 +256,10 @@ const getExternalImport = (
asiSafe asiSafe
) => { ) => {
let exprStart = info.name; let exprStart = info.name;
const exportsType = importedModule.getExportsType(strictHarmonyModule); const exportsType = importedModule.getExportsType(
moduleGraph,
strictHarmonyModule
);
if (exportName.length === 0) { if (exportName.length === 0) {
switch (exportsType) { switch (exportsType) {
case "default-only": case "default-only":
@ -1197,6 +1200,7 @@ class ConcatenatedModule extends Module {
if ( if (
info.module.buildMeta.exportsType === "default" || info.module.buildMeta.exportsType === "default" ||
info.module.buildMeta.exportsType === "flagged" || info.module.buildMeta.exportsType === "flagged" ||
info.module.buildMeta.exportsType === "dynamic" ||
!info.module.buildMeta.exportsType !info.module.buildMeta.exportsType
) { ) {
const externalNameInterop = this.findNewName( const externalNameInterop = this.findNewName(
@ -1208,7 +1212,10 @@ class ConcatenatedModule extends Module {
allUsedNames.add(externalNameInterop); allUsedNames.add(externalNameInterop);
info.interopNamespaceObjectName = externalNameInterop; info.interopNamespaceObjectName = externalNameInterop;
} }
if (!info.module.buildMeta.exportsType) { if (
info.module.buildMeta.exportsType === "dynamic" ||
!info.module.buildMeta.exportsType
) {
const externalNameInterop = this.findNewName( const externalNameInterop = this.findNewName(
"default", "default",
allUsedNames, allUsedNames,
@ -1436,6 +1443,7 @@ class ConcatenatedModule extends Module {
); );
} else if ( } else if (
info.module.buildMeta.exportsType === "flagged" || info.module.buildMeta.exportsType === "flagged" ||
info.module.buildMeta.exportsType === "dynamic" ||
!info.module.buildMeta.exportsType !info.module.buildMeta.exportsType
) { ) {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);

View File

@ -51,17 +51,23 @@ const mangleExportsInfo = (deterministic, exportsInfo, canBeArray) => {
/** @type {ExportInfo[]} */ /** @type {ExportInfo[]} */
const mangleableExports = []; const mangleableExports = [];
const empty = canBeArray ? ARRAY : OBJECT; const empty = canBeArray ? ARRAY : OBJECT;
// Don't rename 1-2 char exports or exports that can't be mangled
for (const exportInfo of exportsInfo.ownedExports) { for (const exportInfo of exportsInfo.ownedExports) {
const name = exportInfo.name; const name = exportInfo.name;
if (!exportInfo.hasUsedName()) { if (!exportInfo.hasUsedName()) {
if ( if (
// Can the export be mangled?
exportInfo.canMangle !== true || exportInfo.canMangle !== true ||
// Never rename 1 char exports
(name.length === 1 && /^[a-zA-Z0-9_$]/.test(name)) || (name.length === 1 && /^[a-zA-Z0-9_$]/.test(name)) ||
// Don't rename 2 char exports in deterministic mode
(deterministic && (deterministic &&
name.length === 2 && name.length === 2 &&
/^[a-zA-Z_$][a-zA-Z0-9_$]|^[1-9][0-9]/.test(name)) || /^[a-zA-Z_$][a-zA-Z0-9_$]|^[1-9][0-9]/.test(name)) ||
(exportInfo.provided !== true && exportInfo.name in empty) // Don't rename exports that are not provided and in prototype chain of JSON
(exportInfo.provided !== true && exportInfo.name in empty) ||
// Don't rename exports that are neither provided nor used
(exportInfo.provided === false &&
exportInfo.getUsed(undefined) === UsageState.Unused)
) { ) {
exportInfo.setUsedName(name); exportInfo.setUsedName(name);
usedNames.add(name); usedNames.add(name);

View File

@ -47,6 +47,8 @@ module.exports = {
require("../dependencies/CachedConstDependency"), require("../dependencies/CachedConstDependency"),
"dependencies/CommonJsRequireContextDependency": () => "dependencies/CommonJsRequireContextDependency": () =>
require("../dependencies/CommonJsRequireContextDependency"), require("../dependencies/CommonJsRequireContextDependency"),
"dependencies/CommonJsExportRequireDependency": () =>
require("../dependencies/CommonJsExportRequireDependency"),
"dependencies/CommonJsExportsDependency": () => "dependencies/CommonJsExportsDependency": () =>
require("../dependencies/CommonJsExportsDependency"), require("../dependencies/CommonJsExportsDependency"),
"dependencies/CommonJsFullRequireDependency": () => "dependencies/CommonJsFullRequireDependency": () =>

View File

@ -521,10 +521,10 @@ exports[`StatsTestCases should print correct stats for chunks-development 1`] =
Time: X ms Time: X ms
Built at: 1970-04-20 12:42:42 Built at: 1970-04-20 12:42:42
PublicPath: (none) PublicPath: (none)
asset b_js.bundle.js 901 bytes [emitted] asset b_js.bundle.js 968 bytes [emitted]
asset bundle.js 9.75 KiB [emitted] (name: main) asset bundle.js 9.82 KiB [emitted] (name: main)
asset c_js.bundle.js 1.1 KiB [emitted] asset c_js.bundle.js 1.1 KiB [emitted]
asset d_js-e_js.bundle.js 1.25 KiB [emitted] asset d_js-e_js.bundle.js 1.38 KiB [emitted]
Entrypoint main = bundle.js Entrypoint main = bundle.js
chunk b_js.bundle.js 22 bytes <{main}> [rendered] chunk b_js.bundle.js 22 bytes <{main}> [rendered]
> ./b ./index.js 2:0-16 > ./b ./index.js 2:0-16
@ -600,6 +600,19 @@ Entrypoint <CLR=BOLD>main</CLR> = <CLR=32>main.js</CLR>
<CLR=BOLD>./index.js</CLR> 1 bytes <CLR=32>[built]</CLR>" <CLR=BOLD>./index.js</CLR> 1 bytes <CLR=32>[built]</CLR>"
`; `;
exports[`StatsTestCases should print correct stats for common-libs 1`] = `
"Hash: cb2d8154f4c30528e43b
Time: X ms
Built at: 1970-04-20 12:42:42
asset react.js 3.12 KiB [emitted] [minimized] (name: react)
asset react.js.LICENSE.txt 295 bytes [emitted]
Entrypoint react = react.js
./react.js 69 bytes [built]
../../../node_modules/react/index.js 190 bytes [built]
../../../node_modules/react/cjs/react.production.min.js 6.52 KiB [built]
../../../node_modules/object-assign/index.js 2.06 KiB [built]"
`;
exports[`StatsTestCases should print correct stats for commons-chunk-min-size-0 1`] = ` exports[`StatsTestCases should print correct stats for commons-chunk-min-size-0 1`] = `
"Hash: b96c5a233eb1688dd315 "Hash: b96c5a233eb1688dd315
Time: X ms Time: X ms
@ -2114,18 +2127,22 @@ chunk {996} (runtime: main) 996.js 22 bytes <{179}> [rendered]
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
[847] ./a.js 22 bytes {179} [depth 1] [built] [847] ./a.js 22 bytes {179} [depth 1] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
[996] ./b.js 22 bytes {996} [depth 1] [built] [996] ./b.js 22 bytes {996} [depth 1] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
[460] ./c.js 54 bytes {460} [depth 1] [built] [460] ./c.js 54 bytes {460} [depth 1] [built]
[used exports unknown] [used exports unknown]
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
[767] ./d.js 22 bytes {524} [depth 2] [built] [767] ./d.js 22 bytes {524} [depth 2] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
[390] ./e.js 22 bytes {524} [depth 2] [built] [390] ./e.js 22 bytes {524} [depth 2] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
webpack/runtime/ensure chunk 326 bytes {179} [runtime] webpack/runtime/ensure chunk 326 bytes {179} [runtime]
[no exports] [no exports]
@ -2342,6 +2359,7 @@ chunk {179} (runtime: main) main.js (main) 73 bytes (javascript) 4.88 KiB (runti
> ./index main > ./index main
[847] ./a.js 22 bytes {179} [depth 1] [built] [847] ./a.js 22 bytes {179} [depth 1] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
cjs self exports reference [847] ./a.js 1:0-14 cjs self exports reference [847] ./a.js 1:0-14
cjs require ./a [10] ./index.js 1:0-14 cjs require ./a [10] ./index.js 1:0-14
@ -2380,12 +2398,14 @@ chunk {524} (runtime: main) 524.js 44 bytes <{460}> [rendered]
> [460] ./c.js 1:0-52 > [460] ./c.js 1:0-52
[767] ./d.js 22 bytes {524} [depth 2] [built] [767] ./d.js 22 bytes {524} [depth 2] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
require.ensure item ./d [460] ./c.js 1:0-52 require.ensure item ./d [460] ./c.js 1:0-52
cjs self exports reference [767] ./d.js 1:0-14 cjs self exports reference [767] ./d.js 1:0-14
X ms [10] -> X ms [460] -> X ms (resolving: X ms, restoring: X ms, integration: X ms, building: X ms, storing: X ms) X ms [10] -> X ms [460] -> X ms (resolving: X ms, restoring: X ms, integration: X ms, building: X ms, storing: X ms)
[390] ./e.js 22 bytes {524} [depth 2] [built] [390] ./e.js 22 bytes {524} [depth 2] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
require.ensure item ./e [460] ./c.js 1:0-52 require.ensure item ./e [460] ./c.js 1:0-52
cjs self exports reference [390] ./e.js 1:0-14 cjs self exports reference [390] ./e.js 1:0-14
@ -2394,6 +2414,7 @@ chunk {996} (runtime: main) 996.js 22 bytes <{179}> [rendered]
> ./b [10] ./index.js 2:0-16 > ./b [10] ./index.js 2:0-16
[996] ./b.js 22 bytes {996} [depth 1] [built] [996] ./b.js 22 bytes {996} [depth 1] [built]
[used exports unknown] [used exports unknown]
CommonJS bailout: module.exports is used directly at 1:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
cjs self exports reference [996] ./b.js 1:0-14 cjs self exports reference [996] ./b.js 1:0-14
amd require ./b [10] ./index.js 2:0-16 amd require ./b [10] ./index.js 2:0-16
@ -2944,6 +2965,7 @@ Entrypoint entry = entry.js
ModuleConcatenation bailout: Cannot concat with ./ref-from-cjs.js: Module ./ref-from-cjs.js is referenced from these modules with unsupported syntax: ./cjs.js (referenced with cjs require) ModuleConcatenation bailout: Cannot concat with ./ref-from-cjs.js: Module ./ref-from-cjs.js is referenced from these modules with unsupported syntax: ./cjs.js (referenced with cjs require)
./entry.js 32 bytes [built] ./entry.js 32 bytes [built]
./cjs.js 59 bytes [built] ./cjs.js 59 bytes [built]
CommonJS bailout: module.exports is used directly at 3:0-14
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
./ref-from-cjs.js 45 bytes [built] ./ref-from-cjs.js 45 bytes [built]
./eval.js 35 bytes [built] ./eval.js 35 bytes [built]
@ -3065,9 +3087,9 @@ Entrypoint main = main.js
`; `;
exports[`StatsTestCases should print correct stats for side-effects-optimization 1`] = ` exports[`StatsTestCases should print correct stats for side-effects-optimization 1`] = `
"Hash: d26335b5c063fdfc2a88c8cd6c316db9be4953d2 "Hash: dfef98e0ef4320bb5e7c18a1362fdec91250a8dc
Child Child
Hash: d26335b5c063fdfc2a88 Hash: dfef98e0ef4320bb5e7c
Time: X ms Time: X ms
Built at: 1970-04-20 12:42:42 Built at: 1970-04-20 12:42:42
asset main.js 207 bytes [emitted] [minimized] (name: main) asset main.js 207 bytes [emitted] [minimized] (name: main)
@ -3088,7 +3110,7 @@ Child
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
+ 4 hidden modules + 4 hidden modules
Child Child
Hash: c8cd6c316db9be4953d2 Hash: 18a1362fdec91250a8dc
Time: X ms Time: X ms
Built at: 1970-04-20 12:42:42 Built at: 1970-04-20 12:42:42
asset main.no-side.js 1.24 KiB [emitted] [minimized] (name: main) asset main.no-side.js 1.24 KiB [emitted] [minimized] (name: main)
@ -4269,7 +4291,7 @@ Child global:
`; `;
exports[`StatsTestCases should print correct stats for tree-shaking 1`] = ` exports[`StatsTestCases should print correct stats for tree-shaking 1`] = `
"Hash: e0f1716012b18c82ad97 "Hash: 9b742a666c2c28e22fdf
Time: X ms Time: X ms
Built at: 1970-04-20 12:42:42 Built at: 1970-04-20 12:42:42
asset bundle.js 7.09 KiB [emitted] (name: main) asset bundle.js 7.09 KiB [emitted] (name: main)

61
types.d.ts vendored
View File

@ -3478,7 +3478,7 @@ declare abstract class JavascriptParser extends Parser {
topLevelAwait: SyncBailHook<[Expression], boolean | void>; topLevelAwait: SyncBailHook<[Expression], boolean | void>;
call: HookMap<SyncBailHook<[Expression], boolean | void>>; call: HookMap<SyncBailHook<[Expression], boolean | void>>;
callMemberChain: HookMap< callMemberChain: HookMap<
SyncBailHook<[Expression, string[]], boolean | void> SyncBailHook<[CallExpression, string[]], boolean | void>
>; >;
memberChainOfCallMemberChain: HookMap< memberChainOfCallMemberChain: HookMap<
SyncBailHook< SyncBailHook<
@ -3513,9 +3513,56 @@ declare abstract class JavascriptParser extends Parser {
state: Record<string, any> & ParserStateBase; state: Record<string, any> & ParserStateBase;
comments: any; comments: any;
semicolons: any; semicolons: any;
statementEndPos: any; statementPath: (
lastStatementEndPos: any; | UnaryExpression
statementStartPos: any; | ThisExpression
| ArrayExpression
| ObjectExpression
| FunctionExpression
| ArrowFunctionExpression
| YieldExpression
| SimpleLiteral
| RegExpLiteral
| UpdateExpression
| BinaryExpression
| AssignmentExpression
| LogicalExpression
| MemberExpression
| ConditionalExpression
| SimpleCallExpression
| NewExpression
| SequenceExpression
| TemplateLiteral
| TaggedTemplateExpression
| ClassExpression
| MetaProperty
| Identifier
| AwaitExpression
| ImportExpression
| ChainExpression
| ExpressionStatement
| BlockStatement
| EmptyStatement
| DebuggerStatement
| WithStatement
| ReturnStatement
| LabeledStatement
| BreakStatement
| ContinueStatement
| IfStatement
| SwitchStatement
| ThrowStatement
| TryStatement
| WhileStatement
| DoWhileStatement
| ForStatement
| ForInStatement
| ForOfStatement
| FunctionDeclaration
| VariableDeclaration
| ClassDeclaration
)[];
prevStatement: any;
currentTagData: any; currentTagData: any;
initializeEvaluating(): void; initializeEvaluating(): void;
getRenameIdentifier(expr?: any): string; getRenameIdentifier(expr?: any): string;
@ -3584,7 +3631,7 @@ declare abstract class JavascriptParser extends Parser {
walkObjectExpression(expression?: any): void; walkObjectExpression(expression?: any): void;
walkFunctionExpression(expression?: any): void; walkFunctionExpression(expression?: any): void;
walkArrowFunctionExpression(expression?: any): void; walkArrowFunctionExpression(expression?: any): void;
walkSequenceExpression(expression?: any): void; walkSequenceExpression(expression: SequenceExpression): void;
walkUpdateExpression(expression?: any): void; walkUpdateExpression(expression?: any): void;
walkUnaryExpression(expression?: any): void; walkUnaryExpression(expression?: any): void;
walkLeftRightExpression(expression?: any): void; walkLeftRightExpression(expression?: any): void;
@ -3664,6 +3711,7 @@ declare abstract class JavascriptParser extends Parser {
evaluate(source?: any): BasicEvaluatedExpression; evaluate(source?: any): BasicEvaluatedExpression;
getComments(range?: any): any; getComments(range?: any): any;
isAsiPosition(pos?: any): any; isAsiPosition(pos?: any): any;
isStatementLevelExpression(expr?: any): boolean;
getTagData(name?: any, tag?: any): any; getTagData(name?: any, tag?: any): any;
tagVariable(name?: any, tag?: any, data?: any): void; tagVariable(name?: any, tag?: any, data?: any): void;
defineVariable(name?: any): void; defineVariable(name?: any): void;
@ -3759,7 +3807,7 @@ declare interface KnownBuildMeta {
exportsArgument?: string; exportsArgument?: string;
strict?: boolean; strict?: boolean;
moduleConcatenationBailout?: string; moduleConcatenationBailout?: string;
exportsType?: "namespace" | "default" | "flagged"; exportsType?: "namespace" | "dynamic" | "default" | "flagged";
defaultObject?: false | "redirect" | "redirect-warn"; defaultObject?: false | "redirect" | "redirect-warn";
strictHarmonyModule?: boolean; strictHarmonyModule?: boolean;
async?: boolean; async?: boolean;
@ -4176,6 +4224,7 @@ declare class Module extends DependenciesBlock {
readonly exportsArgument: string; readonly exportsArgument: string;
readonly moduleArgument: string; readonly moduleArgument: string;
getExportsType( getExportsType(
moduleGraph: ModuleGraph,
strict: boolean strict: boolean
): "namespace" | "default-only" | "default-with-named" | "dynamic"; ): "namespace" | "default-only" | "default-with-named" | "dynamic";
addPresentationalDependency(presentationalDependency: Dependency): void; addPresentationalDependency(presentationalDependency: Dependency): void;