source: trip-planner-front/node_modules/webpack/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3*/
4
5"use strict";
6
7const RuntimeGlobals = require("../RuntimeGlobals");
8const RuntimeModule = require("../RuntimeModule");
9const Template = require("../Template");
10const { compareModulesByIdentifier } = require("../util/comparators");
11const WebAssemblyUtils = require("./WebAssemblyUtils");
12
13/** @typedef {import("../ChunkGraph")} ChunkGraph */
14/** @typedef {import("../Compilation")} Compilation */
15/** @typedef {import("../Module")} Module */
16/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
17
18// TODO webpack 6 remove the whole folder
19
20// Get all wasm modules
21const getAllWasmModules = (moduleGraph, chunkGraph, chunk) => {
22 const wasmModules = chunk.getAllAsyncChunks();
23 const array = [];
24 for (const chunk of wasmModules) {
25 for (const m of chunkGraph.getOrderedChunkModulesIterable(
26 chunk,
27 compareModulesByIdentifier
28 )) {
29 if (m.type.startsWith("webassembly")) {
30 array.push(m);
31 }
32 }
33 }
34
35 return array;
36};
37
38/**
39 * generates the import object function for a module
40 * @param {ChunkGraph} chunkGraph the chunk graph
41 * @param {Module} module the module
42 * @param {boolean} mangle mangle imports
43 * @param {string[]} declarations array where declarations are pushed to
44 * @param {RuntimeSpec} runtime the runtime
45 * @returns {string} source code
46 */
47const generateImportObject = (
48 chunkGraph,
49 module,
50 mangle,
51 declarations,
52 runtime
53) => {
54 const moduleGraph = chunkGraph.moduleGraph;
55 const waitForInstances = new Map();
56 const properties = [];
57 const usedWasmDependencies = WebAssemblyUtils.getUsedDependencies(
58 moduleGraph,
59 module,
60 mangle
61 );
62 for (const usedDep of usedWasmDependencies) {
63 const dep = usedDep.dependency;
64 const importedModule = moduleGraph.getModule(dep);
65 const exportName = dep.name;
66 const usedName =
67 importedModule &&
68 moduleGraph
69 .getExportsInfo(importedModule)
70 .getUsedName(exportName, runtime);
71 const description = dep.description;
72 const direct = dep.onlyDirectImport;
73
74 const module = usedDep.module;
75 const name = usedDep.name;
76
77 if (direct) {
78 const instanceVar = `m${waitForInstances.size}`;
79 waitForInstances.set(instanceVar, chunkGraph.getModuleId(importedModule));
80 properties.push({
81 module,
82 name,
83 value: `${instanceVar}[${JSON.stringify(usedName)}]`
84 });
85 } else {
86 const params = description.signature.params.map(
87 (param, k) => "p" + k + param.valtype
88 );
89
90 const mod = `${RuntimeGlobals.moduleCache}[${JSON.stringify(
91 chunkGraph.getModuleId(importedModule)
92 )}]`;
93 const modExports = `${mod}.exports`;
94
95 const cache = `wasmImportedFuncCache${declarations.length}`;
96 declarations.push(`var ${cache};`);
97
98 properties.push({
99 module,
100 name,
101 value: Template.asString([
102 (importedModule.type.startsWith("webassembly")
103 ? `${mod} ? ${modExports}[${JSON.stringify(usedName)}] : `
104 : "") + `function(${params}) {`,
105 Template.indent([
106 `if(${cache} === undefined) ${cache} = ${modExports};`,
107 `return ${cache}[${JSON.stringify(usedName)}](${params});`
108 ]),
109 "}"
110 ])
111 });
112 }
113 }
114
115 let importObject;
116 if (mangle) {
117 importObject = [
118 "return {",
119 Template.indent([
120 properties.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n")
121 ]),
122 "};"
123 ];
124 } else {
125 const propertiesByModule = new Map();
126 for (const p of properties) {
127 let list = propertiesByModule.get(p.module);
128 if (list === undefined) {
129 propertiesByModule.set(p.module, (list = []));
130 }
131 list.push(p);
132 }
133 importObject = [
134 "return {",
135 Template.indent([
136 Array.from(propertiesByModule, ([module, list]) => {
137 return Template.asString([
138 `${JSON.stringify(module)}: {`,
139 Template.indent([
140 list.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n")
141 ]),
142 "}"
143 ]);
144 }).join(",\n")
145 ]),
146 "};"
147 ];
148 }
149
150 const moduleIdStringified = JSON.stringify(chunkGraph.getModuleId(module));
151 if (waitForInstances.size === 1) {
152 const moduleId = Array.from(waitForInstances.values())[0];
153 const promise = `installedWasmModules[${JSON.stringify(moduleId)}]`;
154 const variable = Array.from(waitForInstances.keys())[0];
155 return Template.asString([
156 `${moduleIdStringified}: function() {`,
157 Template.indent([
158 `return promiseResolve().then(function() { return ${promise}; }).then(function(${variable}) {`,
159 Template.indent(importObject),
160 "});"
161 ]),
162 "},"
163 ]);
164 } else if (waitForInstances.size > 0) {
165 const promises = Array.from(
166 waitForInstances.values(),
167 id => `installedWasmModules[${JSON.stringify(id)}]`
168 ).join(", ");
169 const variables = Array.from(
170 waitForInstances.keys(),
171 (name, i) => `${name} = array[${i}]`
172 ).join(", ");
173 return Template.asString([
174 `${moduleIdStringified}: function() {`,
175 Template.indent([
176 `return promiseResolve().then(function() { return Promise.all([${promises}]); }).then(function(array) {`,
177 Template.indent([`var ${variables};`, ...importObject]),
178 "});"
179 ]),
180 "},"
181 ]);
182 } else {
183 return Template.asString([
184 `${moduleIdStringified}: function() {`,
185 Template.indent(importObject),
186 "},"
187 ]);
188 }
189};
190
191class WasmChunkLoadingRuntimeModule extends RuntimeModule {
192 constructor({ generateLoadBinaryCode, supportsStreaming, mangleImports }) {
193 super("wasm chunk loading", RuntimeModule.STAGE_ATTACH);
194 this.generateLoadBinaryCode = generateLoadBinaryCode;
195 this.supportsStreaming = supportsStreaming;
196 this.mangleImports = mangleImports;
197 }
198
199 /**
200 * @returns {string} runtime code
201 */
202 generate() {
203 const { chunkGraph, compilation, chunk, mangleImports } = this;
204 const { moduleGraph, outputOptions } = compilation;
205 const fn = RuntimeGlobals.ensureChunkHandlers;
206 const wasmModules = getAllWasmModules(moduleGraph, chunkGraph, chunk);
207 const declarations = [];
208 const importObjects = wasmModules.map(module => {
209 return generateImportObject(
210 chunkGraph,
211 module,
212 this.mangleImports,
213 declarations,
214 chunk.runtime
215 );
216 });
217 const chunkModuleIdMap = chunkGraph.getChunkModuleIdMap(chunk, m =>
218 m.type.startsWith("webassembly")
219 );
220 const createImportObject = content =>
221 mangleImports
222 ? `{ ${JSON.stringify(WebAssemblyUtils.MANGLED_MODULE)}: ${content} }`
223 : content;
224 const wasmModuleSrcPath = compilation.getPath(
225 JSON.stringify(outputOptions.webassemblyModuleFilename),
226 {
227 hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
228 hashWithLength: length =>
229 `" + ${RuntimeGlobals.getFullHash}}().slice(0, ${length}) + "`,
230 module: {
231 id: '" + wasmModuleId + "',
232 hash: `" + ${JSON.stringify(
233 chunkGraph.getChunkModuleRenderedHashMap(chunk, m =>
234 m.type.startsWith("webassembly")
235 )
236 )}[chunkId][wasmModuleId] + "`,
237 hashWithLength(length) {
238 return `" + ${JSON.stringify(
239 chunkGraph.getChunkModuleRenderedHashMap(
240 chunk,
241 m => m.type.startsWith("webassembly"),
242 length
243 )
244 )}[chunkId][wasmModuleId] + "`;
245 }
246 },
247 runtime: chunk.runtime
248 }
249 );
250 return Template.asString([
251 "// object to store loaded and loading wasm modules",
252 "var installedWasmModules = {};",
253 "",
254 // This function is used to delay reading the installed wasm module promises
255 // by a microtask. Sorting them doesn't help because there are edge cases where
256 // sorting is not possible (modules splitted into different chunks).
257 // So we not even trying and solve this by a microtask delay.
258 "function promiseResolve() { return Promise.resolve(); }",
259 "",
260 Template.asString(declarations),
261 "var wasmImportObjects = {",
262 Template.indent(importObjects),
263 "};",
264 "",
265 `var wasmModuleMap = ${JSON.stringify(
266 chunkModuleIdMap,
267 undefined,
268 "\t"
269 )};`,
270 "",
271 "// object with all WebAssembly.instance exports",
272 `${RuntimeGlobals.wasmInstances} = {};`,
273 "",
274 "// Fetch + compile chunk loading for webassembly",
275 `${fn}.wasm = function(chunkId, promises) {`,
276 Template.indent([
277 "",
278 `var wasmModules = wasmModuleMap[chunkId] || [];`,
279 "",
280 "wasmModules.forEach(function(wasmModuleId, idx) {",
281 Template.indent([
282 "var installedWasmModuleData = installedWasmModules[wasmModuleId];",
283 "",
284 '// a Promise means "currently loading" or "already loaded".',
285 "if(installedWasmModuleData)",
286 Template.indent(["promises.push(installedWasmModuleData);"]),
287 "else {",
288 Template.indent([
289 `var importObject = wasmImportObjects[wasmModuleId]();`,
290 `var req = ${this.generateLoadBinaryCode(wasmModuleSrcPath)};`,
291 "var promise;",
292 this.supportsStreaming
293 ? Template.asString([
294 "if(importObject && typeof importObject.then === 'function' && typeof WebAssembly.compileStreaming === 'function') {",
295 Template.indent([
296 "promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {",
297 Template.indent([
298 `return WebAssembly.instantiate(items[0], ${createImportObject(
299 "items[1]"
300 )});`
301 ]),
302 "});"
303 ]),
304 "} else if(typeof WebAssembly.instantiateStreaming === 'function') {",
305 Template.indent([
306 `promise = WebAssembly.instantiateStreaming(req, ${createImportObject(
307 "importObject"
308 )});`
309 ])
310 ])
311 : Template.asString([
312 "if(importObject && typeof importObject.then === 'function') {",
313 Template.indent([
314 "var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });",
315 "promise = Promise.all([",
316 Template.indent([
317 "bytesPromise.then(function(bytes) { return WebAssembly.compile(bytes); }),",
318 "importObject"
319 ]),
320 "]).then(function(items) {",
321 Template.indent([
322 `return WebAssembly.instantiate(items[0], ${createImportObject(
323 "items[1]"
324 )});`
325 ]),
326 "});"
327 ])
328 ]),
329 "} else {",
330 Template.indent([
331 "var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });",
332 "promise = bytesPromise.then(function(bytes) {",
333 Template.indent([
334 `return WebAssembly.instantiate(bytes, ${createImportObject(
335 "importObject"
336 )});`
337 ]),
338 "});"
339 ]),
340 "}",
341 "promises.push(installedWasmModules[wasmModuleId] = promise.then(function(res) {",
342 Template.indent([
343 `return ${RuntimeGlobals.wasmInstances}[wasmModuleId] = (res.instance || res).exports;`
344 ]),
345 "}));"
346 ]),
347 "}"
348 ]),
349 "});"
350 ]),
351 "};"
352 ]);
353 }
354}
355
356module.exports = WasmChunkLoadingRuntimeModule;
Note: See TracBrowser for help on using the repository browser.