source: imaps-frontend/node_modules/webpack/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

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