ImportParserPlugin.js 8.0 KB

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