ContextModule.js 37 KB

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