ConcatenationWrapRuntimeModule.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. */
  4. "use strict";
  5. const RuntimeGlobals = require("../RuntimeGlobals");
  6. const Template = require("../Template");
  7. const HelperRuntimeModule = require("./HelperRuntimeModule");
  8. /** @import Compilation from "../Compilation" */
  9. class ConcatenationWrapRuntimeModule extends HelperRuntimeModule {
  10. constructor() {
  11. super("concatenation wrap");
  12. }
  13. /**
  14. * Returns true, if the runtime module should get it's own scope.
  15. * When false, `generate()` must emit complete statements ending with `;`
  16. * so a following runtime IIFE is not parsed as a call (ASI).
  17. * @returns {boolean} true, if the runtime module should get it's own scope
  18. */
  19. shouldIsolate() {
  20. return false;
  21. }
  22. /**
  23. * Generates runtime code for this runtime module.
  24. * @returns {string | null} runtime code
  25. */
  26. generate() {
  27. const compilation = /** @type {Compilation} */ (this.compilation);
  28. const { runtimeTemplate, outputOptions } = compilation;
  29. const { strictModuleErrorHandling, strictModuleExceptionHandling } =
  30. outputOptions;
  31. const fn = RuntimeGlobals.concatenationWrap;
  32. /** @type {string[]} */
  33. const runBody = [];
  34. if (strictModuleErrorHandling) {
  35. // mirrors the module cache: the error is remembered and rethrown
  36. runBody.push(
  37. "try {",
  38. Template.indent("fn.call(mod.exports, mod, mod.exports);"),
  39. "} catch (e) {",
  40. Template.indent(["mod.error = e;", "throw e;"]),
  41. "}"
  42. );
  43. } else if (strictModuleExceptionHandling) {
  44. // mirrors deleting the cache entry: a later call runs the body again
  45. runBody.push(
  46. "var threw = true;",
  47. "try {",
  48. Template.indent([
  49. "fn.call(mod.exports, mod, mod.exports);",
  50. "threw = false;"
  51. ]),
  52. "} finally {",
  53. Template.indent(["if (threw) { body = fn; mod = undefined; }"]),
  54. "}"
  55. );
  56. } else {
  57. runBody.push("fn.call(mod.exports, mod, mod.exports);");
  58. }
  59. return Template.asString([
  60. "// wrap a concatenated module body as a lazy, memoized accessor; mod is",
  61. "// set before the body runs so re-entrant calls (require cycles) observe",
  62. "// the partial exports like Node.js",
  63. `${fn} = ${runtimeTemplate.basicFunction("body", [
  64. "var mod;",
  65. `return ${runtimeTemplate.basicFunction("", [
  66. "if (body) {",
  67. Template.indent([
  68. "var fn = body;",
  69. "body = 0;",
  70. "mod = { exports: {} };",
  71. ...runBody
  72. ]),
  73. "}",
  74. ...(strictModuleErrorHandling
  75. ? ["if (mod.error !== undefined) throw mod.error;"]
  76. : []),
  77. "return mod.exports;"
  78. ])};`
  79. ])};`
  80. ]);
  81. }
  82. }
  83. module.exports = ConcatenationWrapRuntimeModule;