ConditionalInitFragment.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { ConcatSource, PrefixSource } = require("webpack-sources");
  7. const InitFragment = require("./InitFragment");
  8. const Template = require("./Template");
  9. const { mergeRuntime } = require("./util/runtime");
  10. /** @typedef {import("webpack-sources").Source} Source */
  11. /** @typedef {import("./Generator").GenerateContext} GenerateContext */
  12. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  13. /**
  14. * @param {string} condition condition
  15. * @param {string | Source} source source
  16. * @returns {string | Source} wrapped source
  17. */
  18. const wrapInCondition = (condition, source) => {
  19. if (typeof source === "string") {
  20. return Template.asString([
  21. `if (${condition}) {`,
  22. Template.indent(source),
  23. "}",
  24. ""
  25. ]);
  26. } else {
  27. return new ConcatSource(
  28. `if (${condition}) {\n`,
  29. new PrefixSource("\t", source),
  30. "}\n"
  31. );
  32. }
  33. };
  34. /**
  35. * @extends {InitFragment<GenerateContext>}
  36. */
  37. class ConditionalInitFragment extends InitFragment {
  38. /**
  39. * @param {string | Source | undefined} content the source code that will be included as initialization code
  40. * @param {number} stage category of initialization code (contribute to order)
  41. * @param {number} position position in the category (contribute to order)
  42. * @param {string | undefined} key unique key to avoid emitting the same initialization code twice
  43. * @param {RuntimeSpec | boolean} runtimeCondition in which runtime this fragment should be executed
  44. * @param {string | Source=} endContent the source code that will be included at the end of the module
  45. */
  46. constructor(
  47. content,
  48. stage,
  49. position,
  50. key,
  51. runtimeCondition = true,
  52. endContent
  53. ) {
  54. super(content, stage, position, key, endContent);
  55. this.runtimeCondition = runtimeCondition;
  56. }
  57. /**
  58. * @param {GenerateContext} context context
  59. * @returns {string | Source | undefined} the source code that will be included as initialization code
  60. */
  61. getContent(context) {
  62. if (this.runtimeCondition === false || !this.content) return "";
  63. if (this.runtimeCondition === true) return this.content;
  64. const expr = context.runtimeTemplate.runtimeConditionExpression({
  65. chunkGraph: context.chunkGraph,
  66. runtimeRequirements: context.runtimeRequirements,
  67. runtime: context.runtime,
  68. runtimeCondition: this.runtimeCondition
  69. });
  70. if (expr === "true") return this.content;
  71. return wrapInCondition(expr, this.content);
  72. }
  73. /**
  74. * @param {GenerateContext} context context
  75. * @returns {string|Source=} the source code that will be included at the end of the module
  76. */
  77. getEndContent(context) {
  78. if (this.runtimeCondition === false || !this.endContent) return "";
  79. if (this.runtimeCondition === true) return this.endContent;
  80. const expr = context.runtimeTemplate.runtimeConditionExpression({
  81. chunkGraph: context.chunkGraph,
  82. runtimeRequirements: context.runtimeRequirements,
  83. runtime: context.runtime,
  84. runtimeCondition: this.runtimeCondition
  85. });
  86. if (expr === "true") return this.endContent;
  87. return wrapInCondition(expr, this.endContent);
  88. }
  89. /**
  90. * @param {ConditionalInitFragment} other fragment to merge with
  91. * @returns {ConditionalInitFragment} merged fragment
  92. */
  93. merge(other) {
  94. if (this.runtimeCondition === true) return this;
  95. if (other.runtimeCondition === true) return other;
  96. if (this.runtimeCondition === false) return other;
  97. if (other.runtimeCondition === false) return this;
  98. const runtimeCondition = mergeRuntime(
  99. this.runtimeCondition,
  100. other.runtimeCondition
  101. );
  102. return new ConditionalInitFragment(
  103. this.content,
  104. this.stage,
  105. this.position,
  106. this.key,
  107. runtimeCondition,
  108. this.endContent
  109. );
  110. }
  111. }
  112. module.exports = ConditionalInitFragment;