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.

152 lines
4.7 KiB

4 years ago
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Generator = require("../Generator");
  7. const Template = require("../Template");
  8. const { RawSource } = require("webpack-sources");
  9. const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
  10. const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
  11. /** @typedef {import("../NormalModule")} NormalModule */
  12. /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
  13. /** @typedef {import("webpack-sources").Source} Source */
  14. /** @typedef {import("../Dependency").DependencyTemplate} DependencyTemplate */
  15. class WebAssemblyJavascriptGenerator extends Generator {
  16. /**
  17. * @param {NormalModule} module module for which the code should be generated
  18. * @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates
  19. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  20. * @param {string} type which kind of code should be generated
  21. * @returns {Source} generated code
  22. */
  23. generate(module, dependencyTemplates, runtimeTemplate, type) {
  24. const initIdentifer = Array.isArray(module.usedExports)
  25. ? Template.numberToIdentifer(module.usedExports.length)
  26. : "__webpack_init__";
  27. let needExportsCopy = false;
  28. const importedModules = new Map();
  29. const initParams = [];
  30. let index = 0;
  31. for (const dep of module.dependencies) {
  32. const depAsAny = /** @type {any} */ (dep);
  33. if (dep.module) {
  34. let importData = importedModules.get(dep.module);
  35. if (importData === undefined) {
  36. importedModules.set(
  37. dep.module,
  38. (importData = {
  39. importVar: `m${index}`,
  40. index,
  41. request:
  42. "userRequest" in depAsAny ? depAsAny.userRequest : undefined,
  43. names: new Set(),
  44. reexports: []
  45. })
  46. );
  47. index++;
  48. }
  49. if (dep instanceof WebAssemblyImportDependency) {
  50. importData.names.add(dep.name);
  51. if (dep.description.type === "GlobalType") {
  52. const exportName = dep.name;
  53. const usedName = dep.module && dep.module.isUsed(exportName);
  54. if (dep.module) {
  55. if (usedName) {
  56. initParams.push(
  57. runtimeTemplate.exportFromImport({
  58. module: dep.module,
  59. request: dep.request,
  60. importVar: importData.importVar,
  61. originModule: module,
  62. exportName: dep.name,
  63. asiSafe: true,
  64. isCall: false,
  65. callContext: null
  66. })
  67. );
  68. }
  69. }
  70. }
  71. }
  72. if (dep instanceof WebAssemblyExportImportedDependency) {
  73. importData.names.add(dep.name);
  74. const usedName = module.isUsed(dep.exportName);
  75. if (usedName) {
  76. const exportProp = `${module.exportsArgument}[${JSON.stringify(
  77. usedName
  78. )}]`;
  79. const defineStatement = Template.asString([
  80. `${exportProp} = ${runtimeTemplate.exportFromImport({
  81. module: dep.module,
  82. request: dep.request,
  83. importVar: importData.importVar,
  84. originModule: module,
  85. exportName: dep.name,
  86. asiSafe: true,
  87. isCall: false,
  88. callContext: null
  89. })};`,
  90. `if(WebAssembly.Global) ${exportProp} = ` +
  91. `new WebAssembly.Global({ value: ${JSON.stringify(
  92. dep.valueType
  93. )} }, ${exportProp});`
  94. ]);
  95. importData.reexports.push(defineStatement);
  96. needExportsCopy = true;
  97. }
  98. }
  99. }
  100. }
  101. const importsCode = Template.asString(
  102. Array.from(
  103. importedModules,
  104. ([module, { importVar, request, reexports }]) => {
  105. const importStatement = runtimeTemplate.importStatement({
  106. module,
  107. request,
  108. importVar,
  109. originModule: module
  110. });
  111. return importStatement + reexports.join("\n");
  112. }
  113. )
  114. );
  115. // create source
  116. const source = new RawSource(
  117. [
  118. '"use strict";',
  119. "// Instantiate WebAssembly module",
  120. "var wasmExports = __webpack_require__.w[module.i];",
  121. !Array.isArray(module.usedExports)
  122. ? `__webpack_require__.r(${module.exportsArgument});`
  123. : "",
  124. // this must be before import for circular dependencies
  125. "// export exports from WebAssembly module",
  126. Array.isArray(module.usedExports) && !needExportsCopy
  127. ? `${module.moduleArgument}.exports = wasmExports;`
  128. : "for(var name in wasmExports) " +
  129. `if(name != ${JSON.stringify(initIdentifer)}) ` +
  130. `${module.exportsArgument}[name] = wasmExports[name];`,
  131. "// exec imports from WebAssembly module (for esm order)",
  132. importsCode,
  133. "",
  134. "// exec wasm module",
  135. `wasmExports[${JSON.stringify(initIdentifer)}](${initParams.join(
  136. ", "
  137. )})`
  138. ].join("\n")
  139. );
  140. return source;
  141. }
  142. }
  143. module.exports = WebAssemblyJavascriptGenerator;