ImportParserPlugin.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
  7. const CommentCompilationWarning = require("../CommentCompilationWarning");
  8. const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
  9. const ContextDependencyHelpers = require("./ContextDependencyHelpers");
  10. const ImportContextDependency = require("./ImportContextDependency");
  11. const ImportDependency = require("./ImportDependency");
  12. const ImportEagerDependency = require("./ImportEagerDependency");
  13. const ImportWeakDependency = require("./ImportWeakDependency");
  14. /** @typedef {import("../ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */
  15. /** @typedef {import("../ContextModule").ContextMode} ContextMode */
  16. class ImportParserPlugin {
  17. constructor(options) {
  18. this.options = options;
  19. }
  20. apply(parser) {
  21. parser.hooks.importCall.tap("ImportParserPlugin", expr => {
  22. const param = parser.evaluateExpression(expr.source);
  23. let chunkName = null;
  24. /** @type {ContextMode} */
  25. let mode = "lazy";
  26. let include = null;
  27. let exclude = null;
  28. /** @type {string[][] | null} */
  29. let exports = null;
  30. /** @type {RawChunkGroupOptions} */
  31. const groupOptions = {};
  32. const { options: importOptions, errors: commentErrors } =
  33. parser.parseCommentOptions(expr.range);
  34. if (commentErrors) {
  35. for (const e of commentErrors) {
  36. const { comment } = e;
  37. parser.state.module.addWarning(
  38. new CommentCompilationWarning(
  39. `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
  40. comment.loc
  41. )
  42. );
  43. }
  44. }
  45. if (importOptions) {
  46. if (importOptions.webpackIgnore !== undefined) {
  47. if (typeof importOptions.webpackIgnore !== "boolean") {
  48. parser.state.module.addWarning(
  49. new UnsupportedFeatureWarning(
  50. `\`webpackIgnore\` expected a boolean, but received: ${importOptions.webpackIgnore}.`,
  51. expr.loc
  52. )
  53. );
  54. } else {
  55. // Do not instrument `import()` if `webpackIgnore` is `true`
  56. if (importOptions.webpackIgnore) {
  57. return false;
  58. }
  59. }
  60. }
  61. if (importOptions.webpackChunkName !== undefined) {
  62. if (typeof importOptions.webpackChunkName !== "string") {
  63. parser.state.module.addWarning(
  64. new UnsupportedFeatureWarning(
  65. `\`webpackChunkName\` expected a string, but received: ${importOptions.webpackChunkName}.`,
  66. expr.loc
  67. )
  68. );
  69. } else {
  70. chunkName = importOptions.webpackChunkName;
  71. }
  72. }
  73. if (importOptions.webpackMode !== undefined) {
  74. if (typeof importOptions.webpackMode !== "string") {
  75. parser.state.module.addWarning(
  76. new UnsupportedFeatureWarning(
  77. `\`webpackMode\` expected a string, but received: ${importOptions.webpackMode}.`,
  78. expr.loc
  79. )
  80. );
  81. } else {
  82. mode = importOptions.webpackMode;
  83. }
  84. }
  85. if (importOptions.webpackPrefetch !== undefined) {
  86. if (importOptions.webpackPrefetch === true) {
  87. groupOptions.prefetchOrder = 0;
  88. } else if (typeof importOptions.webpackPrefetch === "number") {
  89. groupOptions.prefetchOrder = importOptions.webpackPrefetch;
  90. } else {
  91. parser.state.module.addWarning(
  92. new UnsupportedFeatureWarning(
  93. `\`webpackPrefetch\` expected true or a number, but received: ${importOptions.webpackPrefetch}.`,
  94. expr.loc
  95. )
  96. );
  97. }
  98. }
  99. if (importOptions.webpackPreload !== undefined) {
  100. if (importOptions.webpackPreload === true) {
  101. groupOptions.preloadOrder = 0;
  102. } else if (typeof importOptions.webpackPreload === "number") {
  103. groupOptions.preloadOrder = importOptions.webpackPreload;
  104. } else {
  105. parser.state.module.addWarning(
  106. new UnsupportedFeatureWarning(
  107. `\`webpackPreload\` expected true or a number, but received: ${importOptions.webpackPreload}.`,
  108. expr.loc
  109. )
  110. );
  111. }
  112. }
  113. if (importOptions.webpackInclude !== undefined) {
  114. if (
  115. !importOptions.webpackInclude ||
  116. importOptions.webpackInclude.constructor.name !== "RegExp"
  117. ) {
  118. parser.state.module.addWarning(
  119. new UnsupportedFeatureWarning(
  120. `\`webpackInclude\` expected a regular expression, but received: ${importOptions.webpackInclude}.`,
  121. expr.loc
  122. )
  123. );
  124. } else {
  125. include = new RegExp(importOptions.webpackInclude);
  126. }
  127. }
  128. if (importOptions.webpackExclude !== undefined) {
  129. if (
  130. !importOptions.webpackExclude ||
  131. importOptions.webpackExclude.constructor.name !== "RegExp"
  132. ) {
  133. parser.state.module.addWarning(
  134. new UnsupportedFeatureWarning(
  135. `\`webpackExclude\` expected a regular expression, but received: ${importOptions.webpackExclude}.`,
  136. expr.loc
  137. )
  138. );
  139. } else {
  140. exclude = new RegExp(importOptions.webpackExclude);
  141. }
  142. }
  143. if (importOptions.webpackExports !== undefined) {
  144. if (
  145. !(
  146. typeof importOptions.webpackExports === "string" ||
  147. (Array.isArray(importOptions.webpackExports) &&
  148. importOptions.webpackExports.every(
  149. item => typeof item === "string"
  150. ))
  151. )
  152. ) {
  153. parser.state.module.addWarning(
  154. new UnsupportedFeatureWarning(
  155. `\`webpackExports\` expected a string or an array of strings, but received: ${importOptions.webpackExports}.`,
  156. expr.loc
  157. )
  158. );
  159. } else {
  160. if (typeof importOptions.webpackExports === "string") {
  161. exports = [[importOptions.webpackExports]];
  162. } else {
  163. exports = Array.from(importOptions.webpackExports, e => [e]);
  164. }
  165. }
  166. }
  167. }
  168. if (param.isString()) {
  169. if (mode !== "lazy" && mode !== "eager" && mode !== "weak") {
  170. parser.state.module.addWarning(
  171. new UnsupportedFeatureWarning(
  172. `\`webpackMode\` expected 'lazy', 'eager' or 'weak', but received: ${mode}.`,
  173. expr.loc
  174. )
  175. );
  176. }
  177. if (mode === "eager") {
  178. const dep = new ImportEagerDependency(
  179. param.string,
  180. expr.range,
  181. exports
  182. );
  183. parser.state.current.addDependency(dep);
  184. } else if (mode === "weak") {
  185. const dep = new ImportWeakDependency(
  186. param.string,
  187. expr.range,
  188. exports
  189. );
  190. parser.state.current.addDependency(dep);
  191. } else {
  192. const depBlock = new AsyncDependenciesBlock(
  193. {
  194. ...groupOptions,
  195. name: chunkName
  196. },
  197. expr.loc,
  198. param.string
  199. );
  200. const dep = new ImportDependency(param.string, expr.range, exports);
  201. dep.loc = expr.loc;
  202. depBlock.addDependency(dep);
  203. parser.state.current.addBlock(depBlock);
  204. }
  205. return true;
  206. } else {
  207. if (
  208. mode !== "lazy" &&
  209. mode !== "lazy-once" &&
  210. mode !== "eager" &&
  211. mode !== "weak"
  212. ) {
  213. parser.state.module.addWarning(
  214. new UnsupportedFeatureWarning(
  215. `\`webpackMode\` expected 'lazy', 'lazy-once', 'eager' or 'weak', but received: ${mode}.`,
  216. expr.loc
  217. )
  218. );
  219. mode = "lazy";
  220. }
  221. if (mode === "weak") {
  222. mode = "async-weak";
  223. }
  224. const dep = ContextDependencyHelpers.create(
  225. ImportContextDependency,
  226. expr.range,
  227. param,
  228. expr,
  229. this.options,
  230. {
  231. chunkName,
  232. groupOptions,
  233. include,
  234. exclude,
  235. mode,
  236. namespaceObject: parser.state.module.buildMeta.strictHarmonyModule
  237. ? "strict"
  238. : true,
  239. typePrefix: "import()",
  240. category: "esm",
  241. referencedExports: exports
  242. },
  243. parser
  244. );
  245. if (!dep) return;
  246. dep.loc = expr.loc;
  247. dep.optional = !!parser.scope.inTry;
  248. parser.state.current.addDependency(dep);
  249. return true;
  250. }
  251. });
  252. }
  253. }
  254. module.exports = ImportParserPlugin;