You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
5.7 KiB
194 lines
5.7 KiB
/* |
|
MIT License http://www.opensource.org/licenses/mit-license.php |
|
Author Tobias Koppers @sokra |
|
*/ |
|
|
|
"use strict"; |
|
|
|
const { RawSource } = require("webpack-sources"); |
|
const Generator = require("../Generator"); |
|
const InitFragment = require("../InitFragment"); |
|
const RuntimeGlobals = require("../RuntimeGlobals"); |
|
const Template = require("../Template"); |
|
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); |
|
|
|
/** @typedef {import("webpack-sources").Source} Source */ |
|
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */ |
|
/** @typedef {import("../Generator").GenerateContext} GenerateContext */ |
|
/** @typedef {import("../Module")} Module */ |
|
/** @typedef {import("../NormalModule")} NormalModule */ |
|
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ |
|
|
|
const TYPES = new Set(["webassembly"]); |
|
|
|
class AsyncWebAssemblyJavascriptGenerator extends Generator { |
|
constructor(filenameTemplate) { |
|
super(); |
|
this.filenameTemplate = filenameTemplate; |
|
} |
|
|
|
/** |
|
* @param {NormalModule} module fresh module |
|
* @returns {Set<string>} available types (do not mutate) |
|
*/ |
|
getTypes(module) { |
|
return TYPES; |
|
} |
|
|
|
/** |
|
* @param {NormalModule} module the module |
|
* @param {string=} type source type |
|
* @returns {number} estimate size of the module |
|
*/ |
|
getSize(module, type) { |
|
return 40 + module.dependencies.length * 10; |
|
} |
|
|
|
/** |
|
* @param {NormalModule} module module for which the code should be generated |
|
* @param {GenerateContext} generateContext context for generate |
|
* @returns {Source} generated code |
|
*/ |
|
generate(module, generateContext) { |
|
const { |
|
runtimeTemplate, |
|
chunkGraph, |
|
moduleGraph, |
|
runtimeRequirements, |
|
runtime |
|
} = generateContext; |
|
runtimeRequirements.add(RuntimeGlobals.module); |
|
runtimeRequirements.add(RuntimeGlobals.moduleId); |
|
runtimeRequirements.add(RuntimeGlobals.exports); |
|
runtimeRequirements.add(RuntimeGlobals.instantiateWasm); |
|
/** @type {InitFragment[]} */ |
|
const initFragments = []; |
|
/** @type {Map<Module, { request: string, importVar: string }>} */ |
|
const depModules = new Map(); |
|
/** @type {Map<string, WebAssemblyImportDependency[]>} */ |
|
const wasmDepsByRequest = new Map(); |
|
for (const dep of module.dependencies) { |
|
if (dep instanceof WebAssemblyImportDependency) { |
|
const module = moduleGraph.getModule(dep); |
|
if (!depModules.has(module)) { |
|
depModules.set(module, { |
|
request: dep.request, |
|
importVar: `WEBPACK_IMPORTED_MODULE_${depModules.size}` |
|
}); |
|
} |
|
let list = wasmDepsByRequest.get(dep.request); |
|
if (list === undefined) { |
|
list = []; |
|
wasmDepsByRequest.set(dep.request, list); |
|
} |
|
list.push(dep); |
|
} |
|
} |
|
|
|
const promises = []; |
|
|
|
const importStatements = Array.from( |
|
depModules, |
|
([importedModule, { request, importVar }]) => { |
|
if (moduleGraph.isAsync(importedModule)) { |
|
promises.push(importVar); |
|
} |
|
return runtimeTemplate.importStatement({ |
|
update: false, |
|
module: importedModule, |
|
chunkGraph, |
|
request, |
|
originModule: module, |
|
importVar, |
|
runtimeRequirements |
|
}); |
|
} |
|
); |
|
const importsCode = importStatements.map(([x]) => x).join(""); |
|
const importsCompatCode = importStatements.map(([_, x]) => x).join(""); |
|
|
|
const importObjRequestItems = Array.from( |
|
wasmDepsByRequest, |
|
([request, deps]) => { |
|
const exportItems = deps.map(dep => { |
|
const importedModule = moduleGraph.getModule(dep); |
|
const importVar = depModules.get(importedModule).importVar; |
|
return `${JSON.stringify( |
|
dep.name |
|
)}: ${runtimeTemplate.exportFromImport({ |
|
moduleGraph, |
|
module: importedModule, |
|
request, |
|
exportName: dep.name, |
|
originModule: module, |
|
asiSafe: true, |
|
isCall: false, |
|
callContext: false, |
|
defaultInterop: true, |
|
importVar, |
|
initFragments, |
|
runtime, |
|
runtimeRequirements |
|
})}`; |
|
}); |
|
return Template.asString([ |
|
`${JSON.stringify(request)}: {`, |
|
Template.indent(exportItems.join(",\n")), |
|
"}" |
|
]); |
|
} |
|
); |
|
|
|
const importsObj = |
|
importObjRequestItems.length > 0 |
|
? Template.asString([ |
|
"{", |
|
Template.indent(importObjRequestItems.join(",\n")), |
|
"}" |
|
]) |
|
: undefined; |
|
|
|
const instantiateCall = |
|
`${RuntimeGlobals.instantiateWasm}(${module.exportsArgument}, ${ |
|
module.moduleArgument |
|
}.id, ${JSON.stringify( |
|
chunkGraph.getRenderedModuleHash(module, runtime) |
|
)}` + (importsObj ? `, ${importsObj})` : `)`); |
|
|
|
if (promises.length > 0) |
|
runtimeRequirements.add(RuntimeGlobals.asyncModule); |
|
|
|
const source = new RawSource( |
|
promises.length > 0 |
|
? Template.asString([ |
|
`var __webpack_instantiate__ = ${runtimeTemplate.basicFunction( |
|
`[${promises.join(", ")}]`, |
|
`${importsCompatCode}return ${instantiateCall};` |
|
)}`, |
|
`${RuntimeGlobals.asyncModule}(${ |
|
module.moduleArgument |
|
}, async ${runtimeTemplate.basicFunction( |
|
"__webpack_handle_async_dependencies__, __webpack_async_result__", |
|
[ |
|
"try {", |
|
importsCode, |
|
`var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([${promises.join( |
|
", " |
|
)}]);`, |
|
`var [${promises.join( |
|
", " |
|
)}] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__;`, |
|
`${importsCompatCode}await ${instantiateCall};`, |
|
"__webpack_async_result__();", |
|
"} catch(e) { __webpack_async_result__(e); }" |
|
] |
|
)}, 1);` |
|
]) |
|
: `${importsCode}${importsCompatCode}module.exports = ${instantiateCall};` |
|
); |
|
|
|
return InitFragment.addToSource(source, initFragments, generateContext); |
|
} |
|
} |
|
|
|
module.exports = AsyncWebAssemblyJavascriptGenerator;
|
|
|