ContextModule.js 43 KB

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