5
5
"use strict" ;
6
6
7
7
const Template = require ( "../Template" ) ;
8
- const WebAssemblyImportDependency = require ( "../dependencies/WebAssemblyImportDependency" ) ;
8
+ const WebAssemblyUtils = require ( "./WebAssemblyUtils" ) ;
9
+
10
+ /** @typedef {import("../Module") } Module */
9
11
10
12
// Get all wasm modules
11
13
function getAllWasmModules ( chunk ) {
@@ -22,96 +24,88 @@ function getAllWasmModules(chunk) {
22
24
return array ;
23
25
}
24
26
27
+ /**
28
+ * generates the import object function for a module
29
+ * @param {Module } module the module
30
+ * @returns {string } source code
31
+ */
25
32
function 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 ;
33
43
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 ;
41
45
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
+ ) ;
77
57
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 ) } ]` ;
81
60
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
+ ) ;
90
72
}
91
-
92
- importsCode . push (
93
- Template . asString ( [
94
- `${ JSON . stringify ( pair [ 0 ] ) } : {` ,
95
- Template . indent ( [ properties . join ( "," ) ] ) ,
96
- "}"
97
- ] )
98
- ) ;
99
73
}
100
74
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 ( ", " ) ;
103
97
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 ( ", " ) ;
107
101
return Template . asString ( [
108
102
`${ JSON . stringify ( module . id ) } : function() {` ,
109
103
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) {` ,
111
105
Template . indent ( [
112
- variables ,
106
+ `var ${ variables } ;` ,
113
107
"return {" ,
114
- Template . indent ( [ importsCode . join ( "," ) ] ) ,
108
+ Template . indent ( [ properties . join ( ",\n " ) ] ) ,
115
109
"};"
116
110
] ) ,
117
111
"});"
@@ -123,7 +117,7 @@ function generateImportObject(module) {
123
117
`${ JSON . stringify ( module . id ) } : function() {` ,
124
118
Template . indent ( [
125
119
"return {" ,
126
- Template . indent ( [ importsCode . join ( "," ) ] ) ,
120
+ Template . indent ( [ properties . join ( ",\n " ) ] ) ,
127
121
"};"
128
122
] ) ,
129
123
"},"
@@ -149,6 +143,12 @@ class WasmMainTemplatePlugin {
149
143
"// object to store loaded and loading wasm modules" ,
150
144
"var installedWasmModules = {};" ,
151
145
"" ,
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
+ "" ,
152
152
"var wasmImportObjects = {" ,
153
153
Template . indent ( importObjects ) ,
154
154
"};"
@@ -218,13 +218,15 @@ class WasmMainTemplatePlugin {
218
218
Template . indent ( [
219
219
"promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {" ,
220
220
Template . indent ( [
221
- "return WebAssembly.instantiate(items[0], items[1]);"
221
+ "return WebAssembly.instantiate(items[0], " +
222
+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : items[1] });`
222
223
] ) ,
223
224
"});"
224
225
] ) ,
225
226
"} else if(typeof WebAssembly.instantiateStreaming === 'function') {" ,
226
227
Template . indent ( [
227
- "promise = WebAssembly.instantiateStreaming(req, importObject);"
228
+ "promise = WebAssembly.instantiateStreaming(req, " +
229
+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : importObject });`
228
230
] )
229
231
] )
230
232
: Template . asString ( [
@@ -238,7 +240,8 @@ class WasmMainTemplatePlugin {
238
240
] ) ,
239
241
"]).then(function(items) {" ,
240
242
Template . indent ( [
241
- "return WebAssembly.instantiate(items[0], items[1]);"
243
+ "return WebAssembly.instantiate(items[0], " +
244
+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : items[1] });`
242
245
] ) ,
243
246
"});"
244
247
] )
@@ -248,7 +251,8 @@ class WasmMainTemplatePlugin {
248
251
"var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });" ,
249
252
"promise = bytesPromise.then(function(bytes) {" ,
250
253
Template . indent ( [
251
- "return WebAssembly.instantiate(bytes, importObject);"
254
+ "return WebAssembly.instantiate(bytes, " +
255
+ `{ ${ WebAssemblyUtils . MANGLED_MODULE } : importObject });`
252
256
] ) ,
253
257
"});"
254
258
] ) ,
@@ -257,7 +261,7 @@ class WasmMainTemplatePlugin {
257
261
Template . indent ( [
258
262
`return ${
259
263
mainTemplate . requireFn
260
- } .w[wasmModuleId] = res.instance || res;`
264
+ } .w[wasmModuleId] = ( res.instance || res).exports ;`
261
265
] ) ,
262
266
"}));"
263
267
] ) ,
@@ -275,7 +279,7 @@ class WasmMainTemplatePlugin {
275
279
return Template . asString ( [
276
280
source ,
277
281
"" ,
278
- "// object with all WebAssembly.instance" ,
282
+ "// object with all WebAssembly.instance exports " ,
279
283
`${ mainTemplate . requireFn } .w = {};`
280
284
] ) ;
281
285
}
0 commit comments