mirror of https://github.com/webpack/webpack.git
				
				
				
			add support for reexporting in CommonJS
and necessary refactoring + fixes for that
This commit is contained in:
		
							parent
							
								
									0090eb941c
								
							
						
					
					
						commit
						71cf7f4dc8
					
				|  | @ -490,6 +490,7 @@ class ContextModule extends Module { | |||
| 		const fakeMap = Object.create(null); | ||||
| 		for (const module of sortedModules) { | ||||
| 			const exportsType = module.getExportsType( | ||||
| 				moduleGraph, | ||||
| 				this.options.namespaceObject === "strict" | ||||
| 			); | ||||
| 			const id = chunkGraph.getModuleId(module); | ||||
|  |  | |||
|  | @ -425,9 +425,6 @@ class ExportsInfo { | |||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		if (this._sideEffectsOnlyInfo.getUsed(runtime) !== UsageState.Unused) { | ||||
| 			return true; | ||||
| 		} | ||||
| 		for (const exportInfo of this._exports.values()) { | ||||
| 			if (exportInfo.getUsed(runtime) !== UsageState.Unused) { | ||||
| 				return true; | ||||
|  | @ -641,7 +638,10 @@ class ExportsInfo { | |||
| 	getUsedName(name, runtime) { | ||||
| 		if (Array.isArray(name)) { | ||||
| 			// 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]); | ||||
| 			const x = info.getUsedName(name[0], runtime); | ||||
| 			if (x === false) return false; | ||||
|  |  | |||
|  | @ -71,7 +71,7 @@ const makeSerializable = require("./util/makeSerializable"); | |||
|  * @property {string=} exportsArgument | ||||
|  * @property {boolean=} strict | ||||
|  * @property {string=} moduleConcatenationBailout | ||||
|  * @property {("default" | "namespace" | "flagged")=} exportsType | ||||
|  * @property {("default" | "namespace" | "flagged" | "dynamic")=} exportsType | ||||
|  * @property {(false | "redirect" | "redirect-warn")=} defaultObject | ||||
|  * @property {boolean=} strictHarmonyModule | ||||
|  * @property {boolean=} async | ||||
|  | @ -263,6 +263,10 @@ class Module extends DependenciesBlock { | |||
| 		).getUsedExports(this, undefined); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @deprecated | ||||
| 	 * @returns {(string | OptimizationBailoutFunction)[]} list | ||||
| 	 */ | ||||
| 	get optimizationBailout() { | ||||
| 		return ModuleGraph.getModuleGraphForModule( | ||||
| 			this, | ||||
|  | @ -372,6 +376,7 @@ class Module extends DependenciesBlock { | |||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param {ModuleGraph} moduleGraph the module graph | ||||
| 	 * @param {boolean} strict the importing module is strict | ||||
| 	 * @returns {"namespace" | "default-only" | "default-with-named" | "dynamic"} export type | ||||
| 	 * "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-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) { | ||||
| 			case "flagged": | ||||
| 				return strict ? "default-only" : "namespace"; | ||||
|  | @ -393,6 +398,44 @@ class Module extends DependenciesBlock { | |||
| 					default: | ||||
| 						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: | ||||
| 				return strict ? "default-only" : "dynamic"; | ||||
| 		} | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ exports.exports = "__webpack_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"; | ||||
| 
 | ||||
|  |  | |||
|  | @ -357,7 +357,7 @@ class RuntimeTemplate { | |||
| 			request, | ||||
| 			weak | ||||
| 		}); | ||||
| 		const exportsType = module.getExportsType(strict); | ||||
| 		const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict); | ||||
| 		switch (exportsType) { | ||||
| 			case "namespace": | ||||
| 				return this.moduleRaw({ | ||||
|  | @ -461,7 +461,7 @@ class RuntimeTemplate { | |||
| 			request, | ||||
| 			weak | ||||
| 		}); | ||||
| 		const exportsType = module.getExportsType(strict); | ||||
| 		const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict); | ||||
| 		let fakeType = 0; | ||||
| 		switch (exportsType) { | ||||
| 			case "namespace": | ||||
|  | @ -590,6 +590,7 @@ class RuntimeTemplate { | |||
| 		const optDeclaration = update ? "" : "var "; | ||||
| 
 | ||||
| 		const exportsType = module.getExportsType( | ||||
| 			chunkGraph.moduleGraph, | ||||
| 			originModule.buildMeta.strictHarmonyModule | ||||
| 		); | ||||
| 		runtimeRequirements.add(RuntimeGlobals.require); | ||||
|  | @ -646,6 +647,7 @@ class RuntimeTemplate { | |||
| 			exportName = exportName ? [exportName] : []; | ||||
| 		} | ||||
| 		const exportsType = module.getExportsType( | ||||
| 			moduleGraph, | ||||
| 			originModule.buildMeta.strictHarmonyModule | ||||
| 		); | ||||
| 
 | ||||
|  |  | |||
|  | @ -680,7 +680,13 @@ const applyOptimizationDefaults = ( | |||
| 			apply: compiler => { | ||||
| 				// Lazy load the Terser plugin
 | ||||
| 				const TerserPlugin = require("terser-webpack-plugin"); | ||||
| 				new TerserPlugin().apply(compiler); | ||||
| 				new TerserPlugin({ | ||||
| 					terserOptions: { | ||||
| 						compress: { | ||||
| 							passes: 2 | ||||
| 						} | ||||
| 					} | ||||
| 				}).apply(compiler); | ||||
| 			} | ||||
| 		} | ||||
| 	]); | ||||
|  |  | |||
|  | @ -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]; | ||||
| }; | ||||
|  | @ -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; | ||||
|  | @ -6,9 +6,9 @@ | |||
| "use strict"; | ||||
| 
 | ||||
| const InitFragment = require("../InitFragment"); | ||||
| const RuntimeGlobals = require("../RuntimeGlobals"); | ||||
| const makeSerializable = require("../util/makeSerializable"); | ||||
| const propertyAccess = require("../util/propertyAccess"); | ||||
| const { handleDependencyBase } = require("./CommonJsDependencyHelpers"); | ||||
| const NullDependency = require("./NullDependency"); | ||||
| 
 | ||||
| /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ | ||||
|  | @ -94,42 +94,11 @@ CommonJsExportsDependency.Template = class CommonJsExportsDependencyTemplate ext | |||
| 			.getExportsInfo(module) | ||||
| 			.getUsedName(dep.names, runtime); | ||||
| 
 | ||||
| 		let base = undefined; | ||||
| 		let type; | ||||
| 		switch (dep.base) { | ||||
| 			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 ${dep.base}`); | ||||
| 		} | ||||
| 		const [type, base] = handleDependencyBase( | ||||
| 			dep.base, | ||||
| 			module, | ||||
| 			runtimeRequirements | ||||
| 		); | ||||
| 
 | ||||
| 		switch (type) { | ||||
| 			case "expression": | ||||
|  |  | |||
|  | @ -6,19 +6,21 @@ | |||
| "use strict"; | ||||
| 
 | ||||
| const RuntimeGlobals = require("../RuntimeGlobals"); | ||||
| const formatLocation = require("../formatLocation"); | ||||
| const { evaluateToString } = require("../javascript/JavascriptParserHelpers"); | ||||
| const propertyAccess = require("../util/propertyAccess"); | ||||
| const CommonJsExportRequireDependency = require("./CommonJsExportRequireDependency"); | ||||
| const CommonJsExportsDependency = require("./CommonJsExportsDependency"); | ||||
| const CommonJsSelfReferenceDependency = require("./CommonJsSelfReferenceDependency"); | ||||
| const DynamicExports = require("./DynamicExports"); | ||||
| const HarmonyExports = require("./HarmonyExports"); | ||||
| const ModuleDecoratorDependency = require("./ModuleDecoratorDependency"); | ||||
| 
 | ||||
| /** @typedef {import("estree").Expression} ExpressionNode */ | ||||
| /** @typedef {import("../NormalModule")} NormalModule */ | ||||
| /** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */ | ||||
| /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ | ||||
| 
 | ||||
| /** @type {WeakMap<NormalModule, boolean>} */ | ||||
| const moduleExportsState = new WeakMap(); | ||||
| 
 | ||||
| const getValueOfPropertyDescription = expr => { | ||||
| 	if (expr.type !== "ObjectExpression") return; | ||||
| 	for (const property of expr.properties) { | ||||
|  | @ -49,14 +51,43 @@ const isFalsyLiteral = expr => { | |||
| 	return false; | ||||
| }; | ||||
| 
 | ||||
| class CommonJsExportsParserPlugin { | ||||
| 	static bailout(module) { | ||||
| 		const value = moduleExportsState.get(module); | ||||
| 		moduleExportsState.set(module, false); | ||||
| 		if (value === true) { | ||||
| 			module.buildMeta.exportsType = undefined; | ||||
| 			module.buildMeta.defaultObject = false; | ||||
| /** | ||||
|  * @param {JavascriptParser} parser the parser | ||||
|  * @param {ExpressionNode} expr expression | ||||
|  * @returns {{ argument: BasicEvaluatedExpression, ids: string[] } | undefined} parsed call | ||||
|  */ | ||||
| const parseRequireCall = (parser, expr) => { | ||||
| 	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 = () => { | ||||
| 			DynamicExports.enable(parser.state); | ||||
| 		}; | ||||
| 		const checkNamespace = (members, valueExpr) => { | ||||
| 		const checkNamespace = (topLevel, members, valueExpr) => { | ||||
| 			if (!DynamicExports.isEnabled(parser.state)) return; | ||||
| 			if (members.length > 0 && members[0] === "__esModule") { | ||||
| 				if (isTruthyLiteral(valueExpr)) { | ||||
| 				if (isTruthyLiteral(valueExpr) && topLevel) { | ||||
| 					DynamicExports.setFlagged(parser.state); | ||||
| 				} else { | ||||
| 					DynamicExports.bailout(parser.state); | ||||
| 					DynamicExports.setDynamic(parser.state); | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 		const bailout = () => { | ||||
| 		const bailout = reason => { | ||||
| 			DynamicExports.bailout(parser.state); | ||||
| 			if (reason) bailoutHint(reason); | ||||
| 		}; | ||||
| 		const bailoutHint = reason => { | ||||
| 			this.moduleGraph | ||||
| 				.getOptimizationBailout(parser.state.module) | ||||
| 				.push(`CommonJS bailout: ${reason}`); | ||||
| 		}; | ||||
| 
 | ||||
| 		// metadata //
 | ||||
|  | @ -89,60 +126,74 @@ class CommonJsExportsParserPlugin { | |||
| 			.tap("CommonJsPlugin", evaluateToString("object")); | ||||
| 
 | ||||
| 		// exporting //
 | ||||
| 		parser.hooks.assignMemberChain | ||||
| 			.for("exports") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 		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(); | ||||
| 				checkNamespace(members, expr.right); | ||||
| 				// 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, | ||||
| 					"exports", | ||||
| 					members | ||||
| 				base, | ||||
| 				remainingMembers | ||||
| 			); | ||||
| 			dep.loc = expr.loc; | ||||
| 			parser.state.module.addDependency(dep); | ||||
| 			parser.walkExpression(expr.right); | ||||
| 			return true; | ||||
| 		}; | ||||
| 		parser.hooks.assignMemberChain | ||||
| 			.for("exports") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 				return handleAssignExport(expr, "exports", members); | ||||
| 			}); | ||||
| 		parser.hooks.assignMemberChain | ||||
| 			.for("this") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 				if (HarmonyExports.isEnabled(parser.state)) return; | ||||
| 				if (!parser.scope.topLevelScope) return; | ||||
| 				enableStructuredExports(); | ||||
| 				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; | ||||
| 				return handleAssignExport(expr, "this", members); | ||||
| 			}); | ||||
| 		parser.hooks.assignMemberChain | ||||
| 			.for("module") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 				if (HarmonyExports.isEnabled(parser.state)) return; | ||||
| 				if (members[0] !== "exports" || members.length <= 1) return; | ||||
| 				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; | ||||
| 				if (members[0] !== "exports") return; | ||||
| 				return handleAssignExport(expr, "module.exports", members.slice(1)); | ||||
| 			}); | ||||
| 		parser.hooks.call | ||||
| 			.for("Object.defineProperty") | ||||
| 			.tap("CommonJsExportsParserPlugin", expression => { | ||||
| 				const expr = /** @type {import("estree").CallExpression} */ (expression); | ||||
| 				if (!parser.isStatementLevelExpression(expr)) return; | ||||
| 				if (expr.arguments.length !== 3) return; | ||||
| 				if (expr.arguments[0].type === "SpreadElement") return; | ||||
| 				if (expr.arguments[1].type === "SpreadElement") return; | ||||
|  | @ -162,7 +213,11 @@ class CommonJsExportsParserPlugin { | |||
| 				if (typeof property !== "string") return; | ||||
| 				enableStructuredExports(); | ||||
| 				const descArg = expr.arguments[2]; | ||||
| 				checkNamespace([property], getValueOfPropertyDescription(descArg)); | ||||
| 				checkNamespace( | ||||
| 					parser.statementPath.length === 1, | ||||
| 					[property], | ||||
| 					getValueOfPropertyDescription(descArg) | ||||
| 				); | ||||
| 				const dep = new CommonJsExportsDependency( | ||||
| 					expr.range, | ||||
| 					expr.arguments[2].range, | ||||
|  | @ -177,44 +232,87 @@ class CommonJsExportsParserPlugin { | |||
| 			}); | ||||
| 
 | ||||
| 		// Self reference //
 | ||||
| 		parser.hooks.expression | ||||
| 			.for("exports") | ||||
| 			.tap("CommonJsExportsParserPlugin", expr => { | ||||
| 		const handleAccessExport = (expr, base, members, call = undefined) => { | ||||
| 			if (HarmonyExports.isEnabled(parser.state)) return; | ||||
| 				bailout(); | ||||
| 			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, | ||||
| 					"exports", | ||||
| 					[] | ||||
| 				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 | ||||
| 			.for("exports") | ||||
| 			.tap("CommonJsExportsParserPlugin", expr => { | ||||
| 				return handleAccessExport(expr, "exports", []); | ||||
| 			}); | ||||
| 		parser.hooks.callMemberChain | ||||
| 			.for("module") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 				if (members[0] !== "exports") return; | ||||
| 				return handleAccessExport( | ||||
| 					expr.callee, | ||||
| 					"module.exports", | ||||
| 					members.slice(1), | ||||
| 					expr | ||||
| 				); | ||||
| 			}); | ||||
| 		parser.hooks.expressionMemberChain | ||||
| 			.for("module") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 				if (members[0] !== "exports") return; | ||||
| 				return handleAccessExport(expr, "module.exports", members.slice(1)); | ||||
| 			}); | ||||
| 		parser.hooks.expression | ||||
| 			.for("module.exports") | ||||
| 			.tap("CommonJsExportsParserPlugin", expr => { | ||||
| 				if (HarmonyExports.isEnabled(parser.state)) return; | ||||
| 				bailout(); | ||||
| 				const dep = new CommonJsSelfReferenceDependency( | ||||
| 					expr.range, | ||||
| 					"module.exports", | ||||
| 					[] | ||||
| 				); | ||||
| 				dep.loc = expr.loc; | ||||
| 				parser.state.module.addDependency(dep); | ||||
| 				return true; | ||||
| 				return handleAccessExport(expr, "module.exports", []); | ||||
| 			}); | ||||
| 		parser.hooks.callMemberChain | ||||
| 			.for("this") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 				if (!parser.scope.topLevelScope) return; | ||||
| 				return handleAccessExport(expr.callee, "this", members, expr); | ||||
| 			}); | ||||
| 		parser.hooks.expressionMemberChain | ||||
| 			.for("this") | ||||
| 			.tap("CommonJsExportsParserPlugin", (expr, members) => { | ||||
| 				if (!parser.scope.topLevelScope) return; | ||||
| 				return handleAccessExport(expr, "this", members); | ||||
| 			}); | ||||
| 		parser.hooks.expression | ||||
| 			.for("this") | ||||
| 			.tap("CommonJsExportsParserPlugin", expr => { | ||||
| 				if (HarmonyExports.isEnabled(parser.state)) return; | ||||
| 				if (!parser.scope.topLevelScope) return; | ||||
| 				bailout(); | ||||
| 				const dep = new CommonJsSelfReferenceDependency(expr.range, "this", []); | ||||
| 				dep.loc = expr.loc; | ||||
| 				parser.state.module.addDependency(dep); | ||||
| 				return true; | ||||
| 				return handleAccessExport(expr, "this", []); | ||||
| 			}); | ||||
| 
 | ||||
| 		// Bailouts //
 | ||||
|  |  | |||
|  | @ -5,7 +5,10 @@ | |||
| 
 | ||||
| "use strict"; | ||||
| 
 | ||||
| const Template = require("../Template"); | ||||
| const { equals } = require("../util/ArrayHelpers"); | ||||
| const makeSerializable = require("../util/makeSerializable"); | ||||
| const propertyAccess = require("../util/propertyAccess"); | ||||
| const ModuleDependency = require("./ModuleDependency"); | ||||
| 
 | ||||
| /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ | ||||
|  | @ -40,7 +43,7 @@ class CommonJsFullRequireDependency extends ModuleDependency { | |||
| 			const importedModule = moduleGraph.getModule(this); | ||||
| 			if ( | ||||
| 				!importedModule || | ||||
| 				importedModule.getExportsType(false) !== "namespace" | ||||
| 				importedModule.getExportsType(moduleGraph, false) !== "namespace" | ||||
| 			) { | ||||
| 				return [this.names.slice(0, -1)]; | ||||
| 			} | ||||
|  | @ -96,29 +99,24 @@ CommonJsFullRequireDependency.Template = class CommonJsFullRequireDependencyTemp | |||
| 		const dep = /** @type {CommonJsFullRequireDependency} */ (dependency); | ||||
| 		if (!dep.range) return; | ||||
| 		const importedModule = moduleGraph.getModule(dep); | ||||
| 		const exports = runtimeTemplate.moduleExports({ | ||||
| 		let requireExpr = runtimeTemplate.moduleExports({ | ||||
| 			module: importedModule, | ||||
| 			chunkGraph, | ||||
| 			request: dep.request, | ||||
| 			weak: dep.weak, | ||||
| 			runtimeRequirements | ||||
| 		}); | ||||
| 		const exportExpr = runtimeTemplate.exportFromImport({ | ||||
| 			moduleGraph, | ||||
| 			module: importedModule, | ||||
| 			request: dep.request, | ||||
| 			exportName: dep.names, | ||||
| 			originModule: module, | ||||
| 			asiSafe: dep.asiSafe, | ||||
| 			isCall: dep.call, | ||||
| 			callContext: undefined, | ||||
| 			defaultInterop: false, | ||||
| 			importVar: exports, | ||||
| 			initFragments, | ||||
| 			runtime, | ||||
| 			runtimeRequirements | ||||
| 		}); | ||||
| 		source.replace(dep.range[0], dep.range[1] - 1, exportExpr); | ||||
| 		const ids = dep.names; | ||||
| 		const usedImported = moduleGraph | ||||
| 			.getExportsInfo(importedModule) | ||||
| 			.getUsedName(ids, runtime); | ||||
| 		if (usedImported) { | ||||
| 			const comment = equals(usedImported, ids) | ||||
| 				? "" | ||||
| 				: Template.toNormalComment(propertyAccess(ids)) + " "; | ||||
| 			requireExpr += `${comment}${propertyAccess(usedImported)}`; | ||||
| 		} | ||||
| 		source.replace(dep.range[0], dep.range[1] - 1, requireExpr); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ const { | |||
| 	evaluateToIdentifier, | ||||
| 	toConstantDependency | ||||
| } = require("../javascript/JavascriptParserHelpers"); | ||||
| const CommonJsExportRequireDependency = require("./CommonJsExportRequireDependency"); | ||||
| 
 | ||||
| class CommonJsPlugin { | ||||
| 	constructor(options) { | ||||
|  | @ -99,6 +100,15 @@ class CommonJsPlugin { | |||
| 					new CommonJsExportsDependency.Template() | ||||
| 				); | ||||
| 
 | ||||
| 				compilation.dependencyFactories.set( | ||||
| 					CommonJsExportRequireDependency, | ||||
| 					normalModuleFactory | ||||
| 				); | ||||
| 				compilation.dependencyTemplates.set( | ||||
| 					CommonJsExportRequireDependency, | ||||
| 					new CommonJsExportRequireDependency.Template() | ||||
| 				); | ||||
| 
 | ||||
| 				const selfFactory = new SelfModuleFactory(compilation.moduleGraph); | ||||
| 
 | ||||
| 				compilation.dependencyFactories.set( | ||||
|  | @ -203,7 +213,9 @@ class CommonJsPlugin { | |||
| 					); | ||||
| 
 | ||||
| 					new CommonJsImportsParserPlugin(options).apply(parser); | ||||
| 					new CommonJsExportsParserPlugin().apply(parser); | ||||
| 					new CommonJsExportsParserPlugin(compilation.moduleGraph).apply( | ||||
| 						parser | ||||
| 					); | ||||
| 				}; | ||||
| 
 | ||||
| 				normalModuleFactory.hooks.parser | ||||
|  |  | |||
|  | @ -5,8 +5,8 @@ | |||
| 
 | ||||
| "use strict"; | ||||
| 
 | ||||
| const { UsageState } = require("../ExportsInfo"); | ||||
| const RuntimeGlobals = require("../RuntimeGlobals"); | ||||
| const { equals } = require("../util/ArrayHelpers"); | ||||
| const makeSerializable = require("../util/makeSerializable"); | ||||
| const propertyAccess = require("../util/propertyAccess"); | ||||
| const NullDependency = require("./NullDependency"); | ||||
|  | @ -20,11 +20,12 @@ const NullDependency = require("./NullDependency"); | |||
| /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ | ||||
| 
 | ||||
| class CommonJsSelfReferenceDependency extends NullDependency { | ||||
| 	constructor(range, base, names) { | ||||
| 	constructor(range, base, names, call) { | ||||
| 		super(); | ||||
| 		this.range = range; | ||||
| 		this.base = base; | ||||
| 		this.names = names; | ||||
| 		this.call = call; | ||||
| 	} | ||||
| 
 | ||||
| 	get type() { | ||||
|  | @ -49,7 +50,7 @@ class CommonJsSelfReferenceDependency extends NullDependency { | |||
| 	 * @returns {(string[] | ReferencedExport)[]} referenced exports | ||||
| 	 */ | ||||
| 	getReferencedExports(moduleGraph, runtime) { | ||||
| 		return [this.names]; | ||||
| 		return [this.call ? this.names.slice(0, -1) : this.names]; | ||||
| 	} | ||||
| 
 | ||||
| 	serialize(context) { | ||||
|  | @ -57,6 +58,7 @@ class CommonJsSelfReferenceDependency extends NullDependency { | |||
| 		write(this.range); | ||||
| 		write(this.base); | ||||
| 		write(this.names); | ||||
| 		write(this.call); | ||||
| 		super.serialize(context); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -65,6 +67,7 @@ class CommonJsSelfReferenceDependency extends NullDependency { | |||
| 		this.range = read(); | ||||
| 		this.base = read(); | ||||
| 		this.names = read(); | ||||
| 		this.call = read(); | ||||
| 		super.deserialize(context); | ||||
| 	} | ||||
| } | ||||
|  | @ -90,13 +93,6 @@ CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependency | |||
| 		let used; | ||||
| 		if (dep.names.length === 0) { | ||||
| 			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 { | ||||
| 			used = moduleGraph.getExportsInfo(module).getUsedName(dep.names, runtime); | ||||
| 		} | ||||
|  | @ -124,7 +120,7 @@ CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependency | |||
| 				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
 | ||||
| 			// We don't use a replacement for compat reasons
 | ||||
| 			// for plugins that update `module._source` which they
 | ||||
|  | @ -135,7 +131,7 @@ CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependency | |||
| 		source.replace( | ||||
| 			dep.range[0], | ||||
| 			dep.range[1] - 1, | ||||
| 			`/* self exports access */ ${base}${propertyAccess(used)}` | ||||
| 			`${base}${propertyAccess(used)}` | ||||
| 		); | ||||
| 	} | ||||
| }; | ||||
|  |  | |||
|  | @ -44,7 +44,19 @@ exports.enable = parserState => { | |||
| exports.setFlagged = parserState => { | ||||
| 	const value = parserStateExportsState.get(parserState); | ||||
| 	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"; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| 
 | ||||
| "use strict"; | ||||
| 
 | ||||
| const { UsageState } = require("../ExportsInfo"); | ||||
| const InitFragment = require("../InitFragment"); | ||||
| const RuntimeGlobals = require("../RuntimeGlobals"); | ||||
| const makeSerializable = require("../util/makeSerializable"); | ||||
|  | @ -45,9 +46,11 @@ HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate | |||
| 			runtime | ||||
| 		} | ||||
| 	) { | ||||
| 		// TODO avoid getUsedExports
 | ||||
| 		const usedExports = moduleGraph.getUsedExports(module, runtime); | ||||
| 		if (usedExports === true || usedExports === null) { | ||||
| 		const exportsInfo = moduleGraph.getExportsInfo(module); | ||||
| 		if ( | ||||
| 			exportsInfo.getReadOnlyExportInfo("__esModule").getUsed(runtime) !== | ||||
| 			UsageState.Unused | ||||
| 		) { | ||||
| 			const content = runtimeTemplate.defineEsModuleFlagStatement({ | ||||
| 				exportsArgument: module.exportsArgument, | ||||
| 				runtimeRequirements | ||||
|  | @ -63,17 +66,15 @@ HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate | |||
| 		} | ||||
| 		if (moduleGraph.isAsync(module)) { | ||||
| 			runtimeRequirements.add(RuntimeGlobals.module); | ||||
| 			if (usedExports !== false) | ||||
| 				runtimeRequirements.add(RuntimeGlobals.exports); | ||||
| 			const used = exportsInfo.isUsed(runtime); | ||||
| 			if (used) runtimeRequirements.add(RuntimeGlobals.exports); | ||||
| 			initFragments.push( | ||||
| 				new InitFragment( | ||||
| 					`${module.moduleArgument}.exports = (async () => {\n`, | ||||
| 					InitFragment.STAGE_ASYNC_BOUNDARY, | ||||
| 					0, | ||||
| 					undefined, | ||||
| 					usedExports !== false | ||||
| 						? `\nreturn ${module.exportsArgument};\n})();` | ||||
| 						: "\n})();" | ||||
| 					used ? `\nreturn ${module.exportsArgument};\n})();` : "\n})();" | ||||
| 				) | ||||
| 			); | ||||
| 		} | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ const makeSerializable = require("../util/makeSerializable"); | |||
| const propertyAccess = require("../util/propertyAccess"); | ||||
| const HarmonyExportInitFragment = require("./HarmonyExportInitFragment"); | ||||
| const HarmonyImportDependency = require("./HarmonyImportDependency"); | ||||
| const processExportInfo = require("./processExportInfo"); | ||||
| 
 | ||||
| /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ | ||||
| /** @typedef {import("../ChunkGraph")} ChunkGraph */ | ||||
|  | @ -37,54 +38,6 @@ const HarmonyImportDependency = require("./HarmonyImportDependency"); | |||
| 
 | ||||
| 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 { | ||||
| 	/** | ||||
| 	 * @param {string} name export name | ||||
|  | @ -229,6 +182,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { | |||
| 		} | ||||
| 
 | ||||
| 		const importedExportsType = importedModule.getExportsType( | ||||
| 			moduleGraph, | ||||
| 			parentModule.buildMeta.strictHarmonyModule | ||||
| 		); | ||||
| 
 | ||||
|  | @ -403,7 +357,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { | |||
| 				if (exportInfo.getUsed(runtime) === UsageState.Unused) continue; | ||||
| 				exports.add(name); | ||||
| 				if (importedExportInfo.provided === true) continue; | ||||
| 				checked.add(exportInfo.name); | ||||
| 				checked.add(name); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -104,6 +104,7 @@ class HarmonyImportDependency extends ModuleDependency { | |||
| 
 | ||||
| 		const parentModule = moduleGraph.getParentModule(this); | ||||
| 		const exportsType = importedModule.getExportsType( | ||||
| 			moduleGraph, | ||||
| 			parentModule.buildMeta.strictHarmonyModule | ||||
| 		); | ||||
| 		switch (exportsType) { | ||||
|  | @ -199,16 +200,18 @@ class HarmonyImportDependency extends ModuleDependency { | |||
| 	 */ | ||||
| 	updateHash(hash, context) { | ||||
| 		const { chunkGraph } = context; | ||||
| 		const { moduleGraph } = chunkGraph; | ||||
| 		super.updateHash(hash, context); | ||||
| 		const importedModule = chunkGraph.moduleGraph.getModule(this); | ||||
| 		const importedModule = moduleGraph.getModule(this); | ||||
| 		if (importedModule) { | ||||
| 			const parentModule = chunkGraph.moduleGraph.getParentModule(this); | ||||
| 			const parentModule = moduleGraph.getParentModule(this); | ||||
| 			hash.update( | ||||
| 				importedModule.getExportsType( | ||||
| 					moduleGraph, | ||||
| 					parentModule.buildMeta && parentModule.buildMeta.strictHarmonyModule | ||||
| 				) | ||||
| 			); | ||||
| 			if (chunkGraph.moduleGraph.isAsync(importedModule)) hash.update("async"); | ||||
| 			if (moduleGraph.isAsync(importedModule)) hash.update("async"); | ||||
| 		} | ||||
| 		hash.update(`${this.sourceOrder}`); | ||||
| 	} | ||||
|  |  | |||
|  | @ -113,7 +113,10 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency { | |||
| 			const selfModule = moduleGraph.getParentModule(this); | ||||
| 			const importedModule = moduleGraph.getModule(this); | ||||
| 			switch ( | ||||
| 				importedModule.getExportsType(selfModule.buildMeta.strictHarmonyModule) | ||||
| 				importedModule.getExportsType( | ||||
| 					moduleGraph, | ||||
| 					selfModule.buildMeta.strictHarmonyModule | ||||
| 				) | ||||
| 			) { | ||||
| 				case "default-only": | ||||
| 				case "default-with-named": | ||||
|  |  | |||
|  | @ -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; | ||||
|  | @ -17,6 +17,7 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); | |||
| /** @typedef {import("estree").ArrayExpression} ArrayExpressionNode */ | ||||
| /** @typedef {import("estree").BinaryExpression} BinaryExpressionNode */ | ||||
| /** @typedef {import("estree").BlockStatement} BlockStatementNode */ | ||||
| /** @typedef {import("estree").SequenceExpression} SequenceExpressionNode */ | ||||
| /** @typedef {import("estree").CallExpression} CallExpressionNode */ | ||||
| /** @typedef {import("estree").ClassDeclaration} ClassDeclarationNode */ | ||||
| /** @typedef {import("estree").ClassExpression} ClassExpressionNode */ | ||||
|  | @ -235,7 +236,7 @@ class JavascriptParser extends Parser { | |||
| 			/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */ | ||||
| 			call: new HookMap(() => new SyncBailHook(["expression"])), | ||||
| 			/** Something like "a.b()" */ | ||||
| 			/** @type {HookMap<SyncBailHook<[ExpressionNode, string[]], boolean | void>>} */ | ||||
| 			/** @type {HookMap<SyncBailHook<[CallExpressionNode, string[]], boolean | void>>} */ | ||||
| 			callMemberChain: new HookMap( | ||||
| 				() => new SyncBailHook(["expression", "members"]) | ||||
| 			), | ||||
|  | @ -294,6 +295,7 @@ class JavascriptParser extends Parser { | |||
| 		this.state = undefined; | ||||
| 		this.comments = undefined; | ||||
| 		this.semicolons = undefined; | ||||
| 		/** @type {(StatementNode|ExpressionNode)[]} */ | ||||
| 		this.statementPath = undefined; | ||||
| 		this.prevStatement = undefined; | ||||
| 		this.currentTagData = undefined; | ||||
|  | @ -983,7 +985,7 @@ class JavascriptParser extends Parser { | |||
| 					.setSideEffects(param.couldHaveSideEffects()) | ||||
| 					.setRange(expr.range); | ||||
| 			}); | ||||
| 		["substr", "substring"].forEach(fn => { | ||||
| 		["substr", "substring", "slice"].forEach(fn => { | ||||
| 			this.hooks.evaluateCallExpressionMember | ||||
| 				.for(fn) | ||||
| 				.tap("JavascriptParser", (expr, param) => { | ||||
|  | @ -2242,8 +2244,29 @@ class JavascriptParser extends Parser { | |||
| 		this.scope.topLevelScope = wasTopLevel; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @param {SequenceExpressionNode} expression the sequence | ||||
| 	 */ | ||||
| 	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) { | ||||
|  | @ -2325,8 +2348,8 @@ class JavascriptParser extends Parser { | |||
| 			}); | ||||
| 			return; | ||||
| 		} | ||||
| 		this.walkExpression(expression.right); | ||||
| 		if (expression.left.type.endsWith("Pattern")) { | ||||
| 			this.walkExpression(expression.right); | ||||
| 			this.enterPattern(expression.left, (name, decl) => { | ||||
| 				if (!this.callHooksForName(this.hooks.assign, name, expression)) { | ||||
| 					this.defineVariable(name); | ||||
|  | @ -2349,8 +2372,10 @@ class JavascriptParser extends Parser { | |||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
| 			this.walkExpression(expression.right); | ||||
| 			this.walkExpression(expression.left); | ||||
| 		} else { | ||||
| 			this.walkExpression(expression.right); | ||||
| 			this.walkExpression(expression.left); | ||||
| 		} | ||||
| 	} | ||||
|  | @ -2565,14 +2590,20 @@ class JavascriptParser extends Parser { | |||
| 		if (exprInfo) { | ||||
| 			switch (exprInfo.type) { | ||||
| 				case "expression": { | ||||
| 					const result1 = this.callHooksForInfo( | ||||
| 						this.hooks.expression, | ||||
| 						exprInfo.name, | ||||
| 						expression | ||||
| 					); | ||||
| 					if (result1 === true) return; | ||||
| 					const members = exprInfo.getMembers(); | ||||
| 					const result = this.callHooksForInfo( | ||||
| 					const result2 = this.callHooksForInfo( | ||||
| 						this.hooks.expressionMemberChain, | ||||
| 						exprInfo.rootInfo, | ||||
| 						expression, | ||||
| 						members | ||||
| 					); | ||||
| 					if (result === true) return; | ||||
| 					if (result2 === true) return; | ||||
| 					this.walkMemberExpressionWithExpressionName( | ||||
| 						expression, | ||||
| 						exprInfo.name, | ||||
|  | @ -2616,12 +2647,6 @@ class JavascriptParser extends Parser { | |||
| 		members, | ||||
| 		onUnhandled | ||||
| 	) { | ||||
| 		const result = this.callHooksForInfo( | ||||
| 			this.hooks.expression, | ||||
| 			name, | ||||
| 			expression | ||||
| 		); | ||||
| 		if (result === true) return; | ||||
| 		if (expression.object.type === "MemberExpression") { | ||||
| 			// optimize the case where expression.object is a MemberExpression too.
 | ||||
| 			// we can keep info here when calling walkMemberExpression directly
 | ||||
|  | @ -2629,6 +2654,12 @@ class JavascriptParser extends Parser { | |||
| 				expression.property.name || `${expression.property.value}`; | ||||
| 			name = name.slice(0, -property.length - 1); | ||||
| 			members.pop(); | ||||
| 			const result = this.callHooksForInfo( | ||||
| 				this.hooks.expression, | ||||
| 				name, | ||||
| 				expression.object | ||||
| 			); | ||||
| 			if (result === true) return; | ||||
| 			this.walkMemberExpressionWithExpressionName( | ||||
| 				expression.object, | ||||
| 				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) { | ||||
| 		const info = this.scope.definitions.get(name); | ||||
| 		if (info instanceof VariableInfo) { | ||||
|  |  | |||
|  | @ -256,7 +256,10 @@ const getExternalImport = ( | |||
| 	asiSafe | ||||
| ) => { | ||||
| 	let exprStart = info.name; | ||||
| 	const exportsType = importedModule.getExportsType(strictHarmonyModule); | ||||
| 	const exportsType = importedModule.getExportsType( | ||||
| 		moduleGraph, | ||||
| 		strictHarmonyModule | ||||
| 	); | ||||
| 	if (exportName.length === 0) { | ||||
| 		switch (exportsType) { | ||||
| 			case "default-only": | ||||
|  | @ -1197,6 +1200,7 @@ class ConcatenatedModule extends Module { | |||
| 					if ( | ||||
| 						info.module.buildMeta.exportsType === "default" || | ||||
| 						info.module.buildMeta.exportsType === "flagged" || | ||||
| 						info.module.buildMeta.exportsType === "dynamic" || | ||||
| 						!info.module.buildMeta.exportsType | ||||
| 					) { | ||||
| 						const externalNameInterop = this.findNewName( | ||||
|  | @ -1208,7 +1212,10 @@ class ConcatenatedModule extends Module { | |||
| 						allUsedNames.add(externalNameInterop); | ||||
| 						info.interopNamespaceObjectName = externalNameInterop; | ||||
| 					} | ||||
| 					if (!info.module.buildMeta.exportsType) { | ||||
| 					if ( | ||||
| 						info.module.buildMeta.exportsType === "dynamic" || | ||||
| 						!info.module.buildMeta.exportsType | ||||
| 					) { | ||||
| 						const externalNameInterop = this.findNewName( | ||||
| 							"default", | ||||
| 							allUsedNames, | ||||
|  | @ -1436,6 +1443,7 @@ class ConcatenatedModule extends Module { | |||
| 							); | ||||
| 						} else if ( | ||||
| 							info.module.buildMeta.exportsType === "flagged" || | ||||
| 							info.module.buildMeta.exportsType === "dynamic" || | ||||
| 							!info.module.buildMeta.exportsType | ||||
| 						) { | ||||
| 							runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); | ||||
|  |  | |||
|  | @ -51,17 +51,23 @@ const mangleExportsInfo = (deterministic, exportsInfo, canBeArray) => { | |||
| 	/** @type {ExportInfo[]} */ | ||||
| 	const mangleableExports = []; | ||||
| 	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) { | ||||
| 		const name = exportInfo.name; | ||||
| 		if (!exportInfo.hasUsedName()) { | ||||
| 			if ( | ||||
| 				// Can the export be mangled?
 | ||||
| 				exportInfo.canMangle !== true || | ||||
| 				// Never rename 1 char exports
 | ||||
| 				(name.length === 1 && /^[a-zA-Z0-9_$]/.test(name)) || | ||||
| 				// Don't rename 2 char exports in deterministic mode
 | ||||
| 				(deterministic && | ||||
| 					name.length === 2 && | ||||
| 					/^[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); | ||||
| 				usedNames.add(name); | ||||
|  |  | |||
|  | @ -47,6 +47,8 @@ module.exports = { | |||
| 		require("../dependencies/CachedConstDependency"), | ||||
| 	"dependencies/CommonJsRequireContextDependency": () => | ||||
| 		require("../dependencies/CommonJsRequireContextDependency"), | ||||
| 	"dependencies/CommonJsExportRequireDependency": () => | ||||
| 		require("../dependencies/CommonJsExportRequireDependency"), | ||||
| 	"dependencies/CommonJsExportsDependency": () => | ||||
| 		require("../dependencies/CommonJsExportsDependency"), | ||||
| 	"dependencies/CommonJsFullRequireDependency": () => | ||||
|  |  | |||
|  | @ -521,10 +521,10 @@ exports[`StatsTestCases should print correct stats for chunks-development 1`] = | |||
| Time: X ms | ||||
| Built at: 1970-04-20 12:42:42 | ||||
| PublicPath: (none) | ||||
| asset b_js.bundle.js 901 bytes [emitted] | ||||
| asset bundle.js 9.75 KiB [emitted] (name: main) | ||||
| asset b_js.bundle.js 968 bytes [emitted] | ||||
| asset bundle.js 9.82 KiB [emitted] (name: main) | ||||
| 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 | ||||
| chunk b_js.bundle.js 22 bytes <{main}> [rendered] | ||||
|     > ./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>" | ||||
| `; | ||||
| 
 | ||||
| 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`] = ` | ||||
| "Hash: b96c5a233eb1688dd315 | ||||
| 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 | ||||
| [847] ./a.js 22 bytes {179} [depth 1] [built] | ||||
|       [used exports unknown] | ||||
|       CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|       ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
| [996] ./b.js 22 bytes {996} [depth 1] [built] | ||||
|       [used exports unknown] | ||||
|       CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|       ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
| [460] ./c.js 54 bytes {460} [depth 1] [built] | ||||
|       [used exports unknown] | ||||
|       ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
| [767] ./d.js 22 bytes {524} [depth 2] [built] | ||||
|       [used exports unknown] | ||||
|       CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|       ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
| [390] ./e.js 22 bytes {524} [depth 2] [built] | ||||
|       [used exports unknown] | ||||
|       CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|       ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
| webpack/runtime/ensure chunk 326 bytes {179} [runtime] | ||||
|       [no exports] | ||||
|  | @ -2342,6 +2359,7 @@ chunk {179} (runtime: main) main.js (main) 73 bytes (javascript) 4.88 KiB (runti | |||
|     > ./index main | ||||
|  [847] ./a.js 22 bytes {179} [depth 1] [built] | ||||
|        [used exports unknown] | ||||
|        CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|        ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
|        cjs self exports reference [847] ./a.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 | ||||
|  [767] ./d.js 22 bytes {524} [depth 2] [built] | ||||
|        [used exports unknown] | ||||
|        CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|        ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
|        require.ensure item ./d [460] ./c.js 1:0-52 | ||||
|        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) | ||||
|  [390] ./e.js 22 bytes {524} [depth 2] [built] | ||||
|        [used exports unknown] | ||||
|        CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|        ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
|        require.ensure item ./e [460] ./c.js 1:0-52 | ||||
|        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 | ||||
|  [996] ./b.js 22 bytes {996} [depth 1] [built] | ||||
|        [used exports unknown] | ||||
|        CommonJS bailout: module.exports is used directly at 1:0-14 | ||||
|        ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
|        cjs self exports reference [996] ./b.js 1:0-14 | ||||
|        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) | ||||
| ./entry.js 32 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 | ||||
| ./ref-from-cjs.js 45 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`] = ` | ||||
| "Hash: d26335b5c063fdfc2a88c8cd6c316db9be4953d2 | ||||
| "Hash: dfef98e0ef4320bb5e7c18a1362fdec91250a8dc | ||||
| Child | ||||
|     Hash: d26335b5c063fdfc2a88 | ||||
|     Hash: dfef98e0ef4320bb5e7c | ||||
|     Time: X ms | ||||
|     Built at: 1970-04-20 12:42:42 | ||||
|     asset main.js 207 bytes [emitted] [minimized] (name: main) | ||||
|  | @ -3088,7 +3110,7 @@ Child | |||
|         ModuleConcatenation bailout: Module is not an ECMAScript module | ||||
|         + 4 hidden modules | ||||
| Child | ||||
|     Hash: c8cd6c316db9be4953d2 | ||||
|     Hash: 18a1362fdec91250a8dc | ||||
|     Time: X ms | ||||
|     Built at: 1970-04-20 12:42:42 | ||||
|     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`] = ` | ||||
| "Hash: e0f1716012b18c82ad97 | ||||
| "Hash: 9b742a666c2c28e22fdf | ||||
| Time: X ms | ||||
| Built at: 1970-04-20 12:42:42 | ||||
| asset bundle.js 7.09 KiB [emitted] (name: main) | ||||
|  |  | |||
|  | @ -3478,7 +3478,7 @@ declare abstract class JavascriptParser extends Parser { | |||
| 		topLevelAwait: SyncBailHook<[Expression], boolean | void>; | ||||
| 		call: HookMap<SyncBailHook<[Expression], boolean | void>>; | ||||
| 		callMemberChain: HookMap< | ||||
| 			SyncBailHook<[Expression, string[]], boolean | void> | ||||
| 			SyncBailHook<[CallExpression, string[]], boolean | void> | ||||
| 		>; | ||||
| 		memberChainOfCallMemberChain: HookMap< | ||||
| 			SyncBailHook< | ||||
|  | @ -3513,9 +3513,56 @@ declare abstract class JavascriptParser extends Parser { | |||
| 	state: Record<string, any> & ParserStateBase; | ||||
| 	comments: any; | ||||
| 	semicolons: any; | ||||
| 	statementEndPos: any; | ||||
| 	lastStatementEndPos: any; | ||||
| 	statementStartPos: any; | ||||
| 	statementPath: ( | ||||
| 		| UnaryExpression | ||||
| 		| 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; | ||||
| 	initializeEvaluating(): void; | ||||
| 	getRenameIdentifier(expr?: any): string; | ||||
|  | @ -3584,7 +3631,7 @@ declare abstract class JavascriptParser extends Parser { | |||
| 	walkObjectExpression(expression?: any): void; | ||||
| 	walkFunctionExpression(expression?: any): void; | ||||
| 	walkArrowFunctionExpression(expression?: any): void; | ||||
| 	walkSequenceExpression(expression?: any): void; | ||||
| 	walkSequenceExpression(expression: SequenceExpression): void; | ||||
| 	walkUpdateExpression(expression?: any): void; | ||||
| 	walkUnaryExpression(expression?: any): void; | ||||
| 	walkLeftRightExpression(expression?: any): void; | ||||
|  | @ -3664,6 +3711,7 @@ declare abstract class JavascriptParser extends Parser { | |||
| 	evaluate(source?: any): BasicEvaluatedExpression; | ||||
| 	getComments(range?: any): any; | ||||
| 	isAsiPosition(pos?: any): any; | ||||
| 	isStatementLevelExpression(expr?: any): boolean; | ||||
| 	getTagData(name?: any, tag?: any): any; | ||||
| 	tagVariable(name?: any, tag?: any, data?: any): void; | ||||
| 	defineVariable(name?: any): void; | ||||
|  | @ -3759,7 +3807,7 @@ declare interface KnownBuildMeta { | |||
| 	exportsArgument?: string; | ||||
| 	strict?: boolean; | ||||
| 	moduleConcatenationBailout?: string; | ||||
| 	exportsType?: "namespace" | "default" | "flagged"; | ||||
| 	exportsType?: "namespace" | "dynamic" | "default" | "flagged"; | ||||
| 	defaultObject?: false | "redirect" | "redirect-warn"; | ||||
| 	strictHarmonyModule?: boolean; | ||||
| 	async?: boolean; | ||||
|  | @ -4176,6 +4224,7 @@ declare class Module extends DependenciesBlock { | |||
| 	readonly exportsArgument: string; | ||||
| 	readonly moduleArgument: string; | ||||
| 	getExportsType( | ||||
| 		moduleGraph: ModuleGraph, | ||||
| 		strict: boolean | ||||
| 	): "namespace" | "default-only" | "default-with-named" | "dynamic"; | ||||
| 	addPresentationalDependency(presentationalDependency: Dependency): void; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue