NormalModuleFactory.js 47 KB

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