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