RequireEnsureDependenciesBlockParserPlugin.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RequireEnsureDependenciesBlock = require("./RequireEnsureDependenciesBlock");
  7. const RequireEnsureDependency = require("./RequireEnsureDependency");
  8. const RequireEnsureItemDependency = require("./RequireEnsureItemDependency");
  9. const getFunctionExpression = require("./getFunctionExpression");
  10. /** @typedef {import("../ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */
  11. /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
  12. /** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
  13. /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
  14. /** @typedef {import("../javascript/JavascriptParser").Range} Range */
  15. module.exports = class RequireEnsureDependenciesBlockParserPlugin {
  16. /**
  17. * @param {JavascriptParser} parser the parser
  18. * @returns {void}
  19. */
  20. apply(parser) {
  21. parser.hooks.call
  22. .for("require.ensure")
  23. .tap("RequireEnsureDependenciesBlockParserPlugin", expr => {
  24. let chunkName = null;
  25. let errorExpressionArg = null;
  26. let errorExpression = null;
  27. switch (expr.arguments.length) {
  28. case 4: {
  29. const chunkNameExpr = parser.evaluateExpression(expr.arguments[3]);
  30. if (!chunkNameExpr.isString()) return;
  31. chunkName = chunkNameExpr.string;
  32. }
  33. // falls through
  34. case 3: {
  35. errorExpressionArg = expr.arguments[2];
  36. errorExpression = getFunctionExpression(errorExpressionArg);
  37. if (!errorExpression && !chunkName) {
  38. const chunkNameExpr = parser.evaluateExpression(
  39. expr.arguments[2]
  40. );
  41. if (!chunkNameExpr.isString()) return;
  42. chunkName = chunkNameExpr.string;
  43. }
  44. }
  45. // falls through
  46. case 2: {
  47. const dependenciesExpr = parser.evaluateExpression(
  48. expr.arguments[0]
  49. );
  50. const dependenciesItems =
  51. /** @type {BasicEvaluatedExpression[]} */ (
  52. dependenciesExpr.isArray()
  53. ? dependenciesExpr.items
  54. : [dependenciesExpr]
  55. );
  56. const successExpressionArg = expr.arguments[1];
  57. const successExpression =
  58. getFunctionExpression(successExpressionArg);
  59. if (successExpression) {
  60. parser.walkExpressions(successExpression.expressions);
  61. }
  62. if (errorExpression) {
  63. parser.walkExpressions(errorExpression.expressions);
  64. }
  65. const depBlock = new RequireEnsureDependenciesBlock(
  66. /** @type {ChunkGroupOptions & { entryOptions?: TODO }} */
  67. (chunkName),
  68. /** @type {DependencyLocation} */ (expr.loc)
  69. );
  70. const errorCallbackExists =
  71. expr.arguments.length === 4 ||
  72. (!chunkName && expr.arguments.length === 3);
  73. const dep = new RequireEnsureDependency(
  74. /** @type {Range} */ (expr.range),
  75. /** @type {Range} */ (expr.arguments[1].range),
  76. errorCallbackExists &&
  77. /** @type {Range} */ (expr.arguments[2].range)
  78. );
  79. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  80. depBlock.addDependency(dep);
  81. const old = parser.state.current;
  82. parser.state.current = /** @type {TODO} */ (depBlock);
  83. try {
  84. let failed = false;
  85. parser.inScope([], () => {
  86. for (const ee of dependenciesItems) {
  87. if (ee.isString()) {
  88. const ensureDependency = new RequireEnsureItemDependency(
  89. /** @type {string} */ (ee.string)
  90. );
  91. ensureDependency.loc =
  92. /** @type {DependencyLocation} */
  93. (expr.loc);
  94. depBlock.addDependency(ensureDependency);
  95. } else {
  96. failed = true;
  97. }
  98. }
  99. });
  100. if (failed) {
  101. return;
  102. }
  103. if (successExpression) {
  104. if (successExpression.fn.body.type === "BlockStatement") {
  105. parser.walkStatement(successExpression.fn.body);
  106. } else {
  107. parser.walkExpression(successExpression.fn.body);
  108. }
  109. }
  110. old.addBlock(depBlock);
  111. } finally {
  112. parser.state.current = old;
  113. }
  114. if (!successExpression) {
  115. parser.walkExpression(successExpressionArg);
  116. }
  117. if (errorExpression) {
  118. if (errorExpression.fn.body.type === "BlockStatement") {
  119. parser.walkStatement(errorExpression.fn.body);
  120. } else {
  121. parser.walkExpression(errorExpression.fn.body);
  122. }
  123. } else if (errorExpressionArg) {
  124. parser.walkExpression(errorExpressionArg);
  125. }
  126. return true;
  127. }
  128. }
  129. });
  130. }
  131. };