NormalModuleFactory.js 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336
  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. SyncWaterfallHook,
  11. SyncBailHook,
  12. SyncHook,
  13. HookMap
  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<[TODO, 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. this.hooks.afterResolve.callAsync(resolveData, (err, result) => {
  337. if (err) return callback(err);
  338. if (typeof result === "object")
  339. throw new Error(
  340. deprecationChangedHookMessage(
  341. "afterResolve",
  342. this.hooks.afterResolve
  343. )
  344. );
  345. // Ignored
  346. if (result === false) return callback();
  347. const createData = resolveData.createData;
  348. this.hooks.createModule.callAsync(
  349. createData,
  350. resolveData,
  351. (err, createdModule) => {
  352. if (!createdModule) {
  353. if (!resolveData.request) {
  354. return callback(new Error("Empty dependency (no request)"));
  355. }
  356. // TODO webpack 6 make it required and move javascript/wasm/asset properties to own module
  357. createdModule = this.hooks.createModuleClass
  358. .for(
  359. /** @type {ModuleSettings} */
  360. (createData.settings).type
  361. )
  362. .call(createData, resolveData);
  363. if (!createdModule) {
  364. createdModule = /** @type {Module} */ (
  365. new NormalModule(
  366. /** @type {NormalModuleCreateData} */
  367. (createData)
  368. )
  369. );
  370. }
  371. }
  372. createdModule = this.hooks.module.call(
  373. createdModule,
  374. createData,
  375. resolveData
  376. );
  377. return callback(null, createdModule);
  378. }
  379. );
  380. });
  381. });
  382. }
  383. );
  384. this.hooks.resolve.tapAsync(
  385. {
  386. name: "NormalModuleFactory",
  387. stage: 100
  388. },
  389. (data, callback) => {
  390. const {
  391. contextInfo,
  392. context,
  393. dependencies,
  394. dependencyType,
  395. request,
  396. assertions,
  397. resolveOptions,
  398. fileDependencies,
  399. missingDependencies,
  400. contextDependencies
  401. } = data;
  402. const loaderResolver = this.getResolver("loader");
  403. /** @type {ResourceData | undefined} */
  404. let matchResourceData;
  405. /** @type {string} */
  406. let unresolvedResource;
  407. /** @type {ParsedLoaderRequest[]} */
  408. let elements;
  409. let noPreAutoLoaders = false;
  410. let noAutoLoaders = false;
  411. let noPrePostAutoLoaders = false;
  412. const contextScheme = getScheme(context);
  413. /** @type {string | undefined} */
  414. let scheme = getScheme(request);
  415. if (!scheme) {
  416. /** @type {string} */
  417. let requestWithoutMatchResource = request;
  418. const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
  419. if (matchResourceMatch) {
  420. let matchResource = matchResourceMatch[1];
  421. // Check if matchResource starts with ./ or ../
  422. if (matchResource.charCodeAt(0) === 46) {
  423. // 46 is "."
  424. const secondChar = matchResource.charCodeAt(1);
  425. if (
  426. secondChar === 47 || // 47 is "/"
  427. (secondChar === 46 && matchResource.charCodeAt(2) === 47) // "../"
  428. ) {
  429. // Resolve relative path against context
  430. matchResource = join(this.fs, context, matchResource);
  431. }
  432. }
  433. matchResourceData = {
  434. ...cacheParseResource(matchResource),
  435. resource: matchResource
  436. };
  437. requestWithoutMatchResource = request.slice(
  438. matchResourceMatch[0].length
  439. );
  440. }
  441. scheme = getScheme(requestWithoutMatchResource);
  442. if (!scheme && !contextScheme) {
  443. const firstChar = requestWithoutMatchResource.charCodeAt(0);
  444. const secondChar = requestWithoutMatchResource.charCodeAt(1);
  445. noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!"
  446. noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!"
  447. noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!";
  448. const rawElements = requestWithoutMatchResource
  449. .slice(
  450. noPreAutoLoaders || noPrePostAutoLoaders
  451. ? 2
  452. : noAutoLoaders
  453. ? 1
  454. : 0
  455. )
  456. .split(/!+/);
  457. unresolvedResource = /** @type {string} */ (rawElements.pop());
  458. elements = rawElements.map(el => {
  459. const { path, query } = cachedParseResourceWithoutFragment(el);
  460. return {
  461. loader: path,
  462. options: query ? query.slice(1) : undefined
  463. };
  464. });
  465. scheme = getScheme(unresolvedResource);
  466. } else {
  467. unresolvedResource = requestWithoutMatchResource;
  468. elements = EMPTY_ELEMENTS;
  469. }
  470. } else {
  471. unresolvedResource = request;
  472. elements = EMPTY_ELEMENTS;
  473. }
  474. /** @type {ResolveContext} */
  475. const resolveContext = {
  476. fileDependencies,
  477. missingDependencies,
  478. contextDependencies
  479. };
  480. /** @type {ResourceDataWithData} */
  481. let resourceData;
  482. /** @type {undefined | LoaderItem[]} */
  483. let loaders;
  484. const continueCallback = needCalls(2, err => {
  485. if (err) return callback(err);
  486. // translate option idents
  487. try {
  488. for (const item of /** @type {LoaderItem[]} */ (loaders)) {
  489. if (typeof item.options === "string" && item.options[0] === "?") {
  490. const ident = item.options.slice(1);
  491. if (ident === "[[missing ident]]") {
  492. throw new Error(
  493. "No ident is provided by referenced loader. " +
  494. "When using a function for Rule.use in config you need to " +
  495. "provide an 'ident' property for referenced loader options."
  496. );
  497. }
  498. item.options = this.ruleSet.references.get(ident);
  499. if (item.options === undefined) {
  500. throw new Error(
  501. "Invalid ident is provided by referenced loader"
  502. );
  503. }
  504. item.ident = ident;
  505. }
  506. }
  507. } catch (identErr) {
  508. return callback(/** @type {Error} */ (identErr));
  509. }
  510. if (!resourceData) {
  511. // ignored
  512. return callback(null, dependencies[0].createIgnoredModule(context));
  513. }
  514. const userRequest =
  515. (matchResourceData !== undefined
  516. ? `${matchResourceData.resource}!=!`
  517. : "") +
  518. stringifyLoadersAndResource(
  519. /** @type {LoaderItem[]} */ (loaders),
  520. resourceData.resource
  521. );
  522. /** @type {ModuleSettings} */
  523. const settings = {};
  524. const useLoadersPost = [];
  525. const useLoaders = [];
  526. const useLoadersPre = [];
  527. // handle .webpack[] suffix
  528. let resource;
  529. let match;
  530. if (
  531. matchResourceData &&
  532. typeof (resource = matchResourceData.resource) === "string" &&
  533. (match = /\.webpack\[([^\]]+)\]$/.exec(resource))
  534. ) {
  535. settings.type = match[1];
  536. matchResourceData.resource = matchResourceData.resource.slice(
  537. 0,
  538. -settings.type.length - 10
  539. );
  540. } else {
  541. settings.type = JAVASCRIPT_MODULE_TYPE_AUTO;
  542. const resourceDataForRules = matchResourceData || resourceData;
  543. const result = this.ruleSet.exec({
  544. resource: resourceDataForRules.path,
  545. realResource: resourceData.path,
  546. resourceQuery: resourceDataForRules.query,
  547. resourceFragment: resourceDataForRules.fragment,
  548. scheme,
  549. assertions,
  550. mimetype: matchResourceData
  551. ? ""
  552. : resourceData.data.mimetype || "",
  553. dependency: dependencyType,
  554. descriptionData: matchResourceData
  555. ? undefined
  556. : resourceData.data.descriptionFileData,
  557. issuer: contextInfo.issuer,
  558. compiler: contextInfo.compiler,
  559. issuerLayer: contextInfo.issuerLayer || ""
  560. });
  561. for (const r of result) {
  562. // https://github.com/webpack/webpack/issues/16466
  563. // if a request exists PrePostAutoLoaders, should disable modifying Rule.type
  564. if (r.type === "type" && noPrePostAutoLoaders) {
  565. continue;
  566. }
  567. if (r.type === "use") {
  568. if (!noAutoLoaders && !noPrePostAutoLoaders) {
  569. useLoaders.push(r.value);
  570. }
  571. } else if (r.type === "use-post") {
  572. if (!noPrePostAutoLoaders) {
  573. useLoadersPost.push(r.value);
  574. }
  575. } else if (r.type === "use-pre") {
  576. if (!noPreAutoLoaders && !noPrePostAutoLoaders) {
  577. useLoadersPre.push(r.value);
  578. }
  579. } else if (
  580. typeof r.value === "object" &&
  581. r.value !== null &&
  582. typeof settings[
  583. /** @type {keyof ModuleSettings} */ (r.type)
  584. ] === "object" &&
  585. settings[/** @type {keyof ModuleSettings} */ (r.type)] !== null
  586. ) {
  587. const type = /** @type {keyof ModuleSettings} */ (r.type);
  588. /** @type {TODO} */
  589. (settings)[type] = cachedCleverMerge(settings[type], r.value);
  590. } else {
  591. const type = /** @type {keyof ModuleSettings} */ (r.type);
  592. /** @type {TODO} */
  593. (settings)[type] = r.value;
  594. }
  595. }
  596. }
  597. /** @type {undefined | LoaderItem[]} */
  598. let postLoaders;
  599. /** @type {undefined | LoaderItem[]} */
  600. let normalLoaders;
  601. /** @type {undefined | LoaderItem[]} */
  602. let preLoaders;
  603. const continueCallback = needCalls(3, err => {
  604. if (err) {
  605. return callback(err);
  606. }
  607. const allLoaders = /** @type {LoaderItem[]} */ (postLoaders);
  608. if (matchResourceData === undefined) {
  609. for (const loader of /** @type {LoaderItem[]} */ (loaders))
  610. allLoaders.push(loader);
  611. for (const loader of /** @type {LoaderItem[]} */ (normalLoaders))
  612. allLoaders.push(loader);
  613. } else {
  614. for (const loader of /** @type {LoaderItem[]} */ (normalLoaders))
  615. allLoaders.push(loader);
  616. for (const loader of /** @type {LoaderItem[]} */ (loaders))
  617. allLoaders.push(loader);
  618. }
  619. for (const loader of /** @type {LoaderItem[]} */ (preLoaders))
  620. allLoaders.push(loader);
  621. const type = /** @type {string} */ (settings.type);
  622. const resolveOptions = settings.resolve;
  623. const layer = settings.layer;
  624. if (layer !== undefined && !layers) {
  625. return callback(
  626. new Error(
  627. "'Rule.layer' is only allowed when 'experiments.layers' is enabled"
  628. )
  629. );
  630. }
  631. try {
  632. Object.assign(data.createData, {
  633. layer:
  634. layer === undefined ? contextInfo.issuerLayer || null : layer,
  635. request: stringifyLoadersAndResource(
  636. allLoaders,
  637. resourceData.resource
  638. ),
  639. userRequest,
  640. rawRequest: request,
  641. loaders: allLoaders,
  642. resource: resourceData.resource,
  643. context:
  644. resourceData.context || getContext(resourceData.resource),
  645. matchResource: matchResourceData
  646. ? matchResourceData.resource
  647. : undefined,
  648. resourceResolveData: resourceData.data,
  649. settings,
  650. type,
  651. parser: this.getParser(type, settings.parser),
  652. parserOptions: settings.parser,
  653. generator: this.getGenerator(type, settings.generator),
  654. generatorOptions: settings.generator,
  655. resolveOptions
  656. });
  657. } catch (createDataErr) {
  658. return callback(/** @type {Error} */ (createDataErr));
  659. }
  660. callback();
  661. });
  662. this.resolveRequestArray(
  663. contextInfo,
  664. this.context,
  665. useLoadersPost,
  666. loaderResolver,
  667. resolveContext,
  668. (err, result) => {
  669. postLoaders = result;
  670. continueCallback(err);
  671. }
  672. );
  673. this.resolveRequestArray(
  674. contextInfo,
  675. this.context,
  676. useLoaders,
  677. loaderResolver,
  678. resolveContext,
  679. (err, result) => {
  680. normalLoaders = result;
  681. continueCallback(err);
  682. }
  683. );
  684. this.resolveRequestArray(
  685. contextInfo,
  686. this.context,
  687. useLoadersPre,
  688. loaderResolver,
  689. resolveContext,
  690. (err, result) => {
  691. preLoaders = result;
  692. continueCallback(err);
  693. }
  694. );
  695. });
  696. this.resolveRequestArray(
  697. contextInfo,
  698. contextScheme ? this.context : context,
  699. /** @type {LoaderItem[]} */ (elements),
  700. loaderResolver,
  701. resolveContext,
  702. (err, result) => {
  703. if (err) return continueCallback(err);
  704. loaders = result;
  705. continueCallback();
  706. }
  707. );
  708. /**
  709. * @param {string} context context
  710. */
  711. const defaultResolve = context => {
  712. if (/^($|\?)/.test(unresolvedResource)) {
  713. resourceData = {
  714. ...cacheParseResource(unresolvedResource),
  715. resource: unresolvedResource,
  716. data: {}
  717. };
  718. continueCallback();
  719. }
  720. // resource without scheme and with path
  721. else {
  722. const normalResolver = this.getResolver(
  723. "normal",
  724. dependencyType
  725. ? cachedSetProperty(
  726. resolveOptions || EMPTY_RESOLVE_OPTIONS,
  727. "dependencyType",
  728. dependencyType
  729. )
  730. : resolveOptions
  731. );
  732. this.resolveResource(
  733. contextInfo,
  734. context,
  735. unresolvedResource,
  736. normalResolver,
  737. resolveContext,
  738. (err, _resolvedResource, resolvedResourceResolveData) => {
  739. if (err) return continueCallback(err);
  740. if (_resolvedResource !== false) {
  741. const resolvedResource =
  742. /** @type {string} */
  743. (_resolvedResource);
  744. resourceData = {
  745. ...cacheParseResource(resolvedResource),
  746. resource: resolvedResource,
  747. data:
  748. /** @type {ResolveRequest} */
  749. (resolvedResourceResolveData)
  750. };
  751. }
  752. continueCallback();
  753. }
  754. );
  755. }
  756. };
  757. // resource with scheme
  758. if (scheme) {
  759. resourceData = {
  760. resource: unresolvedResource,
  761. data: {},
  762. path: undefined,
  763. query: undefined,
  764. fragment: undefined,
  765. context: undefined
  766. };
  767. this.hooks.resolveForScheme
  768. .for(scheme)
  769. .callAsync(resourceData, data, err => {
  770. if (err) return continueCallback(err);
  771. continueCallback();
  772. });
  773. }
  774. // resource within scheme
  775. else if (contextScheme) {
  776. resourceData = {
  777. resource: unresolvedResource,
  778. data: {},
  779. path: undefined,
  780. query: undefined,
  781. fragment: undefined,
  782. context: undefined
  783. };
  784. this.hooks.resolveInScheme
  785. .for(contextScheme)
  786. .callAsync(resourceData, data, (err, handled) => {
  787. if (err) return continueCallback(err);
  788. if (!handled) return defaultResolve(this.context);
  789. continueCallback();
  790. });
  791. }
  792. // resource without scheme and without path
  793. else defaultResolve(context);
  794. }
  795. );
  796. }
  797. cleanupForCache() {
  798. for (const module of this._restoredUnsafeCacheEntries) {
  799. ChunkGraph.clearChunkGraphForModule(module);
  800. ModuleGraph.clearModuleGraphForModule(module);
  801. module.cleanupForCache();
  802. }
  803. }
  804. /**
  805. * @param {ModuleFactoryCreateData} data data object
  806. * @param {ModuleFactoryCallback} callback callback
  807. * @returns {void}
  808. */
  809. create(data, callback) {
  810. const dependencies = /** @type {ModuleDependency[]} */ (data.dependencies);
  811. const context = data.context || this.context;
  812. const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
  813. const dependency = dependencies[0];
  814. const request = dependency.request;
  815. const assertions = dependency.assertions;
  816. const dependencyType = dependency.category || "";
  817. const contextInfo = data.contextInfo;
  818. const fileDependencies = new LazySet();
  819. const missingDependencies = new LazySet();
  820. const contextDependencies = new LazySet();
  821. /** @type {ResolveData} */
  822. const resolveData = {
  823. contextInfo,
  824. resolveOptions,
  825. context,
  826. request,
  827. assertions,
  828. dependencies,
  829. dependencyType,
  830. fileDependencies,
  831. missingDependencies,
  832. contextDependencies,
  833. createData: {},
  834. cacheable: true
  835. };
  836. this.hooks.beforeResolve.callAsync(resolveData, (err, result) => {
  837. if (err) {
  838. return callback(err, {
  839. fileDependencies,
  840. missingDependencies,
  841. contextDependencies,
  842. cacheable: false
  843. });
  844. }
  845. // Ignored
  846. if (result === false) {
  847. /** @type {ModuleFactoryResult} * */
  848. const factoryResult = {
  849. fileDependencies,
  850. missingDependencies,
  851. contextDependencies,
  852. cacheable: resolveData.cacheable
  853. };
  854. if (resolveData.ignoredModule) {
  855. factoryResult.module = resolveData.ignoredModule;
  856. }
  857. return callback(null, factoryResult);
  858. }
  859. if (typeof result === "object")
  860. throw new Error(
  861. deprecationChangedHookMessage(
  862. "beforeResolve",
  863. this.hooks.beforeResolve
  864. )
  865. );
  866. this.hooks.factorize.callAsync(resolveData, (err, module) => {
  867. if (err) {
  868. return callback(err, {
  869. fileDependencies,
  870. missingDependencies,
  871. contextDependencies,
  872. cacheable: false
  873. });
  874. }
  875. /** @type {ModuleFactoryResult} * */
  876. const factoryResult = {
  877. module,
  878. fileDependencies,
  879. missingDependencies,
  880. contextDependencies,
  881. cacheable: resolveData.cacheable
  882. };
  883. callback(null, factoryResult);
  884. });
  885. });
  886. }
  887. /**
  888. * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
  889. * @param {string} context context
  890. * @param {string} unresolvedResource unresolved resource
  891. * @param {ResolverWithOptions} resolver resolver
  892. * @param {ResolveContext} resolveContext resolver context
  893. * @param {(err: null | Error, res?: string | false, req?: ResolveRequest) => void} callback callback
  894. */
  895. resolveResource(
  896. contextInfo,
  897. context,
  898. unresolvedResource,
  899. resolver,
  900. resolveContext,
  901. callback
  902. ) {
  903. resolver.resolve(
  904. contextInfo,
  905. context,
  906. unresolvedResource,
  907. resolveContext,
  908. (err, resolvedResource, resolvedResourceResolveData) => {
  909. if (err) {
  910. return this._resolveResourceErrorHints(
  911. err,
  912. contextInfo,
  913. context,
  914. unresolvedResource,
  915. resolver,
  916. resolveContext,
  917. (err2, hints) => {
  918. if (err2) {
  919. err.message += `
  920. A fatal error happened during resolving additional hints for this error: ${err2.message}`;
  921. err.stack += `
  922. A fatal error happened during resolving additional hints for this error:
  923. ${err2.stack}`;
  924. return callback(err);
  925. }
  926. if (hints && hints.length > 0) {
  927. err.message += `
  928. ${hints.join("\n\n")}`;
  929. }
  930. // Check if the extension is missing a leading dot (e.g. "js" instead of ".js")
  931. let appendResolveExtensionsHint = false;
  932. const specifiedExtensions = Array.from(
  933. resolver.options.extensions
  934. );
  935. const expectedExtensions = specifiedExtensions.map(extension => {
  936. if (LEADING_DOT_EXTENSION_REGEX.test(extension)) {
  937. appendResolveExtensionsHint = true;
  938. return `.${extension}`;
  939. }
  940. return extension;
  941. });
  942. if (appendResolveExtensionsHint) {
  943. err.message += `\nDid you miss the leading dot in 'resolve.extensions'? Did you mean '${JSON.stringify(
  944. expectedExtensions
  945. )}' instead of '${JSON.stringify(specifiedExtensions)}'?`;
  946. }
  947. callback(err);
  948. }
  949. );
  950. }
  951. callback(err, resolvedResource, resolvedResourceResolveData);
  952. }
  953. );
  954. }
  955. /**
  956. * @param {Error} error error
  957. * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
  958. * @param {string} context context
  959. * @param {string} unresolvedResource unresolved resource
  960. * @param {ResolverWithOptions} resolver resolver
  961. * @param {ResolveContext} resolveContext resolver context
  962. * @param {Callback<string[]>} callback callback
  963. * @private
  964. */
  965. _resolveResourceErrorHints(
  966. error,
  967. contextInfo,
  968. context,
  969. unresolvedResource,
  970. resolver,
  971. resolveContext,
  972. callback
  973. ) {
  974. asyncLib.parallel(
  975. [
  976. callback => {
  977. if (!resolver.options.fullySpecified) return callback();
  978. resolver
  979. .withOptions({
  980. fullySpecified: false
  981. })
  982. .resolve(
  983. contextInfo,
  984. context,
  985. unresolvedResource,
  986. resolveContext,
  987. (err, resolvedResource) => {
  988. if (!err && resolvedResource) {
  989. const resource = parseResource(resolvedResource).path.replace(
  990. /^.*[\\/]/,
  991. ""
  992. );
  993. return callback(
  994. null,
  995. `Did you mean '${resource}'?
  996. BREAKING CHANGE: The request '${unresolvedResource}' failed to resolve only because it was resolved as fully specified
  997. (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"').
  998. The extension in the request is mandatory for it to be fully specified.
  999. Add the extension to the request.`
  1000. );
  1001. }
  1002. callback();
  1003. }
  1004. );
  1005. },
  1006. callback => {
  1007. if (!resolver.options.enforceExtension) return callback();
  1008. resolver
  1009. .withOptions({
  1010. enforceExtension: false,
  1011. extensions: []
  1012. })
  1013. .resolve(
  1014. contextInfo,
  1015. context,
  1016. unresolvedResource,
  1017. resolveContext,
  1018. (err, resolvedResource) => {
  1019. if (!err && resolvedResource) {
  1020. let hint = "";
  1021. const match = /(\.[^.]+)(\?|$)/.exec(unresolvedResource);
  1022. if (match) {
  1023. const fixedRequest = unresolvedResource.replace(
  1024. /(\.[^.]+)(\?|$)/,
  1025. "$2"
  1026. );
  1027. hint = resolver.options.extensions.has(match[1])
  1028. ? `Did you mean '${fixedRequest}'?`
  1029. : `Did you mean '${fixedRequest}'? Also note that '${match[1]}' is not in 'resolve.extensions' yet and need to be added for this to work?`;
  1030. } else {
  1031. hint =
  1032. "Did you mean to omit the extension or to remove 'resolve.enforceExtension'?";
  1033. }
  1034. return callback(
  1035. null,
  1036. `The request '${unresolvedResource}' failed to resolve only because 'resolve.enforceExtension' was specified.
  1037. ${hint}
  1038. Including the extension in the request is no longer possible. Did you mean to enforce including the extension in requests with 'resolve.extensions: []' instead?`
  1039. );
  1040. }
  1041. callback();
  1042. }
  1043. );
  1044. },
  1045. callback => {
  1046. if (
  1047. /^\.\.?\//.test(unresolvedResource) ||
  1048. resolver.options.preferRelative
  1049. ) {
  1050. return callback();
  1051. }
  1052. resolver.resolve(
  1053. contextInfo,
  1054. context,
  1055. `./${unresolvedResource}`,
  1056. resolveContext,
  1057. (err, resolvedResource) => {
  1058. if (err || !resolvedResource) return callback();
  1059. const moduleDirectories = resolver.options.modules
  1060. .map(m => (Array.isArray(m) ? m.join(", ") : m))
  1061. .join(", ");
  1062. callback(
  1063. null,
  1064. `Did you mean './${unresolvedResource}'?
  1065. Requests that should resolve in the current directory need to start with './'.
  1066. Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}).
  1067. 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.`
  1068. );
  1069. }
  1070. );
  1071. }
  1072. ],
  1073. (err, hints) => {
  1074. if (err) return callback(err);
  1075. callback(null, /** @type {string[]} */ (hints).filter(Boolean));
  1076. }
  1077. );
  1078. }
  1079. /**
  1080. * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
  1081. * @param {string} context context
  1082. * @param {LoaderItem[]} array array
  1083. * @param {ResolverWithOptions} resolver resolver
  1084. * @param {ResolveContext} resolveContext resolve context
  1085. * @param {Callback<LoaderItem[]>} callback callback
  1086. * @returns {void} result
  1087. */
  1088. resolveRequestArray(
  1089. contextInfo,
  1090. context,
  1091. array,
  1092. resolver,
  1093. resolveContext,
  1094. callback
  1095. ) {
  1096. // LoaderItem
  1097. if (array.length === 0) return callback(null, array);
  1098. asyncLib.map(
  1099. array,
  1100. (item, callback) => {
  1101. resolver.resolve(
  1102. contextInfo,
  1103. context,
  1104. item.loader,
  1105. resolveContext,
  1106. (err, result, resolveRequest) => {
  1107. if (
  1108. err &&
  1109. /^[^/]*$/.test(item.loader) &&
  1110. !item.loader.endsWith("-loader")
  1111. ) {
  1112. return resolver.resolve(
  1113. contextInfo,
  1114. context,
  1115. `${item.loader}-loader`,
  1116. resolveContext,
  1117. err2 => {
  1118. if (!err2) {
  1119. err.message =
  1120. `${err.message}\n` +
  1121. "BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
  1122. ` You need to specify '${item.loader}-loader' instead of '${item.loader}',\n` +
  1123. " see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed";
  1124. }
  1125. callback(err);
  1126. }
  1127. );
  1128. }
  1129. if (err) return callback(err);
  1130. const parsedResult = this._parseResourceWithoutFragment(
  1131. /** @type {string} */ (result)
  1132. );
  1133. const type = /\.mjs$/i.test(parsedResult.path)
  1134. ? "module"
  1135. : /\.cjs$/i.test(parsedResult.path)
  1136. ? "commonjs"
  1137. : /** @type {ResolveRequest} */
  1138. (resolveRequest).descriptionFileData === undefined
  1139. ? undefined
  1140. : /** @type {ResolveRequest} */
  1141. (resolveRequest).descriptionFileData.type;
  1142. const resolved = {
  1143. loader: parsedResult.path,
  1144. type,
  1145. options:
  1146. item.options === undefined
  1147. ? parsedResult.query
  1148. ? parsedResult.query.slice(1)
  1149. : undefined
  1150. : item.options,
  1151. ident:
  1152. item.options === undefined
  1153. ? undefined
  1154. : /** @type {string} */ (item.ident)
  1155. };
  1156. return callback(null, /** @type {LoaderItem} */ (resolved));
  1157. }
  1158. );
  1159. },
  1160. /** @type {Callback<(LoaderItem | undefined)[]>} */ (callback)
  1161. );
  1162. }
  1163. /**
  1164. * @param {string} type type
  1165. * @param {ParserOptions} parserOptions parser options
  1166. * @returns {Parser} parser
  1167. */
  1168. getParser(type, parserOptions = EMPTY_PARSER_OPTIONS) {
  1169. let cache = this.parserCache.get(type);
  1170. if (cache === undefined) {
  1171. cache = new WeakMap();
  1172. this.parserCache.set(type, cache);
  1173. }
  1174. let parser = cache.get(parserOptions);
  1175. if (parser === undefined) {
  1176. parser = this.createParser(type, parserOptions);
  1177. cache.set(parserOptions, parser);
  1178. }
  1179. return parser;
  1180. }
  1181. /**
  1182. * @param {string} type type
  1183. * @param {ParserOptions} parserOptions parser options
  1184. * @returns {Parser} parser
  1185. */
  1186. createParser(type, parserOptions = {}) {
  1187. parserOptions = mergeGlobalOptions(
  1188. this._globalParserOptions,
  1189. type,
  1190. parserOptions
  1191. );
  1192. const parser = this.hooks.createParser.for(type).call(parserOptions);
  1193. if (!parser) {
  1194. throw new Error(`No parser registered for ${type}`);
  1195. }
  1196. this.hooks.parser.for(type).call(parser, parserOptions);
  1197. return parser;
  1198. }
  1199. /**
  1200. * @param {string} type type of generator
  1201. * @param {GeneratorOptions} generatorOptions generator options
  1202. * @returns {Generator} generator
  1203. */
  1204. getGenerator(type, generatorOptions = EMPTY_GENERATOR_OPTIONS) {
  1205. let cache = this.generatorCache.get(type);
  1206. if (cache === undefined) {
  1207. cache = new WeakMap();
  1208. this.generatorCache.set(type, cache);
  1209. }
  1210. let generator = cache.get(generatorOptions);
  1211. if (generator === undefined) {
  1212. generator = this.createGenerator(type, generatorOptions);
  1213. cache.set(generatorOptions, generator);
  1214. }
  1215. return generator;
  1216. }
  1217. /**
  1218. * @param {string} type type of generator
  1219. * @param {GeneratorOptions} generatorOptions generator options
  1220. * @returns {Generator} generator
  1221. */
  1222. createGenerator(type, generatorOptions = {}) {
  1223. generatorOptions = mergeGlobalOptions(
  1224. this._globalGeneratorOptions,
  1225. type,
  1226. generatorOptions
  1227. );
  1228. const generator = this.hooks.createGenerator
  1229. .for(type)
  1230. .call(generatorOptions);
  1231. if (!generator) {
  1232. throw new Error(`No generator registered for ${type}`);
  1233. }
  1234. this.hooks.generator.for(type).call(generator, generatorOptions);
  1235. return generator;
  1236. }
  1237. /**
  1238. * @param {Parameters<ResolverFactory["get"]>[0]} type type of resolver
  1239. * @param {Parameters<ResolverFactory["get"]>[1]=} resolveOptions options
  1240. * @returns {ReturnType<ResolverFactory["get"]>} the resolver
  1241. */
  1242. getResolver(type, resolveOptions) {
  1243. return this.resolverFactory.get(type, resolveOptions);
  1244. }
  1245. }
  1246. module.exports = NormalModuleFactory;