1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Tobias Koppers @sokra
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | const { RawSource } = require("webpack-sources");
|
---|
9 | const Generator = require("../Generator");
|
---|
10 | const InitFragment = require("../InitFragment");
|
---|
11 | const { WEBASSEMBLY_TYPES } = require("../ModuleSourceTypesConstants");
|
---|
12 | const RuntimeGlobals = require("../RuntimeGlobals");
|
---|
13 | const Template = require("../Template");
|
---|
14 | const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
|
---|
15 |
|
---|
16 | /** @typedef {import("webpack-sources").Source} Source */
|
---|
17 | /** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
|
---|
18 | /** @typedef {import("../DependencyTemplates")} DependencyTemplates */
|
---|
19 | /** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
---|
20 | /** @typedef {import("../Module")} Module */
|
---|
21 | /** @typedef {import("../Module").SourceTypes} SourceTypes */
|
---|
22 | /** @typedef {import("../NormalModule")} NormalModule */
|
---|
23 | /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
|
---|
24 |
|
---|
25 | /**
|
---|
26 | * @typedef {{ request: string, importVar: string }} ImportObjRequestItem
|
---|
27 | */
|
---|
28 |
|
---|
29 | class AsyncWebAssemblyJavascriptGenerator extends Generator {
|
---|
30 | /**
|
---|
31 | * @param {OutputOptions["webassemblyModuleFilename"]} filenameTemplate template for the WebAssembly module filename
|
---|
32 | */
|
---|
33 | constructor(filenameTemplate) {
|
---|
34 | super();
|
---|
35 | this.filenameTemplate = filenameTemplate;
|
---|
36 | }
|
---|
37 |
|
---|
38 | /**
|
---|
39 | * @param {NormalModule} module fresh module
|
---|
40 | * @returns {SourceTypes} available types (do not mutate)
|
---|
41 | */
|
---|
42 | getTypes(module) {
|
---|
43 | return WEBASSEMBLY_TYPES;
|
---|
44 | }
|
---|
45 |
|
---|
46 | /**
|
---|
47 | * @param {NormalModule} module the module
|
---|
48 | * @param {string=} type source type
|
---|
49 | * @returns {number} estimate size of the module
|
---|
50 | */
|
---|
51 | getSize(module, type) {
|
---|
52 | return 40 + module.dependencies.length * 10;
|
---|
53 | }
|
---|
54 |
|
---|
55 | /**
|
---|
56 | * @param {NormalModule} module module for which the code should be generated
|
---|
57 | * @param {GenerateContext} generateContext context for generate
|
---|
58 | * @returns {Source | null} generated code
|
---|
59 | */
|
---|
60 | generate(module, generateContext) {
|
---|
61 | const {
|
---|
62 | runtimeTemplate,
|
---|
63 | chunkGraph,
|
---|
64 | moduleGraph,
|
---|
65 | runtimeRequirements,
|
---|
66 | runtime
|
---|
67 | } = generateContext;
|
---|
68 | runtimeRequirements.add(RuntimeGlobals.module);
|
---|
69 | runtimeRequirements.add(RuntimeGlobals.moduleId);
|
---|
70 | runtimeRequirements.add(RuntimeGlobals.exports);
|
---|
71 | runtimeRequirements.add(RuntimeGlobals.instantiateWasm);
|
---|
72 | /** @type {InitFragment<InitFragment<string>>[]} */
|
---|
73 | const initFragments = [];
|
---|
74 | /** @type {Map<Module, ImportObjRequestItem>} */
|
---|
75 | const depModules = new Map();
|
---|
76 | /** @type {Map<string, WebAssemblyImportDependency[]>} */
|
---|
77 | const wasmDepsByRequest = new Map();
|
---|
78 | for (const dep of module.dependencies) {
|
---|
79 | if (dep instanceof WebAssemblyImportDependency) {
|
---|
80 | const module = /** @type {Module} */ (moduleGraph.getModule(dep));
|
---|
81 | if (!depModules.has(module)) {
|
---|
82 | depModules.set(module, {
|
---|
83 | request: dep.request,
|
---|
84 | importVar: `WEBPACK_IMPORTED_MODULE_${depModules.size}`
|
---|
85 | });
|
---|
86 | }
|
---|
87 | let list = wasmDepsByRequest.get(dep.request);
|
---|
88 | if (list === undefined) {
|
---|
89 | list = [];
|
---|
90 | wasmDepsByRequest.set(dep.request, list);
|
---|
91 | }
|
---|
92 | list.push(dep);
|
---|
93 | }
|
---|
94 | }
|
---|
95 |
|
---|
96 | /** @type {Array<string>} */
|
---|
97 | const promises = [];
|
---|
98 |
|
---|
99 | const importStatements = Array.from(
|
---|
100 | depModules,
|
---|
101 | ([importedModule, { request, importVar }]) => {
|
---|
102 | if (moduleGraph.isAsync(importedModule)) {
|
---|
103 | promises.push(importVar);
|
---|
104 | }
|
---|
105 | return runtimeTemplate.importStatement({
|
---|
106 | update: false,
|
---|
107 | module: importedModule,
|
---|
108 | chunkGraph,
|
---|
109 | request,
|
---|
110 | originModule: module,
|
---|
111 | importVar,
|
---|
112 | runtimeRequirements
|
---|
113 | });
|
---|
114 | }
|
---|
115 | );
|
---|
116 | const importsCode = importStatements.map(([x]) => x).join("");
|
---|
117 | const importsCompatCode = importStatements.map(([_, x]) => x).join("");
|
---|
118 |
|
---|
119 | const importObjRequestItems = Array.from(
|
---|
120 | wasmDepsByRequest,
|
---|
121 | ([request, deps]) => {
|
---|
122 | const exportItems = deps.map(dep => {
|
---|
123 | const importedModule =
|
---|
124 | /** @type {Module} */
|
---|
125 | (moduleGraph.getModule(dep));
|
---|
126 | const importVar =
|
---|
127 | /** @type {ImportObjRequestItem} */
|
---|
128 | (depModules.get(importedModule)).importVar;
|
---|
129 | return `${JSON.stringify(
|
---|
130 | dep.name
|
---|
131 | )}: ${runtimeTemplate.exportFromImport({
|
---|
132 | moduleGraph,
|
---|
133 | module: importedModule,
|
---|
134 | request,
|
---|
135 | exportName: dep.name,
|
---|
136 | originModule: module,
|
---|
137 | asiSafe: true,
|
---|
138 | isCall: false,
|
---|
139 | callContext: false,
|
---|
140 | defaultInterop: true,
|
---|
141 | importVar,
|
---|
142 | initFragments,
|
---|
143 | runtime,
|
---|
144 | runtimeRequirements
|
---|
145 | })}`;
|
---|
146 | });
|
---|
147 | return Template.asString([
|
---|
148 | `${JSON.stringify(request)}: {`,
|
---|
149 | Template.indent(exportItems.join(",\n")),
|
---|
150 | "}"
|
---|
151 | ]);
|
---|
152 | }
|
---|
153 | );
|
---|
154 |
|
---|
155 | const importsObj =
|
---|
156 | importObjRequestItems.length > 0
|
---|
157 | ? Template.asString([
|
---|
158 | "{",
|
---|
159 | Template.indent(importObjRequestItems.join(",\n")),
|
---|
160 | "}"
|
---|
161 | ])
|
---|
162 | : undefined;
|
---|
163 |
|
---|
164 | const instantiateCall = `${RuntimeGlobals.instantiateWasm}(${module.exportsArgument}, ${
|
---|
165 | module.moduleArgument
|
---|
166 | }.id, ${JSON.stringify(
|
---|
167 | chunkGraph.getRenderedModuleHash(module, runtime)
|
---|
168 | )}${importsObj ? `, ${importsObj})` : ")"}`;
|
---|
169 |
|
---|
170 | if (promises.length > 0)
|
---|
171 | runtimeRequirements.add(RuntimeGlobals.asyncModule);
|
---|
172 |
|
---|
173 | const source = new RawSource(
|
---|
174 | promises.length > 0
|
---|
175 | ? Template.asString([
|
---|
176 | `var __webpack_instantiate__ = ${runtimeTemplate.basicFunction(
|
---|
177 | `[${promises.join(", ")}]`,
|
---|
178 | `${importsCompatCode}return ${instantiateCall};`
|
---|
179 | )}`,
|
---|
180 | `${RuntimeGlobals.asyncModule}(${
|
---|
181 | module.moduleArgument
|
---|
182 | }, async ${runtimeTemplate.basicFunction(
|
---|
183 | "__webpack_handle_async_dependencies__, __webpack_async_result__",
|
---|
184 | [
|
---|
185 | "try {",
|
---|
186 | importsCode,
|
---|
187 | `var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([${promises.join(
|
---|
188 | ", "
|
---|
189 | )}]);`,
|
---|
190 | `var [${promises.join(
|
---|
191 | ", "
|
---|
192 | )}] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__;`,
|
---|
193 | `${importsCompatCode}await ${instantiateCall};`,
|
---|
194 | "__webpack_async_result__();",
|
---|
195 | "} catch(e) { __webpack_async_result__(e); }"
|
---|
196 | ]
|
---|
197 | )}, 1);`
|
---|
198 | ])
|
---|
199 | : `${importsCode}${importsCompatCode}module.exports = ${instantiateCall};`
|
---|
200 | );
|
---|
201 |
|
---|
202 | return InitFragment.addToSource(source, initFragments, generateContext);
|
---|
203 | }
|
---|
204 | }
|
---|
205 |
|
---|
206 | module.exports = AsyncWebAssemblyJavascriptGenerator;
|
---|