NormalModuleFactory.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { getContext } = require("loader-runner");
  7. const asyncLib = require("neo-async");
  8. const {
  9. AsyncSeriesBailHook,
  10. HookMap,
  11. SyncBailHook,
  12. SyncHook,
  13. SyncWaterfallHook
  14. } = require("tapable");
  15. const ChunkGraph = require("./ChunkGraph");
  16. const Module = require("./Module");
  17. const ModuleFactory = require("./ModuleFactory");
  18. const ModuleGraph = require("./ModuleGraph");
  19. const { JAVASCRIPT_MODULE_TYPE_AUTO } = require("./ModuleTypeConstants");
  20. const NormalModule = require("./NormalModule");
  21. const BasicEffectRulePlugin = require("./rules/BasicEffectRulePlugin");
  22. const BasicMatcherRulePlugin = require("./rules/BasicMatcherRulePlugin");
  23. const ObjectMatcherRulePlugin = require("./rules/ObjectMatcherRulePlugin");
  24. const RuleSetCompiler = require("./rules/RuleSetCompiler");
  25. const UseEffectRulePlugin = require("./rules/UseEffectRulePlugin");
  26. const LazySet = require("./util/LazySet");
  27. const { getScheme } = require("./util/URLAbsoluteSpecifier");
  28. const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge");
  29. const { join } = require("./util/fs");
  30. const {
  31. parseResource,
  32. parseResourceWithoutFragment
  33. } = require("./util/identifier");
  34. /** @typedef {import("../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */
  35. /** @typedef {import("../declarations/WebpackOptions").RuleSetRule} RuleSetRule */
  36. /** @typedef {import("./Generator")} Generator */
  37. /** @typedef {import("./ModuleFactory").ModuleFactoryCallback} ModuleFactoryCallback */
  38. /** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
  39. /** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */
  40. /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
  41. /** @typedef {import("./NormalModule").GeneratorOptions} GeneratorOptions */
  42. /** @typedef {import("./NormalModule").LoaderItem} LoaderItem */
  43. /** @typedef {import("./NormalModule").NormalModuleCreateData} NormalModuleCreateData */
  44. /** @typedef {import("./NormalModule").ParserOptions} ParserOptions */
  45. /** @typedef {import("./Parser")} Parser */
  46. /** @typedef {import("./ResolverFactory")} ResolverFactory */
  47. /** @typedef {import("./ResolverFactory").ResolveContext} ResolveContext */
  48. /** @typedef {import("./ResolverFactory").ResolveRequest} ResolveRequest */
  49. /** @typedef {import("./ResolverFactory").ResolverWithOptions} ResolverWithOptions */
  50. /** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
  51. /** @typedef {import("./javascript/JavascriptParser").ImportAttributes} ImportAttributes */
  52. /** @typedef {import("./rules/RuleSetCompiler").RuleSetRules} RuleSetRules */
  53. /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
  54. /** @typedef {import("./util/identifier").AssociatedObjectForCache} AssociatedObjectForCache */
  55. /** @typedef {Pick<RuleSetRule, 'type' | 'sideEffects' | 'parser' | 'generator' | 'resolve' | 'layer'>} ModuleSettings */
  56. /** @typedef {Partial<NormalModuleCreateData & { settings: ModuleSettings }>} CreateData */
  57. /**
  58. * @typedef {object} ResolveData
  59. * @property {ModuleFactoryCreateData["contextInfo"]} contextInfo
  60. * @property {ModuleFactoryCreateData["resolveOptions"]} resolveOptions
  61. * @property {string} context
  62. * @property {string} request
  63. * @property {ImportAttributes | undefined} assertions
  64. * @property {ModuleDependency[]} dependencies
  65. * @property {string} dependencyType
  66. * @property {CreateData} createData
  67. * @property {LazySet<string>} fileDependencies
  68. * @property {LazySet<string>} missingDependencies
  69. * @property {LazySet<string>} contextDependencies
  70. * @property {Module=} ignoredModule
  71. * @property {boolean} cacheable allow to use the unsafe cache
  72. */
  73. /**
  74. * @typedef {object} ResourceData
  75. * @property {string} resource
  76. * @property {string=} path
  77. * @property {string=} query
  78. * @property {string=} fragment
  79. * @property {string=} context
  80. */
  81. /**
  82. * @typedef {object} ResourceSchemeData
  83. * @property {string=} mimetype mime type of the resource
  84. * @property {string=} parameters additional parameters for the resource
  85. * @property {"base64" | false=} encoding encoding of the resource
  86. * @property {string=} encodedContent encoded content of the resource
  87. */
  88. /** @typedef {ResourceData & { data: ResourceSchemeData & Partial<ResolveRequest> }} ResourceDataWithData */
  89. /**
  90. * @typedef {object} ParsedLoaderRequest
  91. * @property {string} loader loader
  92. * @property {string|undefined} options options
  93. */
  94. /**
  95. * @template T
  96. * @callback Callback
  97. * @param {(Error | null)=} err
  98. * @param {T=} stats
  99. * @returns {void}
  100. */
  101. const EMPTY_RESOLVE_OPTIONS = {};
  102. /** @type {ParserOptions} */
  103. const EMPTY_PARSER_OPTIONS = {};
  104. /** @type {GeneratorOptions} */
  105. const EMPTY_GENERATOR_OPTIONS = {};
  106. /** @type {ParsedLoaderRequest[]} */
  107. const EMPTY_ELEMENTS = [];
  108. const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
  109. const LEADING_DOT_EXTENSION_REGEX = /^[^.]/;
  110. /**
  111. * @param {LoaderItem} data data
  112. * @returns {string} ident
  113. */
  114. const loaderToIdent = data => {
  115. if (!data.options) {
  116. return data.loader;
  117. }
  118. if (typeof data.options === "string") {
  119. return `${data.loader}?${data.options}`;
  120. }
  121. if (typeof data.options !== "object") {
  122. throw new Error("loader options must be string or object");
  123. }
  124. if (data.ident) {
  125. return `${data.loader}??${data.ident}`;
  126. }
  127. return `${data.loader}?${JSON.stringify(data.options)}`;
  128. };
  129. /**
  130. * @param {LoaderItem[]} loaders loaders
  131. * @param {string} resource resource
  132. * @returns {string} stringified loaders and resource
  133. */
  134. const stringifyLoadersAndResource = (loaders, resource) => {
  135. let str = "";
  136. for (const loader of loaders) {
  137. str += `${loaderToIdent(loader)}!`;
  138. }
  139. return str + resource;
  140. };
  141. /**
  142. * @param {number} times times
  143. * @param {(err?: null | Error) => void} callback callback
  144. * @returns {(err?: null | Error) => void} callback
  145. */
  146. const needCalls = (times, callback) => err => {
  147. if (--times === 0) {
  148. return callback(err);
  149. }
  150. if (err && times > 0) {
  151. times = Number.NaN;
  152. return callback(err);
  153. }
  154. };
  155. /**
  156. * @template T
  157. * @template O
  158. * @param {T} globalOptions global options
  159. * @param {string} type type
  160. * @param {O} localOptions local options
  161. * @returns {T & O | T | O} result
  162. */
  163. const mergeGlobalOptions = (globalOptions, type, localOptions) => {
  164. const parts = type.split("/");
  165. let result;
  166. let current = "";
  167. for (const part of parts) {
  168. current = current ? `${current}/${part}` : part;
  169. const options =
  170. /** @type {T} */
  171. (globalOptions[/** @type {keyof T} */ (current)]);
  172. if (typeof options === "object") {
  173. result =
  174. result === undefined ? options : cachedCleverMerge(result, options);
  175. }
  176. }
  177. if (result === undefined) {
  178. return localOptions;
  179. }
  180. return cachedCleverMerge(result, localOptions);
  181. };
  182. // TODO webpack 6 remove
  183. /**
  184. * @template {import("tapable").Hook<EXPECTED_ANY, EXPECTED_ANY>} T
  185. * @param {string} name name
  186. * @param {T} hook hook
  187. * @returns {string} result
  188. */
  189. const deprecationChangedHookMessage = (name, hook) => {
  190. const names = hook.taps.map(tapped => tapped.name).join(", ");
  191. return (
  192. `NormalModuleFactory.${name} (${names}) is no longer a waterfall hook, but a bailing hook instead. ` +
  193. "Do not return the passed object, but modify it instead. " +
  194. "Returning false will ignore the request and results in no module created."
  195. );
  196. };
  197. const ruleSetCompiler = new RuleSetCompiler([
  198. new BasicMatcherRulePlugin("test", "resource"),
  199. new BasicMatcherRulePlugin("scheme"),
  200. new BasicMatcherRulePlugin("mimetype"),
  201. new BasicMatcherRulePlugin("dependency"),
  202. new BasicMatcherRulePlugin("include", "resource"),
  203. new BasicMatcherRulePlugin("exclude", "resource", true),
  204. new BasicMatcherRulePlugin("resource"),
  205. new BasicMatcherRulePlugin("resourceQuery"),
  206. new BasicMatcherRulePlugin("resourceFragment"),
  207. new BasicMatcherRulePlugin("realResource"),
  208. new BasicMatcherRulePlugin("issuer"),
  209. new BasicMatcherRulePlugin("compiler"),
  210. new BasicMatcherRulePlugin("issuerLayer"),
  211. new ObjectMatcherRulePlugin("assert", "assertions", value => {
  212. if (value) {
  213. return (
  214. /** @type {ImportAttributes} */ (value)._isLegacyAssert !== undefined
  215. );
  216. }
  217. return false;
  218. }),
  219. new ObjectMatcherRulePlugin("with", "assertions", value => {
  220. if (value) {
  221. return !(/** @type {ImportAttributes} */ (value)._isLegacyAssert);
  222. }
  223. return false;
  224. }),
  225. new ObjectMatcherRulePlugin("descriptionData"),
  226. new BasicEffectRulePlugin("type"),
  227. new BasicEffectRulePlugin("sideEffects"),
  228. new BasicEffectRulePlugin("parser"),
  229. new BasicEffectRulePlugin("resolve"),
  230. new BasicEffectRulePlugin("generator"),
  231. new BasicEffectRulePlugin("layer"),
  232. new UseEffectRulePlugin()
  233. ]);
  234. class NormalModuleFactory extends ModuleFactory {
  235. /**
  236. * @param {object} param params
  237. * @param {string=} param.context context
  238. * @param {InputFileSystem} param.fs file system
  239. * @param {ResolverFactory} param.resolverFactory resolverFactory
  240. * @param {ModuleOptions} param.options options
  241. * @param {AssociatedObjectForCache} param.associatedObjectForCache an object to which the cache will be attached
  242. * @param {boolean=} param.layers enable layers
  243. */
  244. constructor({
  245. context,
  246. fs,
  247. resolverFactory,
  248. options,
  249. associatedObjectForCache,
  250. layers = false
  251. }) {
  252. super();
  253. this.hooks = Object.freeze({
  254. /** @type {AsyncSeriesBailHook<[ResolveData], Module | false | void>} */
  255. resolve: new AsyncSeriesBailHook(["resolveData"]),
  256. /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
  257. resolveForScheme: new HookMap(
  258. () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
  259. ),
  260. /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
  261. resolveInScheme: new HookMap(
  262. () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
  263. ),
  264. /** @type {AsyncSeriesBailHook<[ResolveData], Module | undefined>} */
  265. factorize: new AsyncSeriesBailHook(["resolveData"]),
  266. /** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */
  267. beforeResolve: new AsyncSeriesBailHook(["resolveData"]),
  268. /** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */
  269. afterResolve: new AsyncSeriesBailHook(["resolveData"]),
  270. /** @type {AsyncSeriesBailHook<[CreateData, ResolveData], Module | void>} */
  271. createModule: new AsyncSeriesBailHook(["createData", "resolveData"]),
  272. /** @type {SyncWaterfallHook<[Module, CreateData, ResolveData]>} */
  273. module: new SyncWaterfallHook(["module", "createData", "resolveData"]),
  274. /** @type {HookMap<SyncBailHook<[ParserOptions], Parser | void>>} */
  275. createParser: new HookMap(() => new SyncBailHook(["parserOptions"])),
  276. /** @type {HookMap<SyncBailHook<[TODO, ParserOptions], void>>} */
  277. parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])),
  278. /** @type {HookMap<SyncBailHook<[GeneratorOptions], Generator | void>>} */
  279. createGenerator: new HookMap(
  280. () => new SyncBailHook(["generatorOptions"])
  281. ),
  282. /** @type {HookMap<SyncBailHook<[TODO, GeneratorOptions], void>>} */
  283. generator: new HookMap(
  284. () => new SyncHook(["generator", "generatorOptions"])
  285. ),
  286. /** @type {HookMap<SyncBailHook<[CreateData, ResolveData], Module | void>>} */
  287. createModuleClass: new HookMap(
  288. () => new SyncBailHook(["createData", "resolveData"])
  289. )
  290. });
  291. this.resolverFactory = resolverFactory;
  292. this.ruleSet = ruleSetCompiler.compile([
  293. {
  294. rules: /** @type {RuleSetRules} */ (options.defaultRules)
  295. },
  296. {
  297. rules: /** @type {RuleSetRules} */ (options.rules)
  298. }
  299. ]);
  300. this.context = context || "";
  301. this.fs = fs;
  302. this._globalParserOptions = options.parser;
  303. this._globalGeneratorOptions = options.generator;
  304. /** @type {Map<string, WeakMap<ParserOptions, Parser>>} */
  305. this.parserCache = new Map();
  306. /** @type {Map<string, WeakMap<GeneratorOptions, Generator>>} */
  307. this.generatorCache = new Map();
  308. /** @type {Set<Module>} */
  309. this._restoredUnsafeCacheEntries = new Set();
  310. /** @type {(resource: string) => import("./util/identifier").ParsedResource} */
  311. const cacheParseResource = parseResource.bindCache(
  312. associatedObjectForCache
  313. );
  314. const cachedParseResourceWithoutFragment =
  315. parseResourceWithoutFragment.bindCache(associatedObjectForCache);
  316. this._parseResourceWithoutFragment = cachedParseResourceWithoutFragment;
  317. this.hooks.factorize.tapAsync(
  318. {
  319. name: "NormalModuleFactory",
  320. stage: 100
  321. },
  322. (resolveData, callback) => {
  323. this.hooks.resolve.callAsync(resolveData, (err, result) => {
  324. if (err) return callback(err);
  325. // Ignored
  326. if (result === false) return callback();
  327. // direct module
  328. if (result instanceof Module) return callback(null, result);
  329. if (typeof result === "object") {
  330. throw new Error(
  331. `${deprecationChangedHookMessage(
  332. "resolve",
  333. this.hooks.resolve
  334. )} Returning a Module object will result in this module used as result.`
  335. );
  336. }
  337. this.hooks.afterResolve.callAsync(resolveData, (err, result) => {
  338. if (err) return callback(err);
  339. if (typeof result === "object") {
  340. throw new Error(
  341. deprecationChangedHookMessage(
  342. "afterResolve",
  343. this.hooks.afterResolve
  344. )
  345. );
  346. }
  347. // Ignored
  348. if (result === false) return callback();
  349. const createData = resolveData.createData;
  350. this.hooks.createModule.callAsync(
  351. createData,
  352. resolveData,
  353. (err, createdModule) => {
  354. if (!createdModule) {
  355. if (!resolveData.request) {
  356. return callback(new Error("Empty dependency (no request)"));
  357. }
  358. // TODO webpack 6 make it required and move javascript/wasm/asset properties to own module
  359. createdModule = this.hooks.createModuleClass
  360. .for(
  361. /** @type {ModuleSettings} */
  362. (createData.settings).type
  363. )
  364. .call(createData, resolveData);
  365. if (!createdModule) {
  366. createdModule = /** @type {Module} */ (
  367. new NormalModule(
  368. /** @type {NormalModuleCreateData} */
  369. (createData)
  370. )
  371. );
  372. }
  373. }
  374. createdModule = this.hooks.module.call(
  375. createdModule,
  376. createData,
  377. resolveData
  378. );
  379. return callback(null, createdModule);
  380. }
  381. );
  382. });
  383. });
  384. }
  385. );
  386. this.hooks.resolve.tapAsync(
  387. {
  388. name: "NormalModuleFactory",
  389. stage: 100
  390. },
  391. (data, callback) => {
  392. const {
  393. contextInfo,
  394. context,
  395. dependencies,
  396. dependencyType,
  397. request,
  398. assertions,
  399. resolveOptions,
  400. fileDependencies,
  401. missingDependencies,
  402. contextDependencies
  403. } = data;
  404. const loaderResolver = this.getResolver("loader");
  405. /** @type {ResourceData | undefined} */
  406. let matchResourceData;
  407. /** @type {string} */
  408. let unresolvedResource;
  409. /** @type {ParsedLoaderRequest[]} */
  410. let elements;
  411. let noPreAutoLoaders = false;
  412. let noAutoLoaders = false;
  413. let noPrePostAutoLoaders = false;
  414. const contextScheme = getScheme(context);
  415. /** @type {string | undefined} */
  416. let scheme = getScheme(request);
  417. if (!scheme) {
  418. /** @type {string} */
  419. let requestWithoutMatchResource = request;
  420. const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
  421. if (matchResourceMatch) {
  422. let matchResource = matchResourceMatch[1];
  423. // Check if matchResource starts with ./ or ../
  424. if (matchResource.charCodeAt(0) === 46) {
  425. // 46 is "."
  426. const secondChar = matchResource.charCodeAt(1);
  427. if (
  428. secondChar === 47 || // 47 is "/"
  429. (secondChar === 46 && matchResource.charCodeAt(2) === 47) // "../"
  430. ) {
  431. // Resolve relative path against context
  432. matchResource = join(this.fs, context, matchResource);
  433. }
  434. }
  435. matchResourceData = {
  436. ...cacheParseResource(matchResource),
  437. resource: matchResource
  438. };
  439. requestWithoutMatchResource = request.slice(
  440. matchResourceMatch[0].length
  441. );
  442. }
  443. scheme = getScheme(requestWithoutMatchResource);
  444. if (!scheme && !contextScheme) {
  445. const firstChar = requestWithoutMatchResource.charCodeAt(0);
  446. const secondChar = requestWithoutMatchResource.charCodeAt(1);
  447. noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!"
  448. noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!"
  449. noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!";
  450. const rawElements = requestWithoutMatchResource
  451. .slice(
  452. noPreAutoLoaders || noPrePostAutoLoaders
  453. ? 2
  454. : noAutoLoaders
  455. ? 1
  456. : 0
  457. )
  458. .split(/!+/);
  459. unresolvedResource = /** @type {string} */ (rawElements.pop());
  460. elements = rawElements.map(el => {
  461. const { path, query } = cachedParseResourceWithoutFragment(el);
  462. return {
  463. loader: path,
  464. options: query ? query.slice(1) : undefined
  465. };
  466. });
  467. scheme = getScheme(unresolvedResource);
  468. } else {
  469. unresolvedResource = requestWithoutMatchResource;
  470. elements = EMPTY_ELEMENTS;
  471. }
  472. } else {
  473. unresolvedResource = request;
  474. elements = EMPTY_ELEMENTS;
  475. }
  476. /** @type {ResolveContext} */
  477. const resolveContext = {
  478. fileDependencies,
  479. missingDependencies,
  480. contextDependencies
  481. };
  482. /** @type {ResourceDataWithData} */
  483. let resourceData;
  484. /** @type {undefined | LoaderItem[]} */
  485. let loaders;
  486. const continueCallback = needCalls(2, err => {
  487. if (err) return callback(err);
  488. // translate option idents
  489. try {
  490. for (const item of /** @type {LoaderItem[]} */ (loaders)) {
  491. if (typeof item.options === "string" && item.options[0] === "?") {
  492. const ident = item.options.slice(1);
  493. if (ident === "[[missing ident]]") {
  494. throw new Error(
  495. "No ident is provided by referenced loader. " +
  496. "When using a function for Rule.use in config you need to " +
  497. "provide an 'ident' property for referenced loader options."
  498. );
  499. }
  500. item.options = this.ruleSet.references.get(ident);
  501. if (item.options === undefined) {
  502. throw new Error(
  503. "Invalid ident is provided by referenced loader"
  504. );
  505. }
  506. item.ident = ident;
  507. }
  508. }
  509. } catch (identErr) {
  510. return callback(/** @type {Error} */ (identErr));
  511. }
  512. if (!resourceData) {
  513. // ignored
  514. return callback(null, dependencies[0].createIgnoredModule(context));
  515. }
  516. const userRequest =
  517. (matchResourceData !== undefined
  518. ? `${matchResourceData.resource}!=!`
  519. : "") +
  520. stringifyLoadersAndResource(
  521. /** @type {LoaderItem[]} */ (loaders),
  522. resourceData.resource
  523. );
  524. /** @type {ModuleSettings} */
  525. const settings = {};
  526. /** @type {LoaderItem[]} */
  527. const useLoadersPost = [];
  528. /** @type {LoaderItem[]} */
  529. const useLoaders = [];
  530. /** @type {LoaderItem[]} */
  531. const useLoadersPre = [];
  532. // handle .webpack[] suffix
  533. let resource;
  534. let match;
  535. if (
  536. matchResourceData &&
  537. typeof (resource = matchResourceData.resource) === "string" &&
  538. (match = /\.webpack\[([^\]]+)\]$/.exec(resource))
  539. ) {
  540. settings.type = match[1];
  541. matchResourceData.resource = matchResourceData.resource.slice(
  542. 0,
  543. -settings.type.length - 10
  544. );
  545. } else {
  546. settings.type = JAVASCRIPT_MODULE_TYPE_AUTO;
  547. const resourceDataForRules = matchResourceData || resourceData;
  548. const result = this.ruleSet.exec({
  549. resource: resourceDataForRules.path,
  550. realResource: resourceData.path,
  551. resourceQuery: resourceDataForRules.query,
  552. resourceFragment: resourceDataForRules.fragment,
  553. scheme,
  554. assertions,
  555. mimetype: matchResourceData
  556. ? ""
  557. : resourceData.data.mimetype || "",
  558. dependency: dependencyType,
  559. descriptionData: matchResourceData
  560. ? undefined
  561. : resourceData.data.descriptionFileData,
  562. issuer: contextInfo.issuer,
  563. compiler: contextInfo.compiler,
  564. issuerLayer: contextInfo.issuerLayer || ""
  565. });
  566. for (const r of result) {
  567. // https://github.com/webpack/webpack/issues/16466
  568. // if a request exists PrePostAutoLoaders, should disable modifying Rule.type
  569. if (r.type === "type" && noPrePostAutoLoaders) {
  570. continue;
  571. }
  572. if (r.type === "use") {
  573. if (!noAutoLoaders && !noPrePostAutoLoaders) {
  574. useLoaders.push(r.value);
  575. }
  576. } else if (r.type === "use-post") {
  577. if (!noPrePostAutoLoaders) {
  578. useLoadersPost.push(r.value);
  579. }
  580. } else if (r.type === "use-pre") {
  581. if (!noPreAutoLoaders && !noPrePostAutoLoaders) {
  582. useLoadersPre.push(r.value);
  583. }
  584. } else if (
  585. typeof r.value === "object" &&
  586. r.value !== null &&
  587. typeof settings[
  588. /** @type {keyof ModuleSettings} */
  589. (r.type)
  590. ] === "object" &&
  591. settings[/** @type {keyof ModuleSettings} */ (r.type)] !== null
  592. ) {
  593. const type = /** @type {keyof ModuleSettings} */ (r.type);
  594. settings[type] = cachedCleverMerge(settings[type], r.value);
  595. } else {
  596. const type = /** @type {keyof ModuleSettings} */ (r.type);
  597. settings[type] = r.value;
  598. }
  599. }
  600. }
  601. /** @type {undefined | LoaderItem[]} */
  602. let postLoaders;
  603. /** @type {undefined | LoaderItem[]} */
  604. let normalLoaders;
  605. /** @type {undefined | LoaderItem[]} */
  606. let preLoaders;
  607. const continueCallback = needCalls(3, err => {
  608. if (err) {
  609. return callback(err);
  610. }
  611. const allLoaders = /** @type {LoaderItem[]} */ (postLoaders);
  612. if (matchResourceData === undefined) {
  613. for (const loader of /** @type {LoaderItem[]} */ (loaders)) {
  614. allLoaders.push(loader);
  615. }
  616. for (const loader of /** @type {LoaderItem[]} */ (
  617. normalLoaders
  618. )) {
  619. allLoaders.push(loader);
  620. }
  621. } else {
  622. for (const loader of /** @type {LoaderItem[]} */ (
  623. normalLoaders
  624. )) {
  625. allLoaders.push(loader);
  626. }
  627. for (const loader of /** @type {LoaderItem[]} */ (loaders)) {
  628. allLoaders.push(loader);
  629. }
  630. }
  631. for (const loader of /** @type {LoaderItem[]} */ (preLoaders)) {
  632. allLoaders.push(loader);
  633. }
  634. const type = /** @type {string} */ (settings.type);
  635. const resolveOptions = settings.resolve;
  636. const layer = settings.layer;
  637. if (layer !== undefined && !layers) {
  638. return callback(
  639. new Error(
  640. "'Rule.layer' is only allowed when 'experiments.layers' is enabled"
  641. )
  642. );
  643. }
  644. try {
  645. Object.assign(data.createData, {
  646. layer:
  647. layer === undefined ? contextInfo.issuerLayer || null : layer,
  648. request: stringifyLoadersAndResource(
  649. allLoaders,
  650. resourceData.resource
  651. ),
  652. userRequest,
  653. rawRequest: request,
  654. loaders: allLoaders,
  655. resource: resourceData.resource,
  656. context:
  657. resourceData.context || getContext(resourceData.resource),
  658. matchResource: matchResourceData
  659. ? matchResourceData.resource
  660. : undefined,
  661. resourceResolveData: resourceData.data,
  662. settings,
  663. type,
  664. parser: this.getParser(type, settings.parser),
  665. parserOptions: settings.parser,
  666. generator: this.getGenerator(type, settings.generator),
  667. generatorOptions: settings.generator,
  668. resolveOptions
  669. });
  670. } catch (createDataErr) {
  671. return callback(/** @type {Error} */ (createDataErr));
  672. }
  673. callback();
  674. });
  675. this.resolveRequestArray(
  676. contextInfo,
  677. this.context,
  678. useLoadersPost,
  679. loaderResolver,
  680. resolveContext,
  681. (err, result) => {
  682. postLoaders = result;
  683. continueCallback(err);
  684. }
  685. );
  686. this.resolveRequestArray(
  687. contextInfo,
  688. this.context,
  689. useLoaders,
  690. loaderResolver,
  691. resolveContext,
  692. (err, result) => {
  693. normalLoaders = result;
  694. continueCallback(err);
  695. }
  696. );
  697. this.resolveRequestArray(
  698. contextInfo,
  699. this.context,
  700. useLoadersPre,
  701. loaderResolver,
  702. resolveContext,
  703. (err, result) => {
  704. preLoaders = result;
  705. continueCallback(err);
  706. }
  707. );
  708. });
  709. this.resolveRequestArray(
  710. contextInfo,
  711. contextScheme ? this.context : context,
  712. /** @type {LoaderItem[]} */ (elements),
  713. loaderResolver,
  714. resolveContext,
  715. (err, result) => {
  716. if (err) return continueCallback(err);
  717. loaders = result;
  718. continueCallback();
  719. }
  720. );
  721. /**
  722. * @param {string} context context
  723. */
  724. const defaultResolve = context => {
  725. if (/^($|\?)/.test(unresolvedResource)) {
  726. resourceData = {
  727. ...cacheParseResource(unresolvedResource),
  728. resource: unresolvedResource,
  729. data: {}
  730. };
  731. continueCallback();
  732. }
  733. // resource without scheme and with path
  734. else {
  735. const normalResolver = this.getResolver(
  736. "normal",
  737. dependencyType
  738. ? cachedSetProperty(
  739. resolveOptions || EMPTY_RESOLVE_OPTIONS,
  740. "dependencyType",
  741. dependencyType
  742. )
  743. : resolveOptions
  744. );
  745. this.resolveResource(
  746. contextInfo,
  747. context,
  748. unresolvedResource,
  749. normalResolver,
  750. resolveContext,
  751. (err, _resolvedResource, resolvedResourceResolveData) => {
  752. if (err) return continueCallback(err);
  753. if (_resolvedResource !== false) {
  754. const resolvedResource =
  755. /** @type {string} */
  756. (_resolvedResource);
  757. resourceData = {
  758. ...cacheParseResource(resolvedResource),
  759. resource: resolvedResource,
  760. data:
  761. /** @type {ResolveRequest} */
  762. (resolvedResourceResolveData)
  763. };
  764. }
  765. continueCallback();
  766. }
  767. );
  768. }
  769. };
  770. // resource with scheme
  771. if (scheme) {
  772. resourceData = {
  773. resource: unresolvedResource,
  774. data: {},
  775. path: undefined,
  776. query: undefined,
  777. fragment: undefined,
  778. context: undefined
  779. };
  780. this.hooks.resolveForScheme
  781. .for(scheme)
  782. .callAsync(resourceData, data, err => {
  783. if (err) return continueCallback(err);
  784. continueCallback();
  785. });
  786. }
  787. // resource within scheme
  788. else if (contextScheme) {
  789. resourceData = {
  790. resource: unresolvedResource,
  791. data: {},
  792. path: undefined,
  793. query: undefined,
  794. fragment: undefined,
  795. context: undefined
  796. };
  797. this.hooks.resolveInScheme
  798. .for(contextScheme)
  799. .callAsync(resourceData, data, (err, handled) => {
  800. if (err) return continueCallback(err);
  801. if (!handled) return defaultResolve(this.context);
  802. continueCallback();
  803. });
  804. }
  805. // resource without scheme and without path
  806. else {
  807. defaultResolve(context);
  808. }
  809. }
  810. );
  811. }
  812. cleanupForCache() {
  813. for (const module of this._restoredUnsafeCacheEntries) {
  814. ChunkGraph.clearChunkGraphForModule(module);
  815. ModuleGraph.clearModuleGraphForModule(module);
  816. module.cleanupForCache();
  817. }
  818. }
  819. /**
  820. * @param {ModuleFactoryCreateData} data data object
  821. * @param {ModuleFactoryCallback} callback callback
  822. * @returns {void}
  823. */
  824. create(data, callback) {
  825. const dependencies = /** @type {ModuleDependency[]} */ (data.dependencies);
  826. const context = data.context || this.context;
  827. const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
  828. const dependency = dependencies[0];
  829. const request = dependency.request;
  830. const assertions = dependency.assertions;
  831. const dependencyType = dependency.category || "";
  832. const contextInfo = data.contextInfo;
  833. const fileDependencies = new LazySet();
  834. const missingDependencies = new LazySet();
  835. const contextDependencies = new LazySet();
  836. /** @type {ResolveData} */
  837. const resolveData = {
  838. contextInfo,
  839. resolveOptions,
  840. context,
  841. request,
  842. assertions,
  843. dependencies,
  844. dependencyType,
  845. fileDependencies,
  846. missingDependencies,
  847. contextDependencies,
  848. createData: {},
  849. cacheable: true
  850. };
  851. this.hooks.beforeResolve.callAsync(resolveData, (err, result) => {
  852. if (err) {
  853. return callback(err, {
  854. fileDependencies,
  855. missingDependencies,
  856. contextDependencies,
  857. cacheable: false
  858. });
  859. }
  860. // Ignored
  861. if (result === false) {
  862. /** @type {ModuleFactoryResult} * */
  863. const factoryResult = {
  864. fileDependencies,
  865. missingDependencies,
  866. contextDependencies,
  867. cacheable: resolveData.cacheable
  868. };
  869. if (resolveData.ignoredModule) {
  870. factoryResult.module = resolveData.ignoredModule;
  871. }
  872. return callback(null, factoryResult);
  873. }
  874. if (typeof result === "object") {
  875. throw new Error(
  876. deprecationChangedHookMessage(
  877. "beforeResolve",
  878. this.hooks.beforeResolve
  879. )
  880. );
  881. }
  882. this.hooks.factorize.callAsync(resolveData, (err, module) => {
  883. if (err) {
  884. return callback(err, {
  885. fileDependencies,
  886. missingDependencies,
  887. contextDependencies,
  888. cacheable: false
  889. });
  890. }
  891. /** @type {ModuleFactoryResult} * */
  892. const factoryResult = {
  893. module,
  894. fileDependencies,
  895. missingDependencies,
  896. contextDependencies,
  897. cacheable: resolveData.cacheable
  898. };
  899. callback(null, factoryResult);
  900. });
  901. });
  902. }
  903. /**
  904. * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
  905. * @param {string} context context
  906. * @param {string} unresolvedResource unresolved resource
  907. * @param {ResolverWithOptions} resolver resolver
  908. * @param {ResolveContext} resolveContext resolver context
  909. * @param {(err: null | Error, res?: string | false, req?: ResolveRequest) => void} callback callback
  910. */
  911. resolveResource(
  912. contextInfo,
  913. context,
  914. unresolvedResource,
  915. resolver,
  916. resolveContext,
  917. callback
  918. ) {
  919. resolver.resolve(
  920. contextInfo,
  921. context,
  922. unresolvedResource,
  923. resolveContext,
  924. (err, resolvedResource, resolvedResourceResolveData) => {
  925. if (err) {
  926. return this._resolveResourceErrorHints(
  927. err,
  928. contextInfo,
  929. context,
  930. unresolvedResource,
  931. resolver,
  932. resolveContext,
  933. (err2, hints) => {
  934. if (err2) {
  935. err.message += `
  936. A fatal error happened during resolving additional hints for this error: ${err2.message}`;
  937. err.stack += `
  938. A fatal error happened during resolving additional hints for this error:
  939. ${err2.stack}`;
  940. return callback(err);
  941. }
  942. if (hints && hints.length > 0) {
  943. err.message += `
  944. ${hints.join("\n\n")}`;
  945. }
  946. // Check if the extension is missing a leading dot (e.g. "js" instead of ".js")
  947. let appendResolveExtensionsHint = false;
  948. const specifiedExtensions = [...resolver.options.extensions];
  949. const expectedExtensions = specifiedExtensions.map(extension => {
  950. if (LEADING_DOT_EXTENSION_REGEX.test(extension)) {
  951. appendResolveExtensionsHint = true;
  952. return `.${extension}`;
  953. }
  954. return extension;
  955. });
  956. if (appendResolveExtensionsHint) {
  957. err.message += `\nDid you miss the leading dot in 'resolve.extensions'? Did you mean '${JSON.stringify(
  958. expectedExtensions
  959. )}' instead of '${JSON.stringify(specifiedExtensions)}'?`;
  960. }
  961. callback(err);
  962. }
  963. );
  964. }
  965. callback(err, resolvedResource, resolvedResourceResolveData);
  966. }
  967. );
  968. }
  969. /**
  970. * @param {Error} error error
  971. * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
  972. * @param {string} context context
  973. * @param {string} unresolvedResource unresolved resource
  974. * @param {ResolverWithOptions} resolver resolver
  975. * @param {ResolveContext} resolveContext resolver context
  976. * @param {Callback<string[]>} callback callback
  977. * @private
  978. */
  979. _resolveResourceErrorHints(
  980. error,
  981. contextInfo,
  982. context,
  983. unresolvedResource,
  984. resolver,
  985. resolveContext,
  986. callback
  987. ) {
  988. asyncLib.parallel(
  989. [
  990. callback => {
  991. if (!resolver.options.fullySpecified) return callback();
  992. resolver
  993. .withOptions({
  994. fullySpecified: false
  995. })
  996. .resolve(
  997. contextInfo,
  998. context,
  999. unresolvedResource,
  1000. resolveContext,
  1001. (err, resolvedResource) => {
  1002. if (!err && resolvedResource) {
  1003. const resource = parseResource(resolvedResource).path.replace(
  1004. /^.*[\\/]/,
  1005. ""
  1006. );
  1007. return callback(
  1008. null,
  1009. `Did you mean '${resource}'?
  1010. BREAKING CHANGE: The request '${unresolvedResource}' failed to resolve only because it was resolved as fully specified
  1011. (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
  1012. The extension in the request is mandatory for it to be fully specified.
  1013. Add the extension to the request.`
  1014. );
  1015. }
  1016. callback();
  1017. }
  1018. );
  1019. },
  1020. callback => {
  1021. if (!resolver.options.enforceExtension) return callback();
  1022. resolver
  1023. .withOptions({
  1024. enforceExtension: false,
  1025. extensions: []
  1026. })
  1027. .resolve(
  1028. contextInfo,
  1029. context,
  1030. unresolvedResource,
  1031. resolveContext,
  1032. (err, resolvedResource) => {
  1033. if (!err && resolvedResource) {
  1034. let hint = "";
  1035. const match = /(\.[^.]+)(\?|$)/.exec(unresolvedResource);
  1036. if (match) {
  1037. const fixedRequest = unresolvedResource.replace(
  1038. /(\.[^.]+)(\?|$)/,
  1039. "$2"
  1040. );
  1041. hint = resolver.options.extensions.has(match[1])
  1042. ? `Did you mean '${fixedRequest}'?`
  1043. : `Did you mean '${fixedRequest}'? Also note that '${match[1]}' is not in 'resolve.extensions' yet and need to be added for this to work?`;
  1044. } else {
  1045. hint =
  1046. "Did you mean to omit the extension or to remove 'resolve.enforceExtension'?";
  1047. }
  1048. return callback(
  1049. null,
  1050. `The request '${unresolvedResource}' failed to resolve only because 'resolve.enforceExtension' was specified.
  1051. ${hint}
  1052. Including the extension in the request is no longer possible. Did you mean to enforce including the extension in requests with 'resolve.extensions: []' instead?`
  1053. );
  1054. }
  1055. callback();
  1056. }
  1057. );
  1058. },
  1059. callback => {
  1060. if (
  1061. /^\.\.?\//.test(unresolvedResource) ||
  1062. resolver.options.preferRelative
  1063. ) {
  1064. return callback();
  1065. }
  1066. resolver.resolve(
  1067. contextInfo,
  1068. context,
  1069. `./${unresolvedResource}`,
  1070. resolveContext,
  1071. (err, resolvedResource) => {
  1072. if (err || !resolvedResource) return callback();
  1073. const moduleDirectories = resolver.options.modules
  1074. .map(m => (Array.isArray(m) ? m.join(", ") : m))
  1075. .join(", ");
  1076. callback(
  1077. null,
  1078. `Did you mean './${unresolvedResource}'?
  1079. Requests that should resolve in the current directory need to start with './'.
  1080. Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}).
  1081. If changing the source code is not an option there is also a resolve options called 'preferRelative' which tries to resolve these kind of requests in the current directory too.`
  1082. );
  1083. }
  1084. );
  1085. }
  1086. ],
  1087. (err, hints) => {
  1088. if (err) return callback(err);
  1089. callback(null, /** @type {string[]} */ (hints).filter(Boolean));
  1090. }
  1091. );
  1092. }
  1093. /**
  1094. * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
  1095. * @param {string} context context
  1096. * @param {LoaderItem[]} array array
  1097. * @param {ResolverWithOptions} resolver resolver
  1098. * @param {ResolveContext} resolveContext resolve context
  1099. * @param {Callback<LoaderItem[]>} callback callback
  1100. * @returns {void} result
  1101. */
  1102. resolveRequestArray(
  1103. contextInfo,
  1104. context,
  1105. array,
  1106. resolver,
  1107. resolveContext,
  1108. callback
  1109. ) {
  1110. // LoaderItem
  1111. if (array.length === 0) return callback(null, array);
  1112. asyncLib.map(
  1113. array,
  1114. (item, callback) => {
  1115. resolver.resolve(
  1116. contextInfo,
  1117. context,
  1118. item.loader,
  1119. resolveContext,
  1120. (err, result, resolveRequest) => {
  1121. if (
  1122. err &&
  1123. /^[^/]*$/.test(item.loader) &&
  1124. !item.loader.endsWith("-loader")
  1125. ) {
  1126. return resolver.resolve(
  1127. contextInfo,
  1128. context,
  1129. `${item.loader}-loader`,
  1130. resolveContext,
  1131. err2 => {
  1132. if (!err2) {
  1133. err.message =
  1134. `${err.message}\n` +
  1135. "BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
  1136. ` You need to specify '${item.loader}-loader' instead of '${item.loader}',\n` +
  1137. " see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed";
  1138. }
  1139. callback(err);
  1140. }
  1141. );
  1142. }
  1143. if (err) return callback(err);
  1144. const parsedResult = this._parseResourceWithoutFragment(
  1145. /** @type {string} */ (result)
  1146. );
  1147. const type = /\.mjs$/i.test(parsedResult.path)
  1148. ? "module"
  1149. : /\.cjs$/i.test(parsedResult.path)
  1150. ? "commonjs"
  1151. : /** @type {ResolveRequest} */
  1152. (resolveRequest).descriptionFileData === undefined
  1153. ? undefined
  1154. : /** @type {ResolveRequest} */
  1155. (resolveRequest).descriptionFileData.type;
  1156. const resolved = {
  1157. loader: parsedResult.path,
  1158. type,
  1159. options:
  1160. item.options === undefined
  1161. ? parsedResult.query
  1162. ? parsedResult.query.slice(1)
  1163. : undefined
  1164. : item.options,
  1165. ident:
  1166. item.options === undefined
  1167. ? undefined
  1168. : /** @type {string} */ (item.ident)
  1169. };
  1170. return callback(null, /** @type {LoaderItem} */ (resolved));
  1171. }
  1172. );
  1173. },
  1174. /** @type {Callback<(LoaderItem | undefined)[]>} */ (callback)
  1175. );
  1176. }
  1177. /**
  1178. * @param {string} type type
  1179. * @param {ParserOptions} parserOptions parser options
  1180. * @returns {Parser} parser
  1181. */
  1182. getParser(type, parserOptions = EMPTY_PARSER_OPTIONS) {
  1183. let cache = this.parserCache.get(type);
  1184. if (cache === undefined) {
  1185. cache = new WeakMap();
  1186. this.parserCache.set(type, cache);
  1187. }
  1188. let parser = cache.get(parserOptions);
  1189. if (parser === undefined) {
  1190. parser = this.createParser(type, parserOptions);
  1191. cache.set(parserOptions, parser);
  1192. }
  1193. return parser;
  1194. }
  1195. /**
  1196. * @param {string} type type
  1197. * @param {ParserOptions} parserOptions parser options
  1198. * @returns {Parser} parser
  1199. */
  1200. createParser(type, parserOptions = {}) {
  1201. parserOptions = mergeGlobalOptions(
  1202. this._globalParserOptions,
  1203. type,
  1204. parserOptions
  1205. );
  1206. const parser = this.hooks.createParser.for(type).call(parserOptions);
  1207. if (!parser) {
  1208. throw new Error(`No parser registered for ${type}`);
  1209. }
  1210. this.hooks.parser.for(type).call(parser, parserOptions);
  1211. return parser;
  1212. }
  1213. /**
  1214. * @param {string} type type of generator
  1215. * @param {GeneratorOptions} generatorOptions generator options
  1216. * @returns {Generator} generator
  1217. */
  1218. getGenerator(type, generatorOptions = EMPTY_GENERATOR_OPTIONS) {
  1219. let cache = this.generatorCache.get(type);
  1220. if (cache === undefined) {
  1221. cache = new WeakMap();
  1222. this.generatorCache.set(type, cache);
  1223. }
  1224. let generator = cache.get(generatorOptions);
  1225. if (generator === undefined) {
  1226. generator = this.createGenerator(type, generatorOptions);
  1227. cache.set(generatorOptions, generator);
  1228. }
  1229. return generator;
  1230. }
  1231. /**
  1232. * @param {string} type type of generator
  1233. * @param {GeneratorOptions} generatorOptions generator options
  1234. * @returns {Generator} generator
  1235. */
  1236. createGenerator(type, generatorOptions = {}) {
  1237. generatorOptions = mergeGlobalOptions(
  1238. this._globalGeneratorOptions,
  1239. type,
  1240. generatorOptions
  1241. );
  1242. const generator = this.hooks.createGenerator
  1243. .for(type)
  1244. .call(generatorOptions);
  1245. if (!generator) {
  1246. throw new Error(`No generator registered for ${type}`);
  1247. }
  1248. this.hooks.generator.for(type).call(generator, generatorOptions);
  1249. return generator;
  1250. }
  1251. /**
  1252. * @param {Parameters<ResolverFactory["get"]>[0]} type type of resolver
  1253. * @param {Parameters<ResolverFactory["get"]>[1]=} resolveOptions options
  1254. * @returns {ReturnType<ResolverFactory["get"]>} the resolver
  1255. */
  1256. getResolver(type, resolveOptions) {
  1257. return this.resolverFactory.get(type, resolveOptions);
  1258. }
  1259. }
  1260. module.exports = NormalModuleFactory;