You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			206 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			206 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const { RawSource } = require("webpack-sources"); | ||
|  | const Generator = require("../Generator"); | ||
|  | const InitFragment = require("../InitFragment"); | ||
|  | const RuntimeGlobals = require("../RuntimeGlobals"); | ||
|  | const Template = require("../Template"); | ||
|  | const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); | ||
|  | 
 | ||
|  | /** @typedef {import("webpack-sources").Source} Source */ | ||
|  | /** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */ | ||
|  | /** @typedef {import("../DependencyTemplates")} DependencyTemplates */ | ||
|  | /** @typedef {import("../Generator").GenerateContext} GenerateContext */ | ||
|  | /** @typedef {import("../Module")} Module */ | ||
|  | /** @typedef {import("../NormalModule")} NormalModule */ | ||
|  | /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ | ||
|  | 
 | ||
|  | const TYPES = new Set(["webassembly"]); | ||
|  | 
 | ||
|  | /** | ||
|  |  * @typedef {{ request: string, importVar: string }} ImportObjRequestItem | ||
|  |  */ | ||
|  | 
 | ||
|  | class AsyncWebAssemblyJavascriptGenerator extends Generator { | ||
|  | 	/** | ||
|  | 	 * @param {OutputOptions["webassemblyModuleFilename"]} filenameTemplate template for the WebAssembly module filename | ||
|  | 	 */ | ||
|  | 	constructor(filenameTemplate) { | ||
|  | 		super(); | ||
|  | 		this.filenameTemplate = filenameTemplate; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module fresh module | ||
|  | 	 * @returns {Set<string>} available types (do not mutate) | ||
|  | 	 */ | ||
|  | 	getTypes(module) { | ||
|  | 		return TYPES; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module the module | ||
|  | 	 * @param {string=} type source type | ||
|  | 	 * @returns {number} estimate size of the module | ||
|  | 	 */ | ||
|  | 	getSize(module, type) { | ||
|  | 		return 40 + module.dependencies.length * 10; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module module for which the code should be generated | ||
|  | 	 * @param {GenerateContext} generateContext context for generate | ||
|  | 	 * @returns {Source} generated code | ||
|  | 	 */ | ||
|  | 	generate(module, generateContext) { | ||
|  | 		const { | ||
|  | 			runtimeTemplate, | ||
|  | 			chunkGraph, | ||
|  | 			moduleGraph, | ||
|  | 			runtimeRequirements, | ||
|  | 			runtime | ||
|  | 		} = generateContext; | ||
|  | 		runtimeRequirements.add(RuntimeGlobals.module); | ||
|  | 		runtimeRequirements.add(RuntimeGlobals.moduleId); | ||
|  | 		runtimeRequirements.add(RuntimeGlobals.exports); | ||
|  | 		runtimeRequirements.add(RuntimeGlobals.instantiateWasm); | ||
|  | 		/** @type {InitFragment<InitFragment<string>>[]} */ | ||
|  | 		const initFragments = []; | ||
|  | 		/** @type {Map<Module, ImportObjRequestItem>} */ | ||
|  | 		const depModules = new Map(); | ||
|  | 		/** @type {Map<string, WebAssemblyImportDependency[]>} */ | ||
|  | 		const wasmDepsByRequest = new Map(); | ||
|  | 		for (const dep of module.dependencies) { | ||
|  | 			if (dep instanceof WebAssemblyImportDependency) { | ||
|  | 				const module = moduleGraph.getModule(dep); | ||
|  | 				if (!depModules.has(module)) { | ||
|  | 					depModules.set(module, { | ||
|  | 						request: dep.request, | ||
|  | 						importVar: `WEBPACK_IMPORTED_MODULE_${depModules.size}` | ||
|  | 					}); | ||
|  | 				} | ||
|  | 				let list = wasmDepsByRequest.get(dep.request); | ||
|  | 				if (list === undefined) { | ||
|  | 					list = []; | ||
|  | 					wasmDepsByRequest.set(dep.request, list); | ||
|  | 				} | ||
|  | 				list.push(dep); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		/** @type {Array<string>} */ | ||
|  | 		const promises = []; | ||
|  | 
 | ||
|  | 		const importStatements = Array.from( | ||
|  | 			depModules, | ||
|  | 			([importedModule, { request, importVar }]) => { | ||
|  | 				if (moduleGraph.isAsync(importedModule)) { | ||
|  | 					promises.push(importVar); | ||
|  | 				} | ||
|  | 				return runtimeTemplate.importStatement({ | ||
|  | 					update: false, | ||
|  | 					module: importedModule, | ||
|  | 					chunkGraph, | ||
|  | 					request, | ||
|  | 					originModule: module, | ||
|  | 					importVar, | ||
|  | 					runtimeRequirements | ||
|  | 				}); | ||
|  | 			} | ||
|  | 		); | ||
|  | 		const importsCode = importStatements.map(([x]) => x).join(""); | ||
|  | 		const importsCompatCode = importStatements.map(([_, x]) => x).join(""); | ||
|  | 
 | ||
|  | 		const importObjRequestItems = Array.from( | ||
|  | 			wasmDepsByRequest, | ||
|  | 			([request, deps]) => { | ||
|  | 				const exportItems = deps.map(dep => { | ||
|  | 					const importedModule = moduleGraph.getModule(dep); | ||
|  | 					const importVar = | ||
|  | 						/** @type {ImportObjRequestItem} */ | ||
|  | 						(depModules.get(importedModule)).importVar; | ||
|  | 					return `${JSON.stringify( | ||
|  | 						dep.name | ||
|  | 					)}: ${runtimeTemplate.exportFromImport({ | ||
|  | 						moduleGraph, | ||
|  | 						module: importedModule, | ||
|  | 						request, | ||
|  | 						exportName: dep.name, | ||
|  | 						originModule: module, | ||
|  | 						asiSafe: true, | ||
|  | 						isCall: false, | ||
|  | 						callContext: false, | ||
|  | 						defaultInterop: true, | ||
|  | 						importVar, | ||
|  | 						initFragments, | ||
|  | 						runtime, | ||
|  | 						runtimeRequirements | ||
|  | 					})}`;
 | ||
|  | 				}); | ||
|  | 				return Template.asString([ | ||
|  | 					`${JSON.stringify(request)}: {`, | ||
|  | 					Template.indent(exportItems.join(",\n")), | ||
|  | 					"}" | ||
|  | 				]); | ||
|  | 			} | ||
|  | 		); | ||
|  | 
 | ||
|  | 		const importsObj = | ||
|  | 			importObjRequestItems.length > 0 | ||
|  | 				? Template.asString([ | ||
|  | 						"{", | ||
|  | 						Template.indent(importObjRequestItems.join(",\n")), | ||
|  | 						"}" | ||
|  | 				  ]) | ||
|  | 				: undefined; | ||
|  | 
 | ||
|  | 		const instantiateCall = | ||
|  | 			`${RuntimeGlobals.instantiateWasm}(${module.exportsArgument}, ${ | ||
|  | 				module.moduleArgument | ||
|  | 			}.id, ${JSON.stringify( | ||
|  | 				chunkGraph.getRenderedModuleHash(module, runtime) | ||
|  | 			)}` + (importsObj ? `, ${importsObj})` : `)`);
 | ||
|  | 
 | ||
|  | 		if (promises.length > 0) | ||
|  | 			runtimeRequirements.add(RuntimeGlobals.asyncModule); | ||
|  | 
 | ||
|  | 		const source = new RawSource( | ||
|  | 			promises.length > 0 | ||
|  | 				? Template.asString([ | ||
|  | 						`var __webpack_instantiate__ = ${runtimeTemplate.basicFunction( | ||
|  | 							`[${promises.join(", ")}]`, | ||
|  | 							`${importsCompatCode}return ${instantiateCall};` | ||
|  | 						)}`,
 | ||
|  | 						`${RuntimeGlobals.asyncModule}(${ | ||
|  | 							module.moduleArgument | ||
|  | 						}, async ${runtimeTemplate.basicFunction( | ||
|  | 							"__webpack_handle_async_dependencies__, __webpack_async_result__", | ||
|  | 							[ | ||
|  | 								"try {", | ||
|  | 								importsCode, | ||
|  | 								`var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([${promises.join( | ||
|  | 									", " | ||
|  | 								)}]);`,
 | ||
|  | 								`var [${promises.join( | ||
|  | 									", " | ||
|  | 								)}] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__;`,
 | ||
|  | 								`${importsCompatCode}await ${instantiateCall};`, | ||
|  | 								"__webpack_async_result__();", | ||
|  | 								"} catch(e) { __webpack_async_result__(e); }" | ||
|  | 							] | ||
|  | 						)}, 1);`
 | ||
|  | 				  ]) | ||
|  | 				: `${importsCode}${importsCompatCode}module.exports = ${instantiateCall};` | ||
|  | 		); | ||
|  | 
 | ||
|  | 		return InitFragment.addToSource(source, initFragments, generateContext); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = AsyncWebAssemblyJavascriptGenerator; |