Exemple #1
0
		modulesWithInfo.forEach(info => {
			result.add(`\n// CONCATENATED MODULE: ${info.module.readableIdentifier(requestShortener)}\n`);
			if(info.namespaceObjectSource) {
				result.add(info.namespaceObjectSource);
			}
			result.add(info.source);
		});
		modulesWithInfo.forEach(info => {
			switch(info.type) {
				case "concatenated":
					result.add(`\n// CONCATENATED MODULE: ${info.module.readableIdentifier(requestShortener)}\n`);
					result.add(info.source);
					break;
				case "external":
					result.add(`\n// EXTERNAL MODULE: ${info.module.readableIdentifier(requestShortener)}\n`);
					result.add(`var ${info.name} = __webpack_require__(${JSON.stringify(info.module.id)});\n`);
					if(info.interop) {
						result.add(`var ${info.interopName} = /*#__PURE__*/__webpack_require__.n(${info.name});\n`);
					}
					break;
				default:
					throw new Error(`Unsupported concatenation entry type ${info.type}`);
			}
		});
Exemple #3
0
	source(dependencyTemplates, outputOptions, requestShortener) {
		const modulesSet = new Set();
		this.modules.forEach(m => modulesSet.add(m));

		// Metainfo for each module
		const modulesWithInfo = this.modules.map((m, idx) => {
			const exportMap = new Map();
			const reexportMap = new Map();
			m.dependencies.forEach(dep => {
				if(dep instanceof HarmonyExportSpecifierDependency) {
					exportMap.set(dep.name, dep.id);
				} else if(dep instanceof HarmonyExportExpressionDependency) {
					exportMap.set("default", "__WEBPACK_MODULE_DEFAULT_EXPORT__");
				} else if(dep instanceof HarmonyExportImportedSpecifierDependency) {
					const exportName = dep.name;
					const importName = dep.id;
					const importModule = dep.importDependency.module;
					const innerReexport = modulesSet.has(importModule);
					if(exportName && importName) {
						reexportMap.set(exportName, {
							module: importModule,
							exportName: importName,
							dependency: dep
						});
					} else if(exportName) {
						reexportMap.set(exportName, {
							module: importModule,
							exportName: true,
							dependency: dep
						});
					} else if(Array.isArray(importModule.providedExports)) {
						var activeExports = new Set(HarmonyModulesHelpers.getActiveExports(dep.originModule, dep));
						importModule.providedExports.forEach(name => {
							if(activeExports.has(name) || name === "default")
								return;
							reexportMap.set(name, {
								module: importModule,
								exportName: name,
								dependency: dep
							});
						});
					} else if(innerReexport) {
						throw new Error(`Module "${importModule.readableIdentifier(requestShortener)}" doesn't provide static exports for "export *" in ${m.readableIdentifier(requestShortener)}`);
					}
				}
			});
			return {
				module: m,
				index: idx,
				ast: undefined,
				source: undefined,
				globalScope: undefined,
				moduleScope: undefined,
				internalNames: new Map(),
				exportMap: exportMap,
				reexportMap: reexportMap,
				needCompatibilityFlag: false,
				needNamespaceObject: false,
				namespaceObjectSource: null
			};
		});

		// Create mapping from module to info
		const moduleToInfoMap = new Map();
		modulesWithInfo.forEach(m => moduleToInfoMap.set(m.module, m));

		// Configure template decorators for dependencies
		const innerDependencyTemplates = new Map(dependencyTemplates);

		innerDependencyTemplates.set(HarmonyImportSpecifierDependency, new HarmonyImportSpecifierDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyImportSpecifierDependency),
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyImportDependency, new HarmonyImportDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyImportDependency),
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyExportSpecifierDependency, new HarmonyExportSpecifierDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyExportSpecifierDependency),
			this.rootModule
		));
		innerDependencyTemplates.set(HarmonyExportExpressionDependency, new HarmonyExportExpressionDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyExportExpressionDependency),
			this.rootModule,
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyExportImportedSpecifierDependency, new HarmonyExportImportedSpecifierDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyExportImportedSpecifierDependency),
			this.rootModule,
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyCompatibilityDependency, new HarmonyCompatibilityDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyCompatibilityDependency),
			this.rootModule,
			moduleToInfoMap
		));
		innerDependencyTemplates.set("hash", innerDependencyTemplates.get("hash") + this.rootModule.identifier());

		// Generate source code and analyse scopes
		// Prepare a ReplaceSource for the final source
		modulesWithInfo.forEach(info => {
			const m = info.module;
			const source = m.source(innerDependencyTemplates, outputOptions, requestShortener);
			const code = source.source();
			let ast;
			try {
				ast = acorn.parse(code, {
					ranges: true,
					locations: true,
					ecmaVersion: Parser.ECMA_VERSION,
					sourceType: "module"
				});
			} catch(err) {
				if(err.loc && typeof err.loc === "object" && typeof err.loc.line === "number") {
					const lineNumber = err.loc.line;
					const lines = code.split("\n");
					err.message += "\n| " + lines.slice(Math.max(0, lineNumber - 3), lineNumber + 2).join("\n| ");
				}
				throw err;
			}
			const scopeManager = escope.analyze(ast, {
				ecmaVersion: 6,
				sourceType: "module",
				optimistic: true,
				ignoreEval: true,
				impliedStrict: true
			});
			const globalScope = scopeManager.acquire(ast);
			const moduleScope = globalScope.childScopes[0];
			const resultSource = new ReplaceSource(source);
			info.ast = ast;
			info.source = resultSource;
			info.globalScope = globalScope;
			info.moduleScope = moduleScope;
		});

		// List of all used names to avoid conflicts
		const allUsedNames = new Set(["__WEBPACK_MODULE_DEFAULT_EXPORT__", "defaultExport", "Object"]);

		// get all global names
		modulesWithInfo.forEach(info => {
			info.globalScope.through.forEach(reference => {
				const name = reference.identifier.name;
				if(/^__WEBPACK_MODULE_REFERENCE__\d+_(\d+|ns)__$/.test(name)) {
					for(const s of getSymbolsFromScope(reference.from, info.moduleScope)) {
						allUsedNames.add(s);
					}
				} else {
					allUsedNames.add(name);
				}
			});
		});

		modulesWithInfo.forEach(info => {
			const namespaceObjectName = this.findNewName("namespaceObject", allUsedNames, null, info.module.readableIdentifier(requestShortener));
			allUsedNames.add(namespaceObjectName);
			info.internalNames.set(namespaceObjectName, namespaceObjectName);
			info.exportMap.set(true, namespaceObjectName);
			info.moduleScope.variables.forEach(variable => {
				const name = variable.name;
				if(allUsedNames.has(name)) {
					const references = getAllReferences(variable);
					const symbolsInReferences = references.map(ref => getSymbolsFromScope(ref.from, info.moduleScope)).reduce(reduceSet, new Set());
					const newName = this.findNewName(name, allUsedNames, symbolsInReferences, info.module.readableIdentifier(requestShortener));
					allUsedNames.add(newName);
					info.internalNames.set(name, newName);
					const source = info.source;
					const allIdentifiers = new Set(references.map(r => r.identifier).concat(variable.identifiers));
					for(const identifier of allIdentifiers) {
						const r = identifier.range;
						const path = getPathInAst(info.ast, identifier);
						if(path && path.length > 1 && path[1].type === "Property" && path[1].shorthand) {
							source.insert(r[1], `: ${newName}`);
						} else {
							source.replace(r[0], r[1] - 1, newName);
						}
					}
				} else {
					allUsedNames.add(name);
					info.internalNames.set(name, name);
				}
			});
		});

		modulesWithInfo.forEach(info => {
			info.globalScope.through.forEach(reference => {
				const name = reference.identifier.name;
				const match = /^__WEBPACK_MODULE_REFERENCE__(\d+)_(\d+|ns)__$/.exec(name);
				if(match) {
					const referencedModule = modulesWithInfo[+match[1]];
					let exportName;
					if(match[2] === "ns") {
						exportName = true;
					} else {
						const exportIdx = +match[2];
						exportName = referencedModule.module.providedExports[exportIdx];
					}
					const finalName = getFinalName(referencedModule, exportName, moduleToInfoMap, requestShortener);
					const r = reference.identifier.range;
					const source = info.source;
					source.replace(r[0], r[1] - 1, finalName);
				}
			});
		});

		const result = new ConcatSource();
		if(moduleToInfoMap.get(this.rootModule).needCompatibilityFlag) {
			result.add(`Object.defineProperty(${this.rootModule.exportsArgument || "exports"}, "__esModule", { value: true });\n`);
		}
		let generated = true;
		const ensureNsObjSource = info => {
			if(info.needNamespaceObject && !info.namespaceObjectSource) {
				const name = info.exportMap.get(true);
				const nsObj = [`var ${name} = {};`];
				for(const exportName of info.module.providedExports) {
					const finalName = getFinalName(info, exportName, moduleToInfoMap, requestShortener);
					nsObj.push(`__webpack_require__.d(${name}, ${JSON.stringify(exportName)}, function() { return ${finalName}; });`);
				}
				info.namespaceObjectSource = nsObj.join("\n") + "\n";
				generated = true;
			}
		};
		while(generated) {
			generated = false;
			modulesWithInfo.forEach(ensureNsObjSource);
		}
		modulesWithInfo.forEach(info => {
			result.add(`\n// CONCATENATED MODULE: ${info.module.readableIdentifier(requestShortener)}\n`);
			if(info.namespaceObjectSource) {
				result.add(info.namespaceObjectSource);
			}
			result.add(info.source);
		});

		return result;
	}
		modulesWithInfo.forEach(info => {
			if(info.namespaceObjectSource) {
				result.add(info.namespaceObjectSource);
			}
		});
	source(dependencyTemplates, outputOptions, requestShortener) {
		// Metainfo for each module
		const modulesWithInfo = this._orderedConcatenationList.map((info, idx) => {
			switch(info.type) {
				case "concatenated":
					{
						const exportMap = new Map();
						const reexportMap = new Map();
						info.module.dependencies.forEach(dep => {
							if(dep instanceof HarmonyExportSpecifierDependency) {
								exportMap.set(dep.name, dep.id);
							} else if(dep instanceof HarmonyExportExpressionDependency) {
								exportMap.set("default", "__WEBPACK_MODULE_DEFAULT_EXPORT__");
							} else if(dep instanceof HarmonyExportImportedSpecifierDependency) {
								const exportName = dep.name;
								const importName = dep.id;
								const importedModule = dep.importDependency.module;
								if(exportName && importName) {
									reexportMap.set(exportName, {
										module: importedModule,
										exportName: importName,
										dependency: dep
									});
								} else if(exportName) {
									reexportMap.set(exportName, {
										module: importedModule,
										exportName: true,
										dependency: dep
									});
								} else {
									var activeExports = new Set(HarmonyModulesHelpers.getActiveExports(dep.originModule, dep));
									importedModule.providedExports.forEach(name => {
										if(activeExports.has(name) || name === "default")
											return;
										reexportMap.set(name, {
											module: importedModule,
											exportName: name,
											dependency: dep
										});
									});
								}
							}
						});
						return {
							type: "concatenated",
							module: info.module,
							index: idx,
							ast: undefined,
							source: undefined,
							globalScope: undefined,
							moduleScope: undefined,
							internalNames: new Map(),
							exportMap: exportMap,
							reexportMap: reexportMap,
							hasNamespaceObject: false,
							namespaceObjectSource: null
						};
					}
				case "external":
					return {
						type: "external",
						module: info.module,
						index: idx,
						name: undefined,
						interopName: undefined,
						interop: undefined
					};
				default:
					throw new Error(`Unsupported concatenation entry type ${info.type}`);
			}
		});

		// Create mapping from module to info
		const moduleToInfoMap = new Map();
		modulesWithInfo.forEach(m => moduleToInfoMap.set(m.module, m));

		// Configure template decorators for dependencies
		const innerDependencyTemplates = new Map(dependencyTemplates);

		innerDependencyTemplates.set(HarmonyImportSpecifierDependency, new HarmonyImportSpecifierDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyImportSpecifierDependency),
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyImportDependency, new HarmonyImportDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyImportDependency),
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyExportSpecifierDependency, new HarmonyExportSpecifierDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyExportSpecifierDependency),
			this.rootModule
		));
		innerDependencyTemplates.set(HarmonyExportExpressionDependency, new HarmonyExportExpressionDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyExportExpressionDependency),
			this.rootModule,
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyExportImportedSpecifierDependency, new HarmonyExportImportedSpecifierDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyExportImportedSpecifierDependency),
			this.rootModule,
			moduleToInfoMap
		));
		innerDependencyTemplates.set(HarmonyCompatibilityDependency, new HarmonyCompatibilityDependencyConcatenatedTemplate(
			dependencyTemplates.get(HarmonyCompatibilityDependency),
			this.rootModule,
			moduleToInfoMap
		));
		innerDependencyTemplates.set("hash", innerDependencyTemplates.get("hash") + this.rootModule.identifier());

		// Generate source code and analyse scopes
		// Prepare a ReplaceSource for the final source
		modulesWithInfo.forEach(info => {
			if(info.type === "concatenated") {
				const m = info.module;
				const source = m.source(innerDependencyTemplates, outputOptions, requestShortener);
				const code = source.source();
				let ast;
				try {
					ast = acorn.parse(code, {
						ranges: true,
						locations: true,
						ecmaVersion: Parser.ECMA_VERSION,
						sourceType: "module"
					});
				} catch(err) {
					if(err.loc && typeof err.loc === "object" && typeof err.loc.line === "number") {
						const lineNumber = err.loc.line;
						const lines = code.split("\n");
						err.message += "\n| " + lines.slice(Math.max(0, lineNumber - 3), lineNumber + 2).join("\n| ");
					}
					throw err;
				}
				const scopeManager = escope.analyze(ast, {
					ecmaVersion: 6,
					sourceType: "module",
					optimistic: true,
					ignoreEval: true,
					impliedStrict: true
				});
				const globalScope = scopeManager.acquire(ast);
				const moduleScope = globalScope.childScopes[0];
				const resultSource = new ReplaceSource(source);
				info.ast = ast;
				info.source = resultSource;
				info.globalScope = globalScope;
				info.moduleScope = moduleScope;
			}
		});

		// List of all used names to avoid conflicts
		const allUsedNames = new Set([
			"__WEBPACK_MODULE_DEFAULT_EXPORT__", // avoid using this internal name

			"abstract", "arguments", "async", "await", "boolean", "break", "byte", "case", "catch", "char", "class",
			"const", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "eval",
			"export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if",
			"implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new",
			"null", "package", "private", "protected", "public", "return", "short", "static", "super",
			"switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof",
			"var", "void", "volatile", "while", "with", "yield",

			"module", "__dirname", "__filename", "exports",

			"Array", "Date", "eval", "function", "hasOwnProperty", "Infinity", "isFinite", "isNaN",
			"isPrototypeOf", "length", "Math", "NaN", "name", "Number", "Object", "prototype", "String",
			"toString", "undefined", "valueOf",

			"alert", "all", "anchor", "anchors", "area", "assign", "blur", "button", "checkbox",
			"clearInterval", "clearTimeout", "clientInformation", "close", "closed", "confirm", "constructor",
			"crypto", "decodeURI", "decodeURIComponent", "defaultStatus", "document", "element", "elements",
			"embed", "embeds", "encodeURI", "encodeURIComponent", "escape", "event", "fileUpload", "focus",
			"form", "forms", "frame", "innerHeight", "innerWidth", "layer", "layers", "link", "location",
			"mimeTypes", "navigate", "navigator", "frames", "frameRate", "hidden", "history", "image",
			"images", "offscreenBuffering", "open", "opener", "option", "outerHeight", "outerWidth",
			"packages", "pageXOffset", "pageYOffset", "parent", "parseFloat", "parseInt", "password", "pkcs11",
			"plugin", "prompt", "propertyIsEnum", "radio", "reset", "screenX", "screenY", "scroll", "secure",
			"select", "self", "setInterval", "setTimeout", "status", "submit", "taint", "text", "textarea",
			"top", "unescape", "untaint", "window",

			"onblur", "onclick", "onerror", "onfocus", "onkeydown", "onkeypress", "onkeyup", "onmouseover",
			"onload", "onmouseup", "onmousedown", "onsubmit"
		]);

		// get all global names
		modulesWithInfo.forEach(info => {
			if(info.globalScope) {
				info.globalScope.through.forEach(reference => {
					const name = reference.identifier.name;
					if(/^__WEBPACK_MODULE_REFERENCE__\d+_([\da-f]+|ns)(_call)?__$/.test(name)) {
						for(const s of getSymbolsFromScope(reference.from, info.moduleScope)) {
							allUsedNames.add(s);
						}
					} else {
						allUsedNames.add(name);
					}
				});
			}
		});

		// generate names for symbols
		modulesWithInfo.forEach(info => {
			switch(info.type) {
				case "concatenated":
					{
						const namespaceObjectName = this.findNewName("namespaceObject", allUsedNames, null, info.module.readableIdentifier(requestShortener));
						allUsedNames.add(namespaceObjectName);
						info.internalNames.set(namespaceObjectName, namespaceObjectName);
						info.exportMap.set(true, namespaceObjectName);
						info.moduleScope.variables.forEach(variable => {
							const name = variable.name;
							if(allUsedNames.has(name)) {
								const references = getAllReferences(variable);
								const symbolsInReferences = references.map(ref => getSymbolsFromScope(ref.from, info.moduleScope)).reduce(reduceSet, new Set());
								const newName = this.findNewName(name, allUsedNames, symbolsInReferences, info.module.readableIdentifier(requestShortener));
								allUsedNames.add(newName);
								info.internalNames.set(name, newName);
								const source = info.source;
								const allIdentifiers = new Set(references.map(r => r.identifier).concat(variable.identifiers));
								for(const identifier of allIdentifiers) {
									const r = identifier.range;
									const path = getPathInAst(info.ast, identifier);
									if(path && path.length > 1 && path[1].type === "Property" && path[1].shorthand) {
										source.insert(r[1], `: ${newName}`);
									} else {
										source.replace(r[0], r[1] - 1, newName);
									}
								}
							} else {
								allUsedNames.add(name);
								info.internalNames.set(name, name);
							}
						});
						break;
					}
				case "external":
					{
						info.interop = info.module.meta && !info.module.meta.harmonyModule;
						const externalName = this.findNewName("", allUsedNames, null, info.module.readableIdentifier(requestShortener));
						allUsedNames.add(externalName);
						info.name = externalName;
						if(info.interop) {
							const externalNameInterop = this.findNewName("default", allUsedNames, null, info.module.readableIdentifier(requestShortener));
							allUsedNames.add(externalNameInterop);
							info.interopName = externalNameInterop;
						}
						break;
					}
			}
		});

		// Find and replace referenced to modules
		modulesWithInfo.forEach(info => {
			if(info.type === "concatenated") {
				info.globalScope.through.forEach(reference => {
					const name = reference.identifier.name;
					const match = /^__WEBPACK_MODULE_REFERENCE__(\d+)_([\da-f]+|ns)(_call)?__$/.exec(name);
					if(match) {
						const referencedModule = modulesWithInfo[+match[1]];
						let exportName;
						if(match[2] === "ns") {
							exportName = true;
						} else {
							const exportData = match[2];
							exportName = new Buffer(exportData, "hex").toString("utf-8"); // eslint-disable-line node/no-deprecated-api
						}
						const asCall = !!match[3];
						const finalName = getFinalName(referencedModule, exportName, moduleToInfoMap, requestShortener, asCall);
						const r = reference.identifier.range;
						const source = info.source;
						source.replace(r[0], r[1] - 1, finalName);
					}
				});
			}
		});

		const result = new ConcatSource();

		// add harmony compatibility flag (must be first because of possible circular dependencies)
		const usedExports = this.rootModule.usedExports;
		if(usedExports === true) {
			result.add(`Object.defineProperty(${this.exportsArgument || "exports"}, "__esModule", { value: true });\n`);
		}

		// define required namespace objects (must be before evaluation modules)
		modulesWithInfo.forEach(info => {
			if(info.namespaceObjectSource) {
				result.add(info.namespaceObjectSource);
			}
		});

		// evaluate modules in order
		modulesWithInfo.forEach(info => {
			switch(info.type) {
				case "concatenated":
					result.add(`\n// CONCATENATED MODULE: ${info.module.readableIdentifier(requestShortener)}\n`);
					result.add(info.source);
					break;
				case "external":
					result.add(`\n// EXTERNAL MODULE: ${info.module.readableIdentifier(requestShortener)}\n`);
					result.add(`var ${info.name} = __webpack_require__(${JSON.stringify(info.module.id)});\n`);
					if(info.interop) {
						result.add(`var ${info.interopName} = /*#__PURE__*/__webpack_require__.n(${info.name});\n`);
					}
					break;
				default:
					throw new Error(`Unsupported concatenation entry type ${info.type}`);
			}
		});

		return result;
	}