ConditionalInitFragment.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. * @typedef {GenerateContext} Context
  36. * @extends {InitFragment<Context>}
  37. */
  38. class ConditionalInitFragment extends InitFragment {
  39. /**
  40. * @param {string|Source} content the source code that will be included as initialization code
  41. * @param {number} stage category of initialization code (contribute to order)
  42. * @param {number} position position in the category (contribute to order)
  43. * @param {string | undefined} key unique key to avoid emitting the same initialization code twice
  44. * @param {RuntimeSpec | boolean} runtimeCondition in which runtime this fragment should be executed
  45. * @param {string|Source=} endContent the source code that will be included at the end of the module
  46. */
  47. constructor(
  48. content,
  49. stage,
  50. position,
  51. key,
  52. runtimeCondition = true,
  53. endContent
  54. ) {
  55. super(content, stage, position, key, endContent);
  56. this.runtimeCondition = runtimeCondition;
  57. }
  58. /**
  59. * @param {Context} context context
  60. * @returns {string|Source} the source code that will be included as initialization code
  61. */
  62. getContent(context) {
  63. if (this.runtimeCondition === false || !this.content) return "";
  64. if (this.runtimeCondition === true) return this.content;
  65. const expr = context.runtimeTemplate.runtimeConditionExpression({
  66. chunkGraph: context.chunkGraph,
  67. runtimeRequirements: context.runtimeRequirements,
  68. runtime: context.runtime,
  69. runtimeCondition: this.runtimeCondition
  70. });
  71. if (expr === "true") return this.content;
  72. return wrapInCondition(expr, this.content);
  73. }
  74. /**
  75. * @param {Context} context context
  76. * @returns {string|Source=} the source code that will be included at the end of the module
  77. */
  78. getEndContent(context) {
  79. if (this.runtimeCondition === false || !this.endContent) return "";
  80. if (this.runtimeCondition === true) return this.endContent;
  81. const expr = context.runtimeTemplate.runtimeConditionExpression({
  82. chunkGraph: context.chunkGraph,
  83. runtimeRequirements: context.runtimeRequirements,
  84. runtime: context.runtime,
  85. runtimeCondition: this.runtimeCondition
  86. });
  87. if (expr === "true") return this.endContent;
  88. return wrapInCondition(expr, this.endContent);
  89. }
  90. /**
  91. * @param {ConditionalInitFragment} other fragment to merge with
  92. * @returns {ConditionalInitFragment} merged fragment
  93. */
  94. merge(other) {
  95. if (this.runtimeCondition === true) return this;
  96. if (other.runtimeCondition === true) return other;
  97. if (this.runtimeCondition === false) return other;
  98. if (other.runtimeCondition === false) return this;
  99. const runtimeCondition = mergeRuntime(
  100. this.runtimeCondition,
  101. other.runtimeCondition
  102. );
  103. return new ConditionalInitFragment(
  104. this.content,
  105. this.stage,
  106. this.position,
  107. this.key,
  108. runtimeCondition,
  109. this.endContent
  110. );
  111. }
  112. }
  113. module.exports = ConditionalInitFragment;