ContextModule.js 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { OriginalSource, RawSource } = require("webpack-sources");
  7. const AsyncDependenciesBlock = require("./AsyncDependenciesBlock");
  8. const { makeWebpackError } = require("./HookWebpackError");
  9. const Module = require("./Module");
  10. const {
  11. JAVASCRIPT_TYPE,
  12. JAVASCRIPT_TYPES
  13. } = require("./ModuleSourceTypeConstants");
  14. const { JAVASCRIPT_MODULE_TYPE_DYNAMIC } = require("./ModuleTypeConstants");
  15. const RuntimeGlobals = require("./RuntimeGlobals");
  16. const Template = require("./Template");
  17. const WebpackError = require("./WebpackError");
  18. const {
  19. getOutgoingAsyncModules
  20. } = require("./async-modules/AsyncModuleHelpers");
  21. const { ImportPhase, ImportPhaseUtils } = require("./dependencies/ImportPhase");
  22. const {
  23. compareLocations,
  24. compareModulesById,
  25. compareSelect,
  26. concatComparators,
  27. keepOriginalOrder
  28. } = require("./util/comparators");
  29. const {
  30. contextify,
  31. makePathsRelative,
  32. parseResource
  33. } = require("./util/identifier");
  34. const makeSerializable = require("./util/makeSerializable");
  35. /** @typedef {import("webpack-sources").Source} Source */
  36. /** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
  37. /** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
  38. /** @typedef {import("./Chunk")} Chunk */
  39. /** @typedef {import("./Chunk").ChunkId} ChunkId */
  40. /** @typedef {import("./Chunk").ChunkName} ChunkName */
  41. /** @typedef {import("./ChunkGraph")} ChunkGraph */
  42. /** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
  43. /** @typedef {import("./ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */
  44. /** @typedef {import("./Compilation")} Compilation */
  45. /** @typedef {import("./Dependency")} Dependency */
  46. /** @typedef {import("./Dependency").RawReferencedExports} RawReferencedExports */
  47. /** @typedef {import("./Generator").SourceTypes} SourceTypes */
  48. /** @typedef {import("./Module").BuildCallback} BuildCallback */
  49. /** @typedef {import("./Module").BuildInfo} BuildInfo */
  50. /** @typedef {import("./Module").FileSystemDependencies} FileSystemDependencies */
  51. /** @typedef {import("./Module").BuildMeta} BuildMeta */
  52. /** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
  53. /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
  54. /** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
  55. /** @typedef {import("./Module").LibIdent} LibIdent */
  56. /** @typedef {import("./Module").NeedBuildCallback} NeedBuildCallback */
  57. /** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
  58. /** @typedef {import("./Module").RuntimeRequirements} RuntimeRequirements */
  59. /** @typedef {import("./Module").Sources} Sources */
  60. /** @typedef {import("./RequestShortener")} RequestShortener */
  61. /** @typedef {import("./ResolverFactory").ResolverWithOptions} ResolverWithOptions */
  62. /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
  63. /** @typedef {import("./dependencies/ContextElementDependency")} ContextElementDependency */
  64. /** @typedef {import("./javascript/JavascriptParser").ImportAttributes} ImportAttributes */
  65. /** @typedef {import("./serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  66. /** @typedef {import("./serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
  67. /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
  68. /** @typedef {import("./dependencies/ImportPhase").ImportPhaseType} ImportPhaseType */
  69. /** @typedef {"sync" | "eager" | "weak" | "async-weak" | "lazy" | "lazy-once"} ContextMode Context mode */
  70. /**
  71. * @typedef {object} ContextOptions
  72. * @property {ContextMode} mode
  73. * @property {boolean} recursive
  74. * @property {RegExp | false | null} regExp
  75. * @property {"strict" | boolean=} namespaceObject
  76. * @property {string=} addon
  77. * @property {ChunkName=} chunkName
  78. * @property {RegExp | null=} include
  79. * @property {RegExp | null=} exclude
  80. * @property {RawChunkGroupOptions=} groupOptions
  81. * @property {string=} typePrefix
  82. * @property {string=} category
  83. * @property {RawReferencedExports | null=} referencedExports exports referenced from modules (won't be mangled)
  84. * @property {string | null=} layer
  85. * @property {ImportAttributes=} attributes
  86. * @property {ImportPhaseType=} phase
  87. */
  88. /**
  89. * @typedef {object} ContextModuleOptionsExtras
  90. * @property {false | string | string[]} resource
  91. * @property {string=} resourceQuery
  92. * @property {string=} resourceFragment
  93. * @property {ResolveOptions=} resolveOptions
  94. */
  95. /** @typedef {ContextOptions & ContextModuleOptionsExtras} ContextModuleOptions */
  96. /**
  97. * @callback ResolveDependenciesCallback
  98. * @param {Error | null} err
  99. * @param {ContextElementDependency[]=} dependencies
  100. * @returns {void}
  101. */
  102. /**
  103. * @callback ResolveDependencies
  104. * @param {InputFileSystem} fs
  105. * @param {ContextModuleOptions} options
  106. * @param {ResolveDependenciesCallback} callback
  107. */
  108. /** @typedef {1 | 3 | 7 | 9} FakeMapType */
  109. /** @typedef {Record<ModuleId, FakeMapType>} FakeMap */
  110. /** @typedef {Record<string, ModuleId>} UserRequestMap */
  111. /** @typedef {Record<ModuleId, ModuleId[]>} UserRequestsMap */
  112. class ContextModule extends Module {
  113. /**
  114. * @param {ResolveDependencies} resolveDependencies function to get dependencies in this context
  115. * @param {ContextModuleOptions} options options object
  116. */
  117. constructor(resolveDependencies, options) {
  118. if (!options || typeof options.resource === "string") {
  119. const parsed = parseResource(
  120. options ? /** @type {string} */ (options.resource) : ""
  121. );
  122. const resource = parsed.path;
  123. const resourceQuery = (options && options.resourceQuery) || parsed.query;
  124. const resourceFragment =
  125. (options && options.resourceFragment) || parsed.fragment;
  126. const layer = options && options.layer;
  127. super(JAVASCRIPT_MODULE_TYPE_DYNAMIC, resource, layer);
  128. /** @type {ContextModuleOptions} */
  129. this.options = {
  130. ...options,
  131. resource,
  132. resourceQuery,
  133. resourceFragment
  134. };
  135. } else {
  136. super(JAVASCRIPT_MODULE_TYPE_DYNAMIC, undefined, options.layer);
  137. /** @type {ContextModuleOptions} */
  138. this.options = {
  139. ...options,
  140. resource: options.resource,
  141. resourceQuery: options.resourceQuery || "",
  142. resourceFragment: options.resourceFragment || ""
  143. };
  144. }
  145. // Info from Factory
  146. /** @type {ResolveDependencies | undefined} */
  147. this.resolveDependencies = resolveDependencies;
  148. if (options && options.resolveOptions !== undefined) {
  149. this.resolveOptions = options.resolveOptions;
  150. }
  151. if (options && typeof options.mode !== "string") {
  152. throw new Error("options.mode is a required option");
  153. }
  154. this._identifier = this._createIdentifier();
  155. this._forceBuild = true;
  156. }
  157. /**
  158. * @returns {SourceTypes} types available (do not mutate)
  159. */
  160. getSourceTypes() {
  161. return JAVASCRIPT_TYPES;
  162. }
  163. /**
  164. * Assuming this module is in the cache. Update the (cached) module with
  165. * the fresh module from the factory. Usually updates internal references
  166. * and properties.
  167. * @param {Module} module fresh module
  168. * @returns {void}
  169. */
  170. updateCacheModule(module) {
  171. const m = /** @type {ContextModule} */ (module);
  172. this.resolveDependencies = m.resolveDependencies;
  173. this.options = m.options;
  174. }
  175. /**
  176. * Assuming this module is in the cache. Remove internal references to allow freeing some memory.
  177. */
  178. cleanupForCache() {
  179. super.cleanupForCache();
  180. this.resolveDependencies = undefined;
  181. }
  182. /**
  183. * @private
  184. * @param {RegExp} regexString RegExp as a string
  185. * @param {boolean=} stripSlash do we need to strip a slsh
  186. * @returns {string} pretty RegExp
  187. */
  188. _prettyRegExp(regexString, stripSlash = true) {
  189. const str = stripSlash
  190. ? regexString.source + regexString.flags
  191. : `${regexString}`;
  192. return str.replace(/!/g, "%21").replace(/\|/g, "%7C");
  193. }
  194. _createIdentifier() {
  195. let identifier =
  196. this.context ||
  197. (typeof this.options.resource === "string" ||
  198. this.options.resource === false
  199. ? `${this.options.resource}`
  200. : this.options.resource.join("|"));
  201. if (this.options.resourceQuery) {
  202. identifier += `|${this.options.resourceQuery}`;
  203. }
  204. if (this.options.resourceFragment) {
  205. identifier += `|${this.options.resourceFragment}`;
  206. }
  207. if (this.options.mode) {
  208. identifier += `|${this.options.mode}`;
  209. }
  210. if (!this.options.recursive) {
  211. identifier += "|nonrecursive";
  212. }
  213. if (this.options.addon) {
  214. identifier += `|${this.options.addon}`;
  215. }
  216. if (this.options.regExp) {
  217. identifier += `|${this._prettyRegExp(this.options.regExp, false)}`;
  218. }
  219. if (this.options.include) {
  220. identifier += `|include: ${this._prettyRegExp(
  221. this.options.include,
  222. false
  223. )}`;
  224. }
  225. if (this.options.exclude) {
  226. identifier += `|exclude: ${this._prettyRegExp(
  227. this.options.exclude,
  228. false
  229. )}`;
  230. }
  231. if (this.options.referencedExports) {
  232. identifier += `|referencedExports: ${JSON.stringify(
  233. this.options.referencedExports
  234. )}`;
  235. }
  236. if (this.options.chunkName) {
  237. identifier += `|chunkName: ${this.options.chunkName}`;
  238. }
  239. if (this.options.groupOptions) {
  240. identifier += `|groupOptions: ${JSON.stringify(
  241. this.options.groupOptions
  242. )}`;
  243. }
  244. if (this.options.namespaceObject === "strict") {
  245. identifier += "|strict namespace object";
  246. } else if (this.options.namespaceObject) {
  247. identifier += "|namespace object";
  248. }
  249. if (this.options.attributes) {
  250. identifier += `|importAttributes: ${JSON.stringify(this.options.attributes)}`;
  251. }
  252. if (this.options.phase) {
  253. identifier += `|importPhase: ${this.options.phase}`;
  254. }
  255. if (this.layer) {
  256. identifier += `|layer: ${this.layer}`;
  257. }
  258. return identifier;
  259. }
  260. /**
  261. * @returns {string} a unique identifier of the module
  262. */
  263. identifier() {
  264. return this._identifier;
  265. }
  266. /**
  267. * @param {RequestShortener} requestShortener the request shortener
  268. * @returns {string} a user readable identifier of the module
  269. */
  270. readableIdentifier(requestShortener) {
  271. /** @type {string} */
  272. let identifier;
  273. if (this.context) {
  274. identifier = `${requestShortener.shorten(this.context)}/`;
  275. } else if (
  276. typeof this.options.resource === "string" ||
  277. this.options.resource === false
  278. ) {
  279. identifier = `${requestShortener.shorten(`${this.options.resource}`)}/`;
  280. } else {
  281. identifier = this.options.resource
  282. .map((r) => `${requestShortener.shorten(r)}/`)
  283. .join(" ");
  284. }
  285. if (this.options.resourceQuery) {
  286. identifier += ` ${this.options.resourceQuery}`;
  287. }
  288. if (this.options.mode) {
  289. identifier += ` ${this.options.mode}`;
  290. }
  291. if (!this.options.recursive) {
  292. identifier += " nonrecursive";
  293. }
  294. if (this.options.addon) {
  295. identifier += ` ${requestShortener.shorten(this.options.addon)}`;
  296. }
  297. if (this.options.regExp) {
  298. identifier += ` ${this._prettyRegExp(this.options.regExp)}`;
  299. }
  300. if (this.options.include) {
  301. identifier += ` include: ${this._prettyRegExp(this.options.include)}`;
  302. }
  303. if (this.options.exclude) {
  304. identifier += ` exclude: ${this._prettyRegExp(this.options.exclude)}`;
  305. }
  306. if (this.options.referencedExports) {
  307. identifier += ` referencedExports: ${this.options.referencedExports
  308. .map((e) => e.join("."))
  309. .join(", ")}`;
  310. }
  311. if (this.options.chunkName) {
  312. identifier += ` chunkName: ${this.options.chunkName}`;
  313. }
  314. if (this.options.groupOptions) {
  315. const groupOptions = this.options.groupOptions;
  316. for (const key of Object.keys(groupOptions)) {
  317. identifier += ` ${key}: ${
  318. groupOptions[/** @type {keyof RawChunkGroupOptions} */ (key)]
  319. }`;
  320. }
  321. }
  322. if (this.options.namespaceObject === "strict") {
  323. identifier += " strict namespace object";
  324. } else if (this.options.namespaceObject) {
  325. identifier += " namespace object";
  326. }
  327. return identifier;
  328. }
  329. /**
  330. * @param {LibIdentOptions} options options
  331. * @returns {LibIdent | null} an identifier for library inclusion
  332. */
  333. libIdent(options) {
  334. /** @type {string} */
  335. let identifier;
  336. if (this.context) {
  337. identifier = contextify(
  338. options.context,
  339. this.context,
  340. options.associatedObjectForCache
  341. );
  342. } else if (typeof this.options.resource === "string") {
  343. identifier = contextify(
  344. options.context,
  345. this.options.resource,
  346. options.associatedObjectForCache
  347. );
  348. } else if (this.options.resource === false) {
  349. identifier = "false";
  350. } else {
  351. identifier = this.options.resource
  352. .map((res) =>
  353. contextify(options.context, res, options.associatedObjectForCache)
  354. )
  355. .join(" ");
  356. }
  357. if (this.layer) identifier = `(${this.layer})/${identifier}`;
  358. if (this.options.mode) {
  359. identifier += ` ${this.options.mode}`;
  360. }
  361. if (this.options.recursive) {
  362. identifier += " recursive";
  363. }
  364. if (this.options.addon) {
  365. identifier += ` ${contextify(
  366. options.context,
  367. this.options.addon,
  368. options.associatedObjectForCache
  369. )}`;
  370. }
  371. if (this.options.regExp) {
  372. identifier += ` ${this._prettyRegExp(this.options.regExp)}`;
  373. }
  374. if (this.options.include) {
  375. identifier += ` include: ${this._prettyRegExp(this.options.include)}`;
  376. }
  377. if (this.options.exclude) {
  378. identifier += ` exclude: ${this._prettyRegExp(this.options.exclude)}`;
  379. }
  380. if (this.options.referencedExports) {
  381. identifier += ` referencedExports: ${this.options.referencedExports
  382. .map((e) => e.join("."))
  383. .join(", ")}`;
  384. }
  385. return identifier;
  386. }
  387. /**
  388. * @returns {void}
  389. */
  390. invalidateBuild() {
  391. this._forceBuild = true;
  392. }
  393. /**
  394. * @param {NeedBuildContext} context context info
  395. * @param {NeedBuildCallback} callback callback function, returns true, if the module needs a rebuild
  396. * @returns {void}
  397. */
  398. needBuild({ fileSystemInfo }, callback) {
  399. // build if enforced
  400. if (this._forceBuild) return callback(null, true);
  401. const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
  402. // always build when we have no snapshot and context
  403. if (!buildInfo.snapshot) {
  404. return callback(null, Boolean(this.context || this.options.resource));
  405. }
  406. fileSystemInfo.checkSnapshotValid(buildInfo.snapshot, (err, valid) => {
  407. callback(err, !valid);
  408. });
  409. }
  410. /**
  411. * @param {WebpackOptions} options webpack options
  412. * @param {Compilation} compilation the compilation
  413. * @param {ResolverWithOptions} resolver the resolver
  414. * @param {InputFileSystem} fs the file system
  415. * @param {BuildCallback} callback callback function
  416. * @returns {void}
  417. */
  418. build(options, compilation, resolver, fs, callback) {
  419. this._forceBuild = false;
  420. /** @type {BuildMeta} */
  421. this.buildMeta = {
  422. exportsType: "default",
  423. defaultObject: "redirect-warn"
  424. };
  425. this.buildInfo = {
  426. snapshot: undefined
  427. };
  428. this.dependencies.length = 0;
  429. this.blocks.length = 0;
  430. const startTime = Date.now();
  431. /** @type {ResolveDependencies} */
  432. (this.resolveDependencies)(fs, this.options, (err, dependencies) => {
  433. if (err) {
  434. return callback(
  435. makeWebpackError(err, "ContextModule.resolveDependencies")
  436. );
  437. }
  438. // abort if something failed
  439. // this will create an empty context
  440. if (!dependencies) {
  441. callback();
  442. return;
  443. }
  444. // enhance dependencies with meta info
  445. for (const dep of dependencies) {
  446. dep.loc = {
  447. name: dep.userRequest
  448. };
  449. dep.request = this.options.addon + dep.request;
  450. }
  451. dependencies.sort(
  452. concatComparators(
  453. compareSelect((a) => a.loc, compareLocations),
  454. keepOriginalOrder(this.dependencies)
  455. )
  456. );
  457. if (this.options.mode === "sync" || this.options.mode === "eager") {
  458. // if we have an sync or eager context
  459. // just add all dependencies and continue
  460. this.dependencies = dependencies;
  461. } else if (this.options.mode === "lazy-once") {
  462. // for the lazy-once mode create a new async dependency block
  463. // and add that block to this context
  464. if (dependencies.length > 0) {
  465. const block = new AsyncDependenciesBlock({
  466. ...this.options.groupOptions,
  467. name: this.options.chunkName
  468. });
  469. for (const dep of dependencies) {
  470. block.addDependency(dep);
  471. }
  472. this.addBlock(block);
  473. }
  474. } else if (
  475. this.options.mode === "weak" ||
  476. this.options.mode === "async-weak"
  477. ) {
  478. // we mark all dependencies as weak
  479. for (const dep of dependencies) {
  480. dep.weak = true;
  481. }
  482. this.dependencies = dependencies;
  483. } else if (this.options.mode === "lazy") {
  484. // if we are lazy create a new async dependency block per dependency
  485. // and add all blocks to this context
  486. let index = 0;
  487. for (const dep of dependencies) {
  488. let chunkName = this.options.chunkName;
  489. if (chunkName) {
  490. if (!/\[(?:index|request)\]/.test(chunkName)) {
  491. chunkName += "[index]";
  492. }
  493. chunkName = chunkName.replace(/\[index\]/g, `${index++}`);
  494. chunkName = chunkName.replace(
  495. /\[request\]/g,
  496. Template.toPath(dep.userRequest)
  497. );
  498. }
  499. const block = new AsyncDependenciesBlock(
  500. {
  501. ...this.options.groupOptions,
  502. name: chunkName
  503. },
  504. dep.loc,
  505. dep.userRequest
  506. );
  507. block.addDependency(dep);
  508. this.addBlock(block);
  509. }
  510. } else {
  511. callback(
  512. new WebpackError(`Unsupported mode "${this.options.mode}" in context`)
  513. );
  514. return;
  515. }
  516. if (!this.context && !this.options.resource) return callback();
  517. const snapshotOptions = compilation.options.snapshot.contextModule;
  518. compilation.fileSystemInfo.createSnapshot(
  519. startTime,
  520. null,
  521. this.context
  522. ? [this.context]
  523. : typeof this.options.resource === "string"
  524. ? [this.options.resource]
  525. : /** @type {string[]} */ (this.options.resource),
  526. null,
  527. snapshotOptions,
  528. (err, snapshot) => {
  529. if (err) return callback(err);
  530. /** @type {BuildInfo} */
  531. (this.buildInfo).snapshot = snapshot;
  532. callback();
  533. }
  534. );
  535. });
  536. }
  537. /**
  538. * @param {FileSystemDependencies} fileDependencies set where file dependencies are added to
  539. * @param {FileSystemDependencies} contextDependencies set where context dependencies are added to
  540. * @param {FileSystemDependencies} missingDependencies set where missing dependencies are added to
  541. * @param {FileSystemDependencies} buildDependencies set where build dependencies are added to
  542. */
  543. addCacheDependencies(
  544. fileDependencies,
  545. contextDependencies,
  546. missingDependencies,
  547. buildDependencies
  548. ) {
  549. if (this.context) {
  550. contextDependencies.add(this.context);
  551. } else if (typeof this.options.resource === "string") {
  552. contextDependencies.add(this.options.resource);
  553. } else if (this.options.resource === false) {
  554. // Do nothing
  555. } else {
  556. for (const res of this.options.resource) contextDependencies.add(res);
  557. }
  558. }
  559. /**
  560. * @param {Dependency[]} dependencies all dependencies
  561. * @param {ChunkGraph} chunkGraph chunk graph
  562. * @returns {UserRequestMap} map with user requests
  563. */
  564. getUserRequestMap(dependencies, chunkGraph) {
  565. const moduleGraph = chunkGraph.moduleGraph;
  566. // if we filter first we get a new array
  567. // therefore we don't need to create a clone of dependencies explicitly
  568. // therefore the order of this is !important!
  569. const sortedDependencies =
  570. /** @type {ContextElementDependency[]} */
  571. (dependencies)
  572. .filter((dependency) => moduleGraph.getModule(dependency))
  573. .sort((a, b) => {
  574. if (a.userRequest === b.userRequest) {
  575. return 0;
  576. }
  577. return a.userRequest < b.userRequest ? -1 : 1;
  578. });
  579. /** @type {UserRequestMap} */
  580. const map = Object.create(null);
  581. for (const dep of sortedDependencies) {
  582. const module = /** @type {Module} */ (moduleGraph.getModule(dep));
  583. map[dep.userRequest] =
  584. /** @type {ModuleId} */
  585. (chunkGraph.getModuleId(module));
  586. }
  587. return map;
  588. }
  589. /**
  590. * @param {Dependency[]} dependencies all dependencies
  591. * @param {ChunkGraph} chunkGraph chunk graph
  592. * @returns {FakeMap | FakeMapType} fake map
  593. */
  594. getFakeMap(dependencies, chunkGraph) {
  595. if (!this.options.namespaceObject) {
  596. return 9;
  597. }
  598. const moduleGraph = chunkGraph.moduleGraph;
  599. // bitfield
  600. let hasType = 0;
  601. const comparator = compareModulesById(chunkGraph);
  602. // if we filter first we get a new array
  603. // therefore we don't need to create a clone of dependencies explicitly
  604. // therefore the order of this is !important!
  605. const sortedModules = dependencies
  606. .map(
  607. (dependency) =>
  608. /** @type {Module} */ (moduleGraph.getModule(dependency))
  609. )
  610. .filter(Boolean)
  611. .sort(comparator);
  612. /** @type {FakeMap} */
  613. const fakeMap = Object.create(null);
  614. for (const module of sortedModules) {
  615. const exportsType = module.getExportsType(
  616. moduleGraph,
  617. this.options.namespaceObject === "strict"
  618. );
  619. const id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
  620. switch (exportsType) {
  621. case "namespace":
  622. fakeMap[id] = 9;
  623. hasType |= 1;
  624. break;
  625. case "dynamic":
  626. fakeMap[id] = 7;
  627. hasType |= 2;
  628. break;
  629. case "default-only":
  630. fakeMap[id] = 1;
  631. hasType |= 4;
  632. break;
  633. case "default-with-named":
  634. fakeMap[id] = 3;
  635. hasType |= 8;
  636. break;
  637. default:
  638. throw new Error(`Unexpected exports type ${exportsType}`);
  639. }
  640. }
  641. if (hasType === 1) {
  642. return 9;
  643. }
  644. if (hasType === 2) {
  645. return 7;
  646. }
  647. if (hasType === 4) {
  648. return 1;
  649. }
  650. if (hasType === 8) {
  651. return 3;
  652. }
  653. if (hasType === 0) {
  654. return 9;
  655. }
  656. return fakeMap;
  657. }
  658. /**
  659. * @param {FakeMap | FakeMapType} fakeMap fake map
  660. * @returns {string} fake map init statement
  661. */
  662. getFakeMapInitStatement(fakeMap) {
  663. return typeof fakeMap === "object"
  664. ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};`
  665. : "";
  666. }
  667. /**
  668. * @param {Dependency[]} dependencies all dependencies
  669. * @param {ChunkGraph} chunkGraph chunk graph
  670. * @returns {UserRequestsMap} map with user requests
  671. */
  672. getModuleDeferredAsyncDepsMap(dependencies, chunkGraph) {
  673. const moduleGraph = chunkGraph.moduleGraph;
  674. const comparator = compareModulesById(chunkGraph);
  675. // if we filter first we get a new array
  676. // therefore we don't need to create a clone of dependencies explicitly
  677. // therefore the order of this is !important!
  678. const sortedModules = dependencies
  679. .map(
  680. (dependency) =>
  681. /** @type {Module} */ (moduleGraph.getModule(dependency))
  682. )
  683. .filter(Boolean)
  684. .sort(comparator);
  685. /** @type {UserRequestsMap} */
  686. const map = Object.create(null);
  687. for (const module of sortedModules) {
  688. if (!(/** @type {BuildMeta} */ (module.buildMeta).async)) {
  689. const id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
  690. map[id] = Array.from(
  691. getOutgoingAsyncModules(chunkGraph.moduleGraph, module),
  692. (m) => chunkGraph.getModuleId(m)
  693. ).filter((id) => id !== null);
  694. }
  695. }
  696. return map;
  697. }
  698. /**
  699. * @param {false | UserRequestsMap} asyncDepsMap fake map
  700. * @returns {string} async deps map init statement
  701. */
  702. getModuleDeferredAsyncDepsMapInitStatement(asyncDepsMap) {
  703. return typeof asyncDepsMap === "object"
  704. ? `var asyncDepsMap = ${JSON.stringify(asyncDepsMap, null, "\t")};`
  705. : "";
  706. }
  707. /**
  708. * @param {FakeMapType} type type
  709. * @param {boolean=} asyncModule is async module
  710. * @returns {string} return result
  711. */
  712. getReturn(type, asyncModule) {
  713. if (type === 9) {
  714. return `${RuntimeGlobals.require}(id)`;
  715. }
  716. return `${RuntimeGlobals.createFakeNamespaceObject}(id, ${type}${
  717. asyncModule ? " | 16" : ""
  718. })`;
  719. }
  720. /**
  721. * @param {FakeMap | FakeMapType} fakeMap fake map
  722. * @param {boolean=} asyncModule is async module
  723. * @param {string=} asyncDeps async deps for deferred module
  724. * @param {string=} fakeMapDataExpression fake map data expression
  725. * @returns {string} module object source
  726. */
  727. getReturnModuleObjectSource(
  728. fakeMap,
  729. asyncModule,
  730. asyncDeps,
  731. fakeMapDataExpression = "fakeMap[id]"
  732. ) {
  733. const source =
  734. typeof fakeMap === "number"
  735. ? this.getReturn(fakeMap, asyncModule)
  736. : `${RuntimeGlobals.createFakeNamespaceObject}(id, ${fakeMapDataExpression}${asyncModule ? " | 16" : ""})`;
  737. if (asyncDeps) {
  738. if (!asyncModule) {
  739. throw new Error("Must be async when module is deferred");
  740. }
  741. const type =
  742. typeof fakeMap === "number" ? fakeMap : fakeMapDataExpression;
  743. return `${asyncDeps} ? ${asyncDeps}.length ? ${RuntimeGlobals.deferredModuleAsyncTransitiveDependencies}(${asyncDeps}).then(${RuntimeGlobals.makeDeferredNamespaceObject}.bind(${RuntimeGlobals.require}, id, ${type} ^ 1, true)) : ${RuntimeGlobals.makeDeferredNamespaceObject}(id, ${type} ^ 1 | 16) : ${source}`;
  744. }
  745. return source;
  746. }
  747. /**
  748. * @param {Dependency[]} dependencies dependencies
  749. * @param {ModuleId} id module id
  750. * @param {ChunkGraph} chunkGraph the chunk graph
  751. * @returns {string} source code
  752. */
  753. getSyncSource(dependencies, id, chunkGraph) {
  754. const map = this.getUserRequestMap(dependencies, chunkGraph);
  755. const fakeMap = this.getFakeMap(dependencies, chunkGraph);
  756. const returnModuleObject = this.getReturnModuleObjectSource(fakeMap);
  757. return `var map = ${JSON.stringify(map, null, "\t")};
  758. ${this.getFakeMapInitStatement(fakeMap)}
  759. function webpackContext(req) {
  760. var id = webpackContextResolve(req);
  761. return ${returnModuleObject};
  762. }
  763. function webpackContextResolve(req) {
  764. if(!${RuntimeGlobals.hasOwnProperty}(map, req)) {
  765. var e = new Error("Cannot find module '" + req + "'");
  766. e.code = 'MODULE_NOT_FOUND';
  767. throw e;
  768. }
  769. return map[req];
  770. }
  771. webpackContext.keys = function webpackContextKeys() {
  772. return Object.keys(map);
  773. };
  774. webpackContext.resolve = webpackContextResolve;
  775. module.exports = webpackContext;
  776. webpackContext.id = ${JSON.stringify(id)};`;
  777. }
  778. /**
  779. * @param {Dependency[]} dependencies dependencies
  780. * @param {ModuleId} id module id
  781. * @param {ChunkGraph} chunkGraph the chunk graph
  782. * @returns {string} source code
  783. */
  784. getWeakSyncSource(dependencies, id, chunkGraph) {
  785. const map = this.getUserRequestMap(dependencies, chunkGraph);
  786. const fakeMap = this.getFakeMap(dependencies, chunkGraph);
  787. const returnModuleObject = this.getReturnModuleObjectSource(fakeMap);
  788. return `var map = ${JSON.stringify(map, null, "\t")};
  789. ${this.getFakeMapInitStatement(fakeMap)}
  790. function webpackContext(req) {
  791. var id = webpackContextResolve(req);
  792. if(!${RuntimeGlobals.moduleFactories}[id]) {
  793. var e = new Error("Module '" + req + "' ('" + id + "') is not available (weak dependency)");
  794. e.code = 'MODULE_NOT_FOUND';
  795. throw e;
  796. }
  797. return ${returnModuleObject};
  798. }
  799. function webpackContextResolve(req) {
  800. if(!${RuntimeGlobals.hasOwnProperty}(map, req)) {
  801. var e = new Error("Cannot find module '" + req + "'");
  802. e.code = 'MODULE_NOT_FOUND';
  803. throw e;
  804. }
  805. return map[req];
  806. }
  807. webpackContext.keys = function webpackContextKeys() {
  808. return Object.keys(map);
  809. };
  810. webpackContext.resolve = webpackContextResolve;
  811. webpackContext.id = ${JSON.stringify(id)};
  812. module.exports = webpackContext;`;
  813. }
  814. /**
  815. * @param {Dependency[]} dependencies dependencies
  816. * @param {ModuleId} id module id
  817. * @param {ImportPhaseType} phase import phase
  818. * @param {object} context context
  819. * @param {ChunkGraph} context.chunkGraph the chunk graph
  820. * @param {RuntimeTemplate} context.runtimeTemplate the chunk graph
  821. * @returns {string} source code
  822. */
  823. getAsyncWeakSource(dependencies, id, phase, { chunkGraph, runtimeTemplate }) {
  824. const map = this.getUserRequestMap(dependencies, chunkGraph);
  825. const fakeMap = this.getFakeMap(dependencies, chunkGraph);
  826. const asyncDepsMap =
  827. ImportPhaseUtils.isDefer(phase) &&
  828. this.getModuleDeferredAsyncDepsMap(dependencies, chunkGraph);
  829. const returnModuleObject = this.getReturnModuleObjectSource(
  830. fakeMap,
  831. true,
  832. asyncDepsMap ? "asyncDepsMap[id]" : undefined
  833. );
  834. return `var map = ${JSON.stringify(map, null, "\t")};
  835. ${this.getFakeMapInitStatement(fakeMap)}
  836. ${this.getModuleDeferredAsyncDepsMapInitStatement(asyncDepsMap)}
  837. function webpackAsyncContext(req) {
  838. return webpackAsyncContextResolve(req).then(${runtimeTemplate.basicFunction(
  839. "id",
  840. [
  841. `if(!${RuntimeGlobals.moduleFactories}[id]) {`,
  842. Template.indent([
  843. 'var e = new Error("Module \'" + req + "\' (\'" + id + "\') is not available (weak dependency)");',
  844. "e.code = 'MODULE_NOT_FOUND';",
  845. "throw e;"
  846. ]),
  847. "}",
  848. `return ${returnModuleObject};`
  849. ]
  850. )});
  851. }
  852. function webpackAsyncContextResolve(req) {
  853. // Here Promise.resolve().then() is used instead of new Promise() to prevent
  854. // uncaught exception popping up in devtools
  855. return Promise.resolve().then(${runtimeTemplate.basicFunction("", [
  856. `if(!${RuntimeGlobals.hasOwnProperty}(map, req)) {`,
  857. Template.indent([
  858. 'var e = new Error("Cannot find module \'" + req + "\'");',
  859. "e.code = 'MODULE_NOT_FOUND';",
  860. "throw e;"
  861. ]),
  862. "}",
  863. "return map[req];"
  864. ])});
  865. }
  866. webpackAsyncContext.keys = ${runtimeTemplate.returningFunction(
  867. "Object.keys(map)"
  868. )};
  869. webpackAsyncContext.resolve = webpackAsyncContextResolve;
  870. webpackAsyncContext.id = ${JSON.stringify(id)};
  871. module.exports = webpackAsyncContext;`;
  872. }
  873. /**
  874. * @param {Dependency[]} dependencies dependencies
  875. * @param {ModuleId} id module id
  876. * @param {ImportPhaseType} phase import phase
  877. * @param {object} context context
  878. * @param {ChunkGraph} context.chunkGraph the chunk graph
  879. * @param {RuntimeTemplate} context.runtimeTemplate the chunk graph
  880. * @returns {string} source code
  881. */
  882. getEagerSource(dependencies, id, phase, { chunkGraph, runtimeTemplate }) {
  883. const map = this.getUserRequestMap(dependencies, chunkGraph);
  884. const fakeMap = this.getFakeMap(dependencies, chunkGraph);
  885. const asyncDepsMap =
  886. ImportPhaseUtils.isDefer(phase) &&
  887. this.getModuleDeferredAsyncDepsMap(dependencies, chunkGraph);
  888. const thenFunction = runtimeTemplate.returningFunction(
  889. this.getReturnModuleObjectSource(
  890. fakeMap,
  891. true,
  892. asyncDepsMap ? "asyncDepsMap[id]" : undefined
  893. ),
  894. "id"
  895. );
  896. return `var map = ${JSON.stringify(map, null, "\t")};
  897. ${this.getFakeMapInitStatement(fakeMap)}
  898. ${this.getModuleDeferredAsyncDepsMapInitStatement(asyncDepsMap)}
  899. function webpackAsyncContext(req) {
  900. return webpackAsyncContextResolve(req).then(${thenFunction});
  901. }
  902. function webpackAsyncContextResolve(req) {
  903. // Here Promise.resolve().then() is used instead of new Promise() to prevent
  904. // uncaught exception popping up in devtools
  905. return Promise.resolve().then(${runtimeTemplate.basicFunction("", [
  906. `if(!${RuntimeGlobals.hasOwnProperty}(map, req)) {`,
  907. Template.indent([
  908. 'var e = new Error("Cannot find module \'" + req + "\'");',
  909. "e.code = 'MODULE_NOT_FOUND';",
  910. "throw e;"
  911. ]),
  912. "}",
  913. "return map[req];"
  914. ])});
  915. }
  916. webpackAsyncContext.keys = ${runtimeTemplate.returningFunction(
  917. "Object.keys(map)"
  918. )};
  919. webpackAsyncContext.resolve = webpackAsyncContextResolve;
  920. webpackAsyncContext.id = ${JSON.stringify(id)};
  921. module.exports = webpackAsyncContext;`;
  922. }
  923. /**
  924. * @param {AsyncDependenciesBlock} block block
  925. * @param {Dependency[]} dependencies dependencies
  926. * @param {ModuleId} id module id
  927. * @param {ImportPhaseType} phase import phase
  928. * @param {object} options options object
  929. * @param {RuntimeTemplate} options.runtimeTemplate the runtime template
  930. * @param {ChunkGraph} options.chunkGraph the chunk graph
  931. * @returns {string} source code
  932. */
  933. getLazyOnceSource(
  934. block,
  935. dependencies,
  936. id,
  937. phase,
  938. { runtimeTemplate, chunkGraph }
  939. ) {
  940. const promise = runtimeTemplate.blockPromise({
  941. chunkGraph,
  942. block,
  943. message: "lazy-once context",
  944. /** @type {RuntimeRequirements} */
  945. runtimeRequirements: new Set()
  946. });
  947. const map = this.getUserRequestMap(dependencies, chunkGraph);
  948. const fakeMap = this.getFakeMap(dependencies, chunkGraph);
  949. const asyncDepsMap =
  950. ImportPhaseUtils.isDefer(phase) &&
  951. this.getModuleDeferredAsyncDepsMap(dependencies, chunkGraph);
  952. const thenFunction = runtimeTemplate.returningFunction(
  953. this.getReturnModuleObjectSource(
  954. fakeMap,
  955. true,
  956. asyncDepsMap ? "asyncDepsMap[id]" : undefined
  957. ),
  958. "id"
  959. );
  960. return `var map = ${JSON.stringify(map, null, "\t")};
  961. ${this.getFakeMapInitStatement(fakeMap)}
  962. ${this.getModuleDeferredAsyncDepsMapInitStatement(asyncDepsMap)}
  963. function webpackAsyncContext(req) {
  964. return webpackAsyncContextResolve(req).then(${thenFunction});
  965. }
  966. function webpackAsyncContextResolve(req) {
  967. return ${promise}.then(${runtimeTemplate.basicFunction("", [
  968. `if(!${RuntimeGlobals.hasOwnProperty}(map, req)) {`,
  969. Template.indent([
  970. 'var e = new Error("Cannot find module \'" + req + "\'");',
  971. "e.code = 'MODULE_NOT_FOUND';",
  972. "throw e;"
  973. ]),
  974. "}",
  975. "return map[req];"
  976. ])});
  977. }
  978. webpackAsyncContext.keys = ${runtimeTemplate.returningFunction(
  979. "Object.keys(map)"
  980. )};
  981. webpackAsyncContext.resolve = webpackAsyncContextResolve;
  982. webpackAsyncContext.id = ${JSON.stringify(id)};
  983. module.exports = webpackAsyncContext;`;
  984. }
  985. /**
  986. * @param {AsyncDependenciesBlock[]} blocks blocks
  987. * @param {ModuleId} id module id
  988. * @param {ImportPhaseType} phase import phase
  989. * @param {object} context context
  990. * @param {ChunkGraph} context.chunkGraph the chunk graph
  991. * @param {RuntimeTemplate} context.runtimeTemplate the chunk graph
  992. * @returns {string} source code
  993. */
  994. getLazySource(blocks, id, phase, { chunkGraph, runtimeTemplate }) {
  995. const moduleGraph = chunkGraph.moduleGraph;
  996. let hasMultipleOrNoChunks = false;
  997. let hasNoChunk = true;
  998. let hasNoModuleDeferred = true;
  999. const fakeMap = this.getFakeMap(
  1000. blocks.map((b) => b.dependencies[0]),
  1001. chunkGraph
  1002. );
  1003. const hasFakeMap = typeof fakeMap === "object";
  1004. /** @typedef {{ userRequest: string, dependency: ContextElementDependency, chunks: undefined | Chunk[], module: Module, block: AsyncDependenciesBlock, asyncDeps: undefined | ModuleId[] }} Item */
  1005. /**
  1006. * @type {Item[]}
  1007. */
  1008. const items = blocks
  1009. .map((block) => {
  1010. const dependency =
  1011. /** @type {ContextElementDependency} */
  1012. (block.dependencies[0]);
  1013. return {
  1014. dependency,
  1015. module: /** @type {Module} */ (moduleGraph.getModule(dependency)),
  1016. block,
  1017. userRequest: dependency.userRequest,
  1018. chunks: undefined,
  1019. asyncDeps: undefined
  1020. };
  1021. })
  1022. .filter((item) => item.module);
  1023. for (const item of items) {
  1024. const chunkGroup = chunkGraph.getBlockChunkGroup(item.block);
  1025. const chunks = (chunkGroup && chunkGroup.chunks) || [];
  1026. item.chunks = chunks;
  1027. if (chunks.length > 0) {
  1028. hasNoChunk = false;
  1029. }
  1030. if (chunks.length !== 1) {
  1031. hasMultipleOrNoChunks = true;
  1032. }
  1033. const isModuleDeferred =
  1034. ImportPhaseUtils.isDefer(phase) &&
  1035. !(/** @type {BuildMeta} */ (item.module.buildMeta).async);
  1036. if (isModuleDeferred) {
  1037. const asyncDeps = Array.from(
  1038. getOutgoingAsyncModules(chunkGraph.moduleGraph, item.module),
  1039. (m) => chunkGraph.getModuleId(m)
  1040. ).filter((id) => id !== null);
  1041. item.asyncDeps = asyncDeps;
  1042. hasNoModuleDeferred = false;
  1043. }
  1044. }
  1045. const shortMode = hasNoChunk && hasNoModuleDeferred && !hasFakeMap;
  1046. const sortedItems = items.sort((a, b) => {
  1047. if (a.userRequest === b.userRequest) return 0;
  1048. return a.userRequest < b.userRequest ? -1 : 1;
  1049. });
  1050. /** @type {Record<string, ModuleId | (ModuleId | FakeMapType | ChunkId[] | (ModuleId[] | undefined))[]>} */
  1051. const map = Object.create(null);
  1052. for (const item of sortedItems) {
  1053. const moduleId =
  1054. /** @type {ModuleId} */
  1055. (chunkGraph.getModuleId(item.module));
  1056. if (shortMode) {
  1057. map[item.userRequest] = moduleId;
  1058. } else {
  1059. /** @type {(ModuleId | FakeMapType | ChunkId[] | (ModuleId[] | undefined))[]} */
  1060. const array = [moduleId];
  1061. if (hasFakeMap) {
  1062. array.push(fakeMap[moduleId]);
  1063. }
  1064. if (!hasNoChunk) {
  1065. array.push(
  1066. /** @type {Chunk[]} */ (item.chunks).map(
  1067. (chunk) => /** @type {ChunkId} */ (chunk.id)
  1068. )
  1069. );
  1070. }
  1071. if (!hasNoModuleDeferred) {
  1072. array.push(item.asyncDeps);
  1073. }
  1074. map[item.userRequest] = array;
  1075. }
  1076. }
  1077. const chunksPosition = hasFakeMap ? 2 : 1;
  1078. const asyncDepsPosition = chunksPosition + 1;
  1079. const requestPrefix = hasNoChunk
  1080. ? "Promise.resolve()"
  1081. : hasMultipleOrNoChunks
  1082. ? `Promise.all(ids[${chunksPosition}].map(${RuntimeGlobals.ensureChunk}))`
  1083. : `${RuntimeGlobals.ensureChunk}(ids[${chunksPosition}][0])`;
  1084. const returnModuleObject = this.getReturnModuleObjectSource(
  1085. fakeMap,
  1086. true,
  1087. hasNoModuleDeferred ? undefined : `ids[${asyncDepsPosition}]`,
  1088. shortMode ? "invalid" : "ids[1]"
  1089. );
  1090. const webpackAsyncContext =
  1091. requestPrefix === "Promise.resolve()"
  1092. ? `
  1093. function webpackAsyncContext(req) {
  1094. return Promise.resolve().then(${runtimeTemplate.basicFunction("", [
  1095. `if(!${RuntimeGlobals.hasOwnProperty}(map, req)) {`,
  1096. Template.indent([
  1097. 'var e = new Error("Cannot find module \'" + req + "\'");',
  1098. "e.code = 'MODULE_NOT_FOUND';",
  1099. "throw e;"
  1100. ]),
  1101. "}",
  1102. shortMode ? "var id = map[req];" : "var ids = map[req], id = ids[0];",
  1103. `return ${returnModuleObject};`
  1104. ])});
  1105. }`
  1106. : `function webpackAsyncContext(req) {
  1107. try {
  1108. if(!${RuntimeGlobals.hasOwnProperty}(map, req)) {
  1109. return Promise.resolve().then(${runtimeTemplate.basicFunction("", [
  1110. 'var e = new Error("Cannot find module \'" + req + "\'");',
  1111. "e.code = 'MODULE_NOT_FOUND';",
  1112. "throw e;"
  1113. ])});
  1114. }
  1115. } catch(err) {
  1116. return Promise.reject(err);
  1117. }
  1118. var ids = map[req], id = ids[0];
  1119. return ${requestPrefix}.then(${runtimeTemplate.returningFunction(returnModuleObject)});
  1120. }`;
  1121. return `var map = ${JSON.stringify(map, null, "\t")};
  1122. ${webpackAsyncContext}
  1123. webpackAsyncContext.keys = ${runtimeTemplate.returningFunction(
  1124. "Object.keys(map)"
  1125. )};
  1126. webpackAsyncContext.id = ${JSON.stringify(id)};
  1127. module.exports = webpackAsyncContext;`;
  1128. }
  1129. /**
  1130. * @param {ModuleId} id module id
  1131. * @param {RuntimeTemplate} runtimeTemplate runtime template
  1132. * @returns {string} source for empty async context
  1133. */
  1134. getSourceForEmptyContext(id, runtimeTemplate) {
  1135. return `function webpackEmptyContext(req) {
  1136. var e = new Error("Cannot find module '" + req + "'");
  1137. e.code = 'MODULE_NOT_FOUND';
  1138. throw e;
  1139. }
  1140. webpackEmptyContext.keys = ${runtimeTemplate.returningFunction("[]")};
  1141. webpackEmptyContext.resolve = webpackEmptyContext;
  1142. webpackEmptyContext.id = ${JSON.stringify(id)};
  1143. module.exports = webpackEmptyContext;`;
  1144. }
  1145. /**
  1146. * @param {ModuleId} id module id
  1147. * @param {RuntimeTemplate} runtimeTemplate runtime template
  1148. * @returns {string} source for empty async context
  1149. */
  1150. getSourceForEmptyAsyncContext(id, runtimeTemplate) {
  1151. return `function webpackEmptyAsyncContext(req) {
  1152. // Here Promise.resolve().then() is used instead of new Promise() to prevent
  1153. // uncaught exception popping up in devtools
  1154. return Promise.resolve().then(${runtimeTemplate.basicFunction("", [
  1155. 'var e = new Error("Cannot find module \'" + req + "\'");',
  1156. "e.code = 'MODULE_NOT_FOUND';",
  1157. "throw e;"
  1158. ])});
  1159. }
  1160. webpackEmptyAsyncContext.keys = ${runtimeTemplate.returningFunction("[]")};
  1161. webpackEmptyAsyncContext.resolve = webpackEmptyAsyncContext;
  1162. webpackEmptyAsyncContext.id = ${JSON.stringify(id)};
  1163. module.exports = webpackEmptyAsyncContext;`;
  1164. }
  1165. /**
  1166. * @param {string} asyncMode module mode
  1167. * @param {ImportPhaseType} phase import phase
  1168. * @param {CodeGenerationContext} context context info
  1169. * @returns {string} the source code
  1170. */
  1171. getSourceString(asyncMode, phase, { runtimeTemplate, chunkGraph }) {
  1172. const id = /** @type {ModuleId} */ (chunkGraph.getModuleId(this));
  1173. if (asyncMode === "lazy") {
  1174. if (this.blocks && this.blocks.length > 0) {
  1175. return this.getLazySource(this.blocks, id, phase, {
  1176. runtimeTemplate,
  1177. chunkGraph
  1178. });
  1179. }
  1180. return this.getSourceForEmptyAsyncContext(id, runtimeTemplate);
  1181. }
  1182. if (asyncMode === "eager") {
  1183. if (this.dependencies && this.dependencies.length > 0) {
  1184. return this.getEagerSource(this.dependencies, id, phase, {
  1185. chunkGraph,
  1186. runtimeTemplate
  1187. });
  1188. }
  1189. return this.getSourceForEmptyAsyncContext(id, runtimeTemplate);
  1190. }
  1191. if (asyncMode === "lazy-once") {
  1192. const block = this.blocks[0];
  1193. if (block) {
  1194. return this.getLazyOnceSource(block, block.dependencies, id, phase, {
  1195. runtimeTemplate,
  1196. chunkGraph
  1197. });
  1198. }
  1199. return this.getSourceForEmptyAsyncContext(id, runtimeTemplate);
  1200. }
  1201. if (asyncMode === "async-weak") {
  1202. if (this.dependencies && this.dependencies.length > 0) {
  1203. return this.getAsyncWeakSource(this.dependencies, id, phase, {
  1204. chunkGraph,
  1205. runtimeTemplate
  1206. });
  1207. }
  1208. return this.getSourceForEmptyAsyncContext(id, runtimeTemplate);
  1209. }
  1210. if (
  1211. asyncMode === "weak" &&
  1212. this.dependencies &&
  1213. this.dependencies.length > 0
  1214. ) {
  1215. return this.getWeakSyncSource(this.dependencies, id, chunkGraph);
  1216. }
  1217. if (this.dependencies && this.dependencies.length > 0) {
  1218. return this.getSyncSource(this.dependencies, id, chunkGraph);
  1219. }
  1220. return this.getSourceForEmptyContext(id, runtimeTemplate);
  1221. }
  1222. /**
  1223. * @param {string} sourceString source content
  1224. * @param {Compilation=} compilation the compilation
  1225. * @returns {Source} generated source
  1226. */
  1227. getSource(sourceString, compilation) {
  1228. if (this.useSourceMap || this.useSimpleSourceMap) {
  1229. return new OriginalSource(
  1230. sourceString,
  1231. `webpack://${makePathsRelative(
  1232. (compilation && compilation.compiler.context) || "",
  1233. this.identifier(),
  1234. compilation && compilation.compiler.root
  1235. )}`
  1236. );
  1237. }
  1238. return new RawSource(sourceString);
  1239. }
  1240. /**
  1241. * @param {CodeGenerationContext} context context for code generation
  1242. * @returns {CodeGenerationResult} result
  1243. */
  1244. codeGeneration(context) {
  1245. const { chunkGraph, compilation } = context;
  1246. /** @type {Sources} */
  1247. const sources = new Map();
  1248. sources.set(
  1249. JAVASCRIPT_TYPE,
  1250. this.getSource(
  1251. this.getSourceString(
  1252. this.options.mode,
  1253. this.options.phase || ImportPhase.Evaluation,
  1254. context
  1255. ),
  1256. compilation
  1257. )
  1258. );
  1259. /** @type {RuntimeRequirements} */
  1260. const set = new Set();
  1261. const allDeps =
  1262. this.dependencies.length > 0
  1263. ? /** @type {ContextElementDependency[]} */ [...this.dependencies]
  1264. : [];
  1265. for (const block of this.blocks) {
  1266. for (const dep of block.dependencies) {
  1267. allDeps.push(/** @type {ContextElementDependency} */ (dep));
  1268. }
  1269. }
  1270. set.add(RuntimeGlobals.module);
  1271. set.add(RuntimeGlobals.hasOwnProperty);
  1272. if (allDeps.length > 0) {
  1273. const asyncMode = this.options.mode;
  1274. set.add(RuntimeGlobals.require);
  1275. if (asyncMode === "weak") {
  1276. set.add(RuntimeGlobals.moduleFactories);
  1277. } else if (asyncMode === "async-weak") {
  1278. set.add(RuntimeGlobals.moduleFactories);
  1279. set.add(RuntimeGlobals.ensureChunk);
  1280. } else if (asyncMode === "lazy" || asyncMode === "lazy-once") {
  1281. set.add(RuntimeGlobals.ensureChunk);
  1282. }
  1283. if (this.getFakeMap(allDeps, chunkGraph) !== 9) {
  1284. set.add(RuntimeGlobals.createFakeNamespaceObject);
  1285. }
  1286. if (
  1287. ImportPhaseUtils.isDefer(this.options.phase || ImportPhase.Evaluation)
  1288. ) {
  1289. set.add(RuntimeGlobals.makeDeferredNamespaceObject);
  1290. }
  1291. }
  1292. return {
  1293. sources,
  1294. runtimeRequirements: set
  1295. };
  1296. }
  1297. /**
  1298. * @param {string=} type the source type for which the size should be estimated
  1299. * @returns {number} the estimated size of the module (must be non-zero)
  1300. */
  1301. size(type) {
  1302. // base penalty
  1303. let size = 160;
  1304. // if we don't have dependencies we stop here.
  1305. for (const dependency of this.dependencies) {
  1306. const element = /** @type {ContextElementDependency} */ (dependency);
  1307. size += 5 + element.userRequest.length;
  1308. }
  1309. return size;
  1310. }
  1311. /**
  1312. * @param {ObjectSerializerContext} context context
  1313. */
  1314. serialize(context) {
  1315. const { write } = context;
  1316. write(this._identifier);
  1317. write(this._forceBuild);
  1318. super.serialize(context);
  1319. }
  1320. /**
  1321. * @param {ObjectDeserializerContext} context context
  1322. */
  1323. deserialize(context) {
  1324. const { read } = context;
  1325. this._identifier = read();
  1326. this._forceBuild = read();
  1327. super.deserialize(context);
  1328. }
  1329. }
  1330. makeSerializable(ContextModule, "webpack/lib/ContextModule");
  1331. module.exports = ContextModule;