RequireEnsureDependenciesBlockParserPlugin.js 3.8 KB

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