UNPKG

6.69 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { RawSource } = require("webpack-sources");
9const { UsageState } = require("../ExportsInfo");
10const Generator = require("../Generator");
11const InitFragment = require("../InitFragment");
12const RuntimeGlobals = require("../RuntimeGlobals");
13const Template = require("../Template");
14const ModuleDependency = require("../dependencies/ModuleDependency");
15const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
16const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
17
18/** @typedef {import("webpack-sources").Source} Source */
19/** @typedef {import("../Dependency")} Dependency */
20/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
21/** @typedef {import("../Generator").GenerateContext} GenerateContext */
22/** @typedef {import("../NormalModule")} NormalModule */
23/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
24
25const TYPES = new Set(["webassembly"]);
26
27class WebAssemblyJavascriptGenerator extends Generator {
28 /**
29 * @param {NormalModule} module fresh module
30 * @returns {Set<string>} available types (do not mutate)
31 */
32 getTypes(module) {
33 return TYPES;
34 }
35
36 /**
37 * @param {NormalModule} module the module
38 * @param {string=} type source type
39 * @returns {number} estimate size of the module
40 */
41 getSize(module, type) {
42 return 95 + module.dependencies.length * 5;
43 }
44
45 /**
46 * @param {NormalModule} module module for which the code should be generated
47 * @param {GenerateContext} generateContext context for generate
48 * @returns {Source} generated code
49 */
50 generate(module, generateContext) {
51 const {
52 runtimeTemplate,
53 moduleGraph,
54 chunkGraph,
55 runtimeRequirements,
56 runtime
57 } = generateContext;
58 /** @type {InitFragment[]} */
59 const initFragments = [];
60
61 const exportsInfo = moduleGraph.getExportsInfo(module);
62
63 let needExportsCopy = false;
64 const importedModules = new Map();
65 const initParams = [];
66 let index = 0;
67 for (const dep of module.dependencies) {
68 const moduleDep =
69 dep && dep instanceof ModuleDependency ? dep : undefined;
70 if (moduleGraph.getModule(dep)) {
71 let importData = importedModules.get(moduleGraph.getModule(dep));
72 if (importData === undefined) {
73 importedModules.set(
74 moduleGraph.getModule(dep),
75 (importData = {
76 importVar: `m${index}`,
77 index,
78 request: (moduleDep && moduleDep.userRequest) || undefined,
79 names: new Set(),
80 reexports: []
81 })
82 );
83 index++;
84 }
85 if (dep instanceof WebAssemblyImportDependency) {
86 importData.names.add(dep.name);
87 if (dep.description.type === "GlobalType") {
88 const exportName = dep.name;
89 const importedModule = moduleGraph.getModule(dep);
90
91 if (importedModule) {
92 const usedName = moduleGraph
93 .getExportsInfo(importedModule)
94 .getUsedName(exportName, runtime);
95 if (usedName) {
96 initParams.push(
97 runtimeTemplate.exportFromImport({
98 moduleGraph,
99 module: importedModule,
100 request: dep.request,
101 importVar: importData.importVar,
102 originModule: module,
103 exportName: dep.name,
104 asiSafe: true,
105 isCall: false,
106 callContext: null,
107 defaultInterop: true,
108 initFragments,
109 runtime,
110 runtimeRequirements
111 })
112 );
113 }
114 }
115 }
116 }
117 if (dep instanceof WebAssemblyExportImportedDependency) {
118 importData.names.add(dep.name);
119 const usedName = moduleGraph
120 .getExportsInfo(module)
121 .getUsedName(dep.exportName, runtime);
122 if (usedName) {
123 runtimeRequirements.add(RuntimeGlobals.exports);
124 const exportProp = `${module.exportsArgument}[${JSON.stringify(
125 usedName
126 )}]`;
127 const defineStatement = Template.asString([
128 `${exportProp} = ${runtimeTemplate.exportFromImport({
129 moduleGraph,
130 module: moduleGraph.getModule(dep),
131 request: dep.request,
132 importVar: importData.importVar,
133 originModule: module,
134 exportName: dep.name,
135 asiSafe: true,
136 isCall: false,
137 callContext: null,
138 defaultInterop: true,
139 initFragments,
140 runtime,
141 runtimeRequirements
142 })};`,
143 `if(WebAssembly.Global) ${exportProp} = ` +
144 `new WebAssembly.Global({ value: ${JSON.stringify(
145 dep.valueType
146 )} }, ${exportProp});`
147 ]);
148 importData.reexports.push(defineStatement);
149 needExportsCopy = true;
150 }
151 }
152 }
153 }
154 const importsCode = Template.asString(
155 Array.from(
156 importedModules,
157 ([module, { importVar, request, reexports }]) => {
158 const importStatement = runtimeTemplate.importStatement({
159 module,
160 chunkGraph,
161 request,
162 importVar,
163 originModule: module,
164 runtimeRequirements
165 });
166 return importStatement[0] + importStatement[1] + reexports.join("\n");
167 }
168 )
169 );
170
171 const copyAllExports =
172 exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused &&
173 !needExportsCopy;
174
175 // need these globals
176 runtimeRequirements.add(RuntimeGlobals.module);
177 runtimeRequirements.add(RuntimeGlobals.moduleId);
178 runtimeRequirements.add(RuntimeGlobals.wasmInstances);
179 if (exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused) {
180 runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
181 runtimeRequirements.add(RuntimeGlobals.exports);
182 }
183 if (!copyAllExports) {
184 runtimeRequirements.add(RuntimeGlobals.exports);
185 }
186
187 // create source
188 const source = new RawSource(
189 [
190 '"use strict";',
191 "// Instantiate WebAssembly module",
192 `var wasmExports = ${RuntimeGlobals.wasmInstances}[${module.moduleArgument}.id];`,
193
194 exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused
195 ? `${RuntimeGlobals.makeNamespaceObject}(${module.exportsArgument});`
196 : "",
197
198 // this must be before import for circular dependencies
199 "// export exports from WebAssembly module",
200 copyAllExports
201 ? `${module.moduleArgument}.exports = wasmExports;`
202 : "for(var name in wasmExports) " +
203 `if(name) ` +
204 `${module.exportsArgument}[name] = wasmExports[name];`,
205 "// exec imports from WebAssembly module (for esm order)",
206 importsCode,
207 "",
208 "// exec wasm module",
209 `wasmExports[""](${initParams.join(", ")})`
210 ].join("\n")
211 );
212 return InitFragment.addToSource(source, initFragments, generateContext);
213 }
214}
215
216module.exports = WebAssemblyJavascriptGenerator;