55"use strict" ;
66
77const Template = require ( "../Template" ) ;
8- const WebAssemblyImportDependency = require ( "../dependencies/WebAssemblyImportDependency" ) ;
8+ const WebAssemblyUtils = require ( "./WebAssemblyUtils" ) ;
9+
10+ /** @typedef {import("../Module") } Module */
911
1012// Get all wasm modules
1113function getAllWasmModules ( chunk ) {
@@ -22,96 +24,88 @@ function getAllWasmModules(chunk) {
2224 return array ;
2325}
2426
27+ /**
28+ * generates the import object function for a module
29+ * @param {Module } module the module
30+ * @returns {string } source code
31+ */
2532function generateImportObject ( module ) {
26- const depsByRequest = new Map ( ) ;
27- for ( const dep of module . dependencies ) {
28- if ( dep instanceof WebAssemblyImportDependency ) {
29- // Ignore global they will be handled later
30- if ( dep . description . type === "GlobalType" ) {
31- continue ;
32- }
33+ const waitForInstances = new Map ( ) ;
34+ const properties = [ ] ;
35+ const usedWasmDependencies = WebAssemblyUtils . getUsedDependencies ( module ) ;
36+ for ( const usedDep of usedWasmDependencies ) {
37+ const dep = usedDep . dependency ;
38+ const importedModule = dep . module ;
39+ const exportName = dep . name ;
40+ const usedName = importedModule && importedModule . isUsed ( exportName ) ;
41+ const description = dep . description ;
42+ const direct = dep . onlyDirectImport ;
3343
34- const request = dep . request ;
35- let array = depsByRequest . get ( request ) ;
36- if ( ! array ) {
37- depsByRequest . set ( request , ( array = [ ] ) ) ;
38- }
39- const exportName = dep . name ;
40- const usedName = dep . module && dep . module . isUsed ( exportName ) ;
44+ const propertyName = usedDep . name ;
4145
42- if ( dep . module === null ) {
43- // Dependency was not found, an error will be thrown later
44- continue ;
45- }
46-
47- if ( usedName !== false ) {
48- array . push ( {
49- exportName,
50- usedName,
51- module : dep . module ,
52- description : dep . description ,
53- direct : dep . onlyDirectImport
54- } ) ;
55- }
56- }
57- }
58- const importsCode = [ ] ;
59- const waitForPromises = new Map ( ) ;
60- for ( const pair of depsByRequest ) {
61- const properties = [ ] ;
62- for ( const data of pair [ 1 ] ) {
63- if ( data . direct ) {
64- const instanceVar = `m${ waitForPromises . size } ` ;
65- waitForPromises . set (
66- instanceVar ,
67- `installedWasmModules[${ JSON . stringify ( data . module . id ) } ]`
68- ) ;
69- properties . push (
70- `${ JSON . stringify ( data . exportName ) } : ${ instanceVar } .exports` +
71- `[${ JSON . stringify ( data . exportName ) } ]`
72- ) ;
73- } else {
74- const params = data . description . signature . params . map (
75- ( param , k ) => "p" + k + param . valtype
76- ) ;
46+ if ( direct ) {
47+ const instanceVar = `m${ waitForInstances . size } ` ;
48+ waitForInstances . set ( instanceVar , importedModule . id ) ;
49+ properties . push (
50+ `${ JSON . stringify ( propertyName ) } : ${ instanceVar } ` +
51+ `[${ JSON . stringify ( usedName ) } ]`
52+ ) ;
53+ } else {
54+ const params = description . signature . params . map (
55+ ( param , k ) => "p" + k + param . valtype
56+ ) ;
7757
78- const result = `__webpack_require__(${ JSON . stringify (
79- data . module . id
80- ) } )[${ JSON . stringify ( data . usedName ) } ](${ params } )`;
58+ const mod = `installedModules[${ JSON . stringify ( importedModule . id ) } ]` ;
59+ const func = `${ mod } .exports[${ JSON . stringify ( usedName ) } ]` ;
8160
82- properties . push (
83- Template . asString ( [
84- `${ JSON . stringify ( data . exportName ) } : function(${ params } ) {` ,
85- Template . indent ( [ `return ${ result } ;` ] ) ,
86- "}"
87- ] )
88- ) ;
89- }
61+ properties . push (
62+ Template . asString ( [
63+ `${ JSON . stringify ( propertyName ) } : ` +
64+ ( importedModule . type . startsWith ( "webassembly" )
65+ ? `${ mod } ? ${ func } : `
66+ : "" ) +
67+ `function(${ params } ) {` ,
68+ Template . indent ( [ `return ${ func } (${ params } );` ] ) ,
69+ "}"
70+ ] )
71+ ) ;
9072 }
91-
92- importsCode . push (
93- Template . asString ( [
94- `${ JSON . stringify ( pair [ 0 ] ) } : {` ,
95- Template . indent ( [ properties . join ( "," ) ] ) ,
96- "}"
97- ] )
98- ) ;
9973 }
10074
101- if ( waitForPromises . size > 0 ) {
102- const promises = Array . from ( waitForPromises . values ( ) ) . join ( ", " ) ;
75+ if ( waitForInstances . size === 1 ) {
76+ const moduleId = Array . from ( waitForInstances . values ( ) ) [ 0 ] ;
77+ const promise = `installedWasmModules[${ JSON . stringify ( moduleId ) } ]` ;
78+ const variable = Array . from ( waitForInstances . keys ( ) ) [ 0 ] ;
79+ return Template . asString ( [
80+ `${ JSON . stringify ( module . id ) } : function() {` ,
81+ Template . indent ( [
82+ `return promiseResolve().then(function() { return ${ promise } ; }).then(function(${ variable } ) {` ,
83+ Template . indent ( [
84+ "return {" ,
85+ Template . indent ( [ properties . join ( ",\n" ) ] ) ,
86+ "};"
87+ ] ) ,
88+ "});"
89+ ] ) ,
90+ "},"
91+ ] ) ;
92+ } else if ( waitForInstances . size > 0 ) {
93+ const promises = Array . from (
94+ waitForInstances . values ( ) ,
95+ id => `installedWasmModules[${ JSON . stringify ( id ) } ]`
96+ ) . join ( ", " ) ;
10397 const variables = Array . from (
104- waitForPromises . keys ( ) ,
105- ( name , i ) => `var ${ name } = array[${ i } ];`
106- ) . join ( "\n " ) ;
98+ waitForInstances . keys ( ) ,
99+ ( name , i ) => `${ name } = array[${ i } ];`
100+ ) . join ( ", " ) ;
107101 return Template . asString ( [
108102 `${ JSON . stringify ( module . id ) } : function() {` ,
109103 Template . indent ( [
110- `return Promise.resolve ().then(function() { return Promise.all([${ promises } ]); }).then(function(array) {` ,
104+ `return promiseResolve ().then(function() { return Promise.all([${ promises } ]); }).then(function(array) {` ,
111105 Template . indent ( [
112- variables ,
106+ `var ${ variables } ;` ,
113107 "return {" ,
114- Template . indent ( [ importsCode . join ( "," ) ] ) ,
108+ Template . indent ( [ properties . join ( ",\n " ) ] ) ,
115109 "};"
116110 ] ) ,
117111 "});"
@@ -123,7 +117,7 @@ function generateImportObject(module) {
123117 `${ JSON . stringify ( module . id ) } : function() {` ,
124118 Template . indent ( [
125119 "return {" ,
126- Template . indent ( [ importsCode . join ( "," ) ] ) ,
120+ Template . indent ( [ properties . join ( ",\n " ) ] ) ,
127121 "};"
128122 ] ) ,
129123 "},"
@@ -149,6 +143,12 @@ class WasmMainTemplatePlugin {
149143 "// object to store loaded and loading wasm modules" ,
150144 "var installedWasmModules = {};" ,
151145 "" ,
146+ // This function is used to delay reading the installed wasm module promises
147+ // by a microtask. Sorting them doesn't help because there are egdecases where
148+ // sorting is not possible (modules splitted into different chunks).
149+ // So we not even trying and solve this by a microtask delay.
150+ "function promiseResolve() { return Promise.resolve(); }" ,
151+ "" ,
152152 "var wasmImportObjects = {" ,
153153 Template . indent ( importObjects ) ,
154154 "};"
@@ -218,13 +218,15 @@ class WasmMainTemplatePlugin {
218218 Template . indent ( [
219219 "promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {" ,
220220 Template . indent ( [
221- "return WebAssembly.instantiate(items[0], items[1]);"
221+ "return WebAssembly.instantiate(items[0], " +
222+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : items[1] });`
222223 ] ) ,
223224 "});"
224225 ] ) ,
225226 "} else if(typeof WebAssembly.instantiateStreaming === 'function') {" ,
226227 Template . indent ( [
227- "promise = WebAssembly.instantiateStreaming(req, importObject);"
228+ "promise = WebAssembly.instantiateStreaming(req, " +
229+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : importObject });`
228230 ] )
229231 ] )
230232 : Template . asString ( [
@@ -238,7 +240,8 @@ class WasmMainTemplatePlugin {
238240 ] ) ,
239241 "]).then(function(items) {" ,
240242 Template . indent ( [
241- "return WebAssembly.instantiate(items[0], items[1]);"
243+ "return WebAssembly.instantiate(items[0], " +
244+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : items[1] });`
242245 ] ) ,
243246 "});"
244247 ] )
@@ -248,7 +251,8 @@ class WasmMainTemplatePlugin {
248251 "var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });" ,
249252 "promise = bytesPromise.then(function(bytes) {" ,
250253 Template . indent ( [
251- "return WebAssembly.instantiate(bytes, importObject);"
254+ "return WebAssembly.instantiate(bytes, " +
255+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : importObject });`
252256 ] ) ,
253257 "});"
254258 ] ) ,
@@ -257,7 +261,7 @@ class WasmMainTemplatePlugin {
257261 Template . indent ( [
258262 `return ${
259263 mainTemplate . requireFn
260- } .w[wasmModuleId] = res.instance || res;`
264+ } .w[wasmModuleId] = ( res.instance || res).exports ;`
261265 ] ) ,
262266 "}));"
263267 ] ) ,
@@ -275,7 +279,7 @@ class WasmMainTemplatePlugin {
275279 return Template . asString ( [
276280 source ,
277281 "" ,
278- "// object with all WebAssembly.instance" ,
282+ "// object with all WebAssembly.instance exports " ,
279283 `${ mainTemplate . requireFn } .w = {};`
280284 ] ) ;
281285 }
0 commit comments