您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ContextModule.js 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const { OriginalSource, RawSource } = require("webpack-sources");
  8. const Module = require("./Module");
  9. const AsyncDependenciesBlock = require("./AsyncDependenciesBlock");
  10. const Template = require("./Template");
  11. const contextify = require("./util/identifier").contextify;
  12. /** @typedef {"sync" | "eager" | "weak" | "async-weak" | "lazy" | "lazy-once"} ContextMode Context mode */
  13. /** @typedef {import("./dependencies/ContextElementDependency")} ContextElementDependency */
  14. /**
  15. * @callback ResolveDependenciesCallback
  16. * @param {Error=} err
  17. * @param {ContextElementDependency[]} dependencies
  18. */
  19. /**
  20. * @callback ResolveDependencies
  21. * @param {TODO} fs
  22. * @param {TODO} options
  23. * @param {ResolveDependenciesCallback} callback
  24. */
  25. class ContextModule extends Module {
  26. // type ContextMode = "sync" | "eager" | "weak" | "async-weak" | "lazy" | "lazy-once"
  27. // type ContextOptions = { resource: string, recursive: boolean, regExp: RegExp, addon?: string, mode?: ContextMode, chunkName?: string, include?: RegExp, exclude?: RegExp, groupOptions?: Object }
  28. // resolveDependencies: (fs: FS, options: ContextOptions, (err: Error?, dependencies: Dependency[]) => void) => void
  29. // options: ContextOptions
  30. /**
  31. * @param {ResolveDependencies} resolveDependencies function to get dependencies in this context
  32. * @param {TODO} options options object
  33. */
  34. constructor(resolveDependencies, options) {
  35. let resource;
  36. let resourceQuery;
  37. const queryIdx = options.resource.indexOf("?");
  38. if (queryIdx >= 0) {
  39. resource = options.resource.substr(0, queryIdx);
  40. resourceQuery = options.resource.substr(queryIdx);
  41. } else {
  42. resource = options.resource;
  43. resourceQuery = "";
  44. }
  45. super("javascript/dynamic", resource);
  46. // Info from Factory
  47. this.resolveDependencies = resolveDependencies;
  48. this.options = Object.assign({}, options, {
  49. resource: resource,
  50. resourceQuery: resourceQuery
  51. });
  52. if (options.resolveOptions !== undefined) {
  53. this.resolveOptions = options.resolveOptions;
  54. }
  55. // Info from Build
  56. this._contextDependencies = new Set([this.context]);
  57. if (typeof options.mode !== "string") {
  58. throw new Error("options.mode is a required option");
  59. }
  60. this._identifier = this._createIdentifier();
  61. }
  62. updateCacheModule(module) {
  63. this.resolveDependencies = module.resolveDependencies;
  64. this.options = module.options;
  65. this.resolveOptions = module.resolveOptions;
  66. }
  67. prettyRegExp(regexString) {
  68. // remove the "/" at the front and the beginning
  69. // "/foo/" -> "foo"
  70. return regexString.substring(1, regexString.length - 1);
  71. }
  72. _createIdentifier() {
  73. let identifier = this.context;
  74. if (this.options.resourceQuery) {
  75. identifier += ` ${this.options.resourceQuery}`;
  76. }
  77. if (this.options.mode) {
  78. identifier += ` ${this.options.mode}`;
  79. }
  80. if (!this.options.recursive) {
  81. identifier += " nonrecursive";
  82. }
  83. if (this.options.addon) {
  84. identifier += ` ${this.options.addon}`;
  85. }
  86. if (this.options.regExp) {
  87. identifier += ` ${this.options.regExp}`;
  88. }
  89. if (this.options.include) {
  90. identifier += ` include: ${this.options.include}`;
  91. }
  92. if (this.options.exclude) {
  93. identifier += ` exclude: ${this.options.exclude}`;
  94. }
  95. if (this.options.groupOptions) {
  96. identifier += ` groupOptions: ${JSON.stringify(
  97. this.options.groupOptions
  98. )}`;
  99. }
  100. if (this.options.namespaceObject === "strict") {
  101. identifier += " strict namespace object";
  102. } else if (this.options.namespaceObject) {
  103. identifier += " namespace object";
  104. }
  105. return identifier;
  106. }
  107. identifier() {
  108. return this._identifier;
  109. }
  110. readableIdentifier(requestShortener) {
  111. let identifier = requestShortener.shorten(this.context);
  112. if (this.options.resourceQuery) {
  113. identifier += ` ${this.options.resourceQuery}`;
  114. }
  115. if (this.options.mode) {
  116. identifier += ` ${this.options.mode}`;
  117. }
  118. if (!this.options.recursive) {
  119. identifier += " nonrecursive";
  120. }
  121. if (this.options.addon) {
  122. identifier += ` ${requestShortener.shorten(this.options.addon)}`;
  123. }
  124. if (this.options.regExp) {
  125. identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
  126. }
  127. if (this.options.include) {
  128. identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
  129. }
  130. if (this.options.exclude) {
  131. identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
  132. }
  133. if (this.options.groupOptions) {
  134. const groupOptions = this.options.groupOptions;
  135. for (const key of Object.keys(groupOptions)) {
  136. identifier += ` ${key}: ${groupOptions[key]}`;
  137. }
  138. }
  139. if (this.options.namespaceObject === "strict") {
  140. identifier += " strict namespace object";
  141. } else if (this.options.namespaceObject) {
  142. identifier += " namespace object";
  143. }
  144. return identifier;
  145. }
  146. libIdent(options) {
  147. let identifier = contextify(options.context, this.context);
  148. if (this.options.mode) {
  149. identifier += ` ${this.options.mode}`;
  150. }
  151. if (this.options.recursive) {
  152. identifier += " recursive";
  153. }
  154. if (this.options.addon) {
  155. identifier += ` ${contextify(options.context, this.options.addon)}`;
  156. }
  157. if (this.options.regExp) {
  158. identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
  159. }
  160. if (this.options.include) {
  161. identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
  162. }
  163. if (this.options.exclude) {
  164. identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
  165. }
  166. return identifier;
  167. }
  168. needRebuild(fileTimestamps, contextTimestamps) {
  169. const ts = contextTimestamps.get(this.context);
  170. if (!ts) {
  171. return true;
  172. }
  173. return ts >= this.buildInfo.builtTime;
  174. }
  175. build(options, compilation, resolver, fs, callback) {
  176. this.built = true;
  177. this.buildMeta = {};
  178. this.buildInfo = {
  179. builtTime: Date.now(),
  180. contextDependencies: this._contextDependencies
  181. };
  182. this.resolveDependencies(fs, this.options, (err, dependencies) => {
  183. if (err) return callback(err);
  184. // abort if something failed
  185. // this will create an empty context
  186. if (!dependencies) {
  187. callback();
  188. return;
  189. }
  190. // enhance dependencies with meta info
  191. for (const dep of dependencies) {
  192. dep.loc = {
  193. name: dep.userRequest
  194. };
  195. dep.request = this.options.addon + dep.request;
  196. }
  197. if (this.options.mode === "sync" || this.options.mode === "eager") {
  198. // if we have an sync or eager context
  199. // just add all dependencies and continue
  200. this.dependencies = dependencies;
  201. } else if (this.options.mode === "lazy-once") {
  202. // for the lazy-once mode create a new async dependency block
  203. // and add that block to this context
  204. if (dependencies.length > 0) {
  205. const block = new AsyncDependenciesBlock(
  206. Object.assign({}, this.options.groupOptions, {
  207. name: this.options.chunkName
  208. }),
  209. this
  210. );
  211. for (const dep of dependencies) {
  212. block.addDependency(dep);
  213. }
  214. this.addBlock(block);
  215. }
  216. } else if (
  217. this.options.mode === "weak" ||
  218. this.options.mode === "async-weak"
  219. ) {
  220. // we mark all dependencies as weak
  221. for (const dep of dependencies) {
  222. dep.weak = true;
  223. }
  224. this.dependencies = dependencies;
  225. } else if (this.options.mode === "lazy") {
  226. // if we are lazy create a new async dependency block per dependency
  227. // and add all blocks to this context
  228. let index = 0;
  229. for (const dep of dependencies) {
  230. let chunkName = this.options.chunkName;
  231. if (chunkName) {
  232. if (!/\[(index|request)\]/.test(chunkName)) {
  233. chunkName += "[index]";
  234. }
  235. chunkName = chunkName.replace(/\[index\]/g, index++);
  236. chunkName = chunkName.replace(
  237. /\[request\]/g,
  238. Template.toPath(dep.userRequest)
  239. );
  240. }
  241. const block = new AsyncDependenciesBlock(
  242. Object.assign({}, this.options.groupOptions, {
  243. name: chunkName
  244. }),
  245. dep.module,
  246. dep.loc,
  247. dep.userRequest
  248. );
  249. block.addDependency(dep);
  250. this.addBlock(block);
  251. }
  252. } else {
  253. callback(
  254. new Error(`Unsupported mode "${this.options.mode}" in context`)
  255. );
  256. return;
  257. }
  258. callback();
  259. });
  260. }
  261. getUserRequestMap(dependencies) {
  262. // if we filter first we get a new array
  263. // therefor we dont need to create a clone of dependencies explicitly
  264. // therefore the order of this is !important!
  265. return dependencies
  266. .filter(dependency => dependency.module)
  267. .sort((a, b) => {
  268. if (a.userRequest === b.userRequest) {
  269. return 0;
  270. }
  271. return a.userRequest < b.userRequest ? -1 : 1;
  272. })
  273. .reduce((map, dep) => {
  274. map[dep.userRequest] = dep.module.id;
  275. return map;
  276. }, Object.create(null));
  277. }
  278. getFakeMap(dependencies) {
  279. if (!this.options.namespaceObject) {
  280. return 9;
  281. }
  282. // if we filter first we get a new array
  283. // therefor we dont need to create a clone of dependencies explicitly
  284. // therefore the order of this is !important!
  285. let hasNonHarmony = false;
  286. let hasNamespace = false;
  287. let hasNamed = false;
  288. const fakeMap = dependencies
  289. .filter(dependency => dependency.module)
  290. .sort((a, b) => {
  291. return b.module.id - a.module.id;
  292. })
  293. .reduce((map, dep) => {
  294. const exportsType =
  295. dep.module.buildMeta && dep.module.buildMeta.exportsType;
  296. const id = dep.module.id;
  297. if (!exportsType) {
  298. map[id] = this.options.namespaceObject === "strict" ? 1 : 7;
  299. hasNonHarmony = true;
  300. } else if (exportsType === "namespace") {
  301. map[id] = 9;
  302. hasNamespace = true;
  303. } else if (exportsType === "named") {
  304. map[id] = 3;
  305. hasNamed = true;
  306. }
  307. return map;
  308. }, Object.create(null));
  309. if (!hasNamespace && hasNonHarmony && !hasNamed) {
  310. return this.options.namespaceObject === "strict" ? 1 : 7;
  311. }
  312. if (hasNamespace && !hasNonHarmony && !hasNamed) {
  313. return 9;
  314. }
  315. if (!hasNamespace && !hasNonHarmony && hasNamed) {
  316. return 3;
  317. }
  318. if (!hasNamespace && !hasNonHarmony && !hasNamed) {
  319. return 9;
  320. }
  321. return fakeMap;
  322. }
  323. getFakeMapInitStatement(fakeMap) {
  324. return typeof fakeMap === "object"
  325. ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};`
  326. : "";
  327. }
  328. getReturn(type) {
  329. if (type === 9) {
  330. return "__webpack_require__(id)";
  331. }
  332. return `__webpack_require__.t(id, ${type})`;
  333. }
  334. getReturnModuleObjectSource(fakeMap, fakeMapDataExpression = "fakeMap[id]") {
  335. if (typeof fakeMap === "number") {
  336. return `return ${this.getReturn(fakeMap)};`;
  337. }
  338. return `return __webpack_require__.t(id, ${fakeMapDataExpression})`;
  339. }
  340. getSyncSource(dependencies, id) {
  341. const map = this.getUserRequestMap(dependencies);
  342. const fakeMap = this.getFakeMap(dependencies);
  343. const returnModuleObject = this.getReturnModuleObjectSource(fakeMap);
  344. return `var map = ${JSON.stringify(map, null, "\t")};
  345. ${this.getFakeMapInitStatement(fakeMap)}
  346. function webpackContext(req) {
  347. var id = webpackContextResolve(req);
  348. ${returnModuleObject}
  349. }
  350. function webpackContextResolve(req) {
  351. if(!__webpack_require__.o(map, req)) {
  352. var e = new Error("Cannot find module '" + req + "'");
  353. e.code = 'MODULE_NOT_FOUND';
  354. throw e;
  355. }
  356. return map[req];
  357. }
  358. webpackContext.keys = function webpackContextKeys() {
  359. return Object.keys(map);
  360. };
  361. webpackContext.resolve = webpackContextResolve;
  362. module.exports = webpackContext;
  363. webpackContext.id = ${JSON.stringify(id)};`;
  364. }
  365. getWeakSyncSource(dependencies, id) {
  366. const map = this.getUserRequestMap(dependencies);
  367. const fakeMap = this.getFakeMap(dependencies);
  368. const returnModuleObject = this.getReturnModuleObjectSource(fakeMap);
  369. return `var map = ${JSON.stringify(map, null, "\t")};
  370. ${this.getFakeMapInitStatement(fakeMap)}
  371. function webpackContext(req) {
  372. var id = webpackContextResolve(req);
  373. if(!__webpack_require__.m[id]) {
  374. var e = new Error("Module '" + req + "' ('" + id + "') is not available (weak dependency)");
  375. e.code = 'MODULE_NOT_FOUND';
  376. throw e;
  377. }
  378. ${returnModuleObject}
  379. }
  380. function webpackContextResolve(req) {
  381. if(!__webpack_require__.o(map, req)) {
  382. var e = new Error("Cannot find module '" + req + "'");
  383. e.code = 'MODULE_NOT_FOUND';
  384. throw e;
  385. }
  386. return map[req];
  387. }
  388. webpackContext.keys = function webpackContextKeys() {
  389. return Object.keys(map);
  390. };
  391. webpackContext.resolve = webpackContextResolve;
  392. webpackContext.id = ${JSON.stringify(id)};
  393. module.exports = webpackContext;`;
  394. }
  395. getAsyncWeakSource(dependencies, id) {
  396. const map = this.getUserRequestMap(dependencies);
  397. const fakeMap = this.getFakeMap(dependencies);
  398. const returnModuleObject = this.getReturnModuleObjectSource(fakeMap);
  399. return `var map = ${JSON.stringify(map, null, "\t")};
  400. ${this.getFakeMapInitStatement(fakeMap)}
  401. function webpackAsyncContext(req) {
  402. return webpackAsyncContextResolve(req).then(function(id) {
  403. if(!__webpack_require__.m[id]) {
  404. var e = new Error("Module '" + req + "' ('" + id + "') is not available (weak dependency)");
  405. e.code = 'MODULE_NOT_FOUND';
  406. throw e;
  407. }
  408. ${returnModuleObject}
  409. });
  410. }
  411. function webpackAsyncContextResolve(req) {
  412. // Here Promise.resolve().then() is used instead of new Promise() to prevent
  413. // uncaught exception popping up in devtools
  414. return Promise.resolve().then(function() {
  415. if(!__webpack_require__.o(map, req)) {
  416. var e = new Error("Cannot find module '" + req + "'");
  417. e.code = 'MODULE_NOT_FOUND';
  418. throw e;
  419. }
  420. return map[req];
  421. });
  422. }
  423. webpackAsyncContext.keys = function webpackAsyncContextKeys() {
  424. return Object.keys(map);
  425. };
  426. webpackAsyncContext.resolve = webpackAsyncContextResolve;
  427. webpackAsyncContext.id = ${JSON.stringify(id)};
  428. module.exports = webpackAsyncContext;`;
  429. }
  430. getEagerSource(dependencies, id) {
  431. const map = this.getUserRequestMap(dependencies);
  432. const fakeMap = this.getFakeMap(dependencies);
  433. const thenFunction =
  434. fakeMap !== 9
  435. ? `function(id) {
  436. ${this.getReturnModuleObjectSource(fakeMap)}
  437. }`
  438. : "__webpack_require__";
  439. return `var map = ${JSON.stringify(map, null, "\t")};
  440. ${this.getFakeMapInitStatement(fakeMap)}
  441. function webpackAsyncContext(req) {
  442. return webpackAsyncContextResolve(req).then(${thenFunction});
  443. }
  444. function webpackAsyncContextResolve(req) {
  445. // Here Promise.resolve().then() is used instead of new Promise() to prevent
  446. // uncaught exception popping up in devtools
  447. return Promise.resolve().then(function() {
  448. if(!__webpack_require__.o(map, req)) {
  449. var e = new Error("Cannot find module '" + req + "'");
  450. e.code = 'MODULE_NOT_FOUND';
  451. throw e;
  452. }
  453. return map[req];
  454. });
  455. }
  456. webpackAsyncContext.keys = function webpackAsyncContextKeys() {
  457. return Object.keys(map);
  458. };
  459. webpackAsyncContext.resolve = webpackAsyncContextResolve;
  460. webpackAsyncContext.id = ${JSON.stringify(id)};
  461. module.exports = webpackAsyncContext;`;
  462. }
  463. getLazyOnceSource(block, dependencies, id, runtimeTemplate) {
  464. const promise = runtimeTemplate.blockPromise({
  465. block,
  466. message: "lazy-once context"
  467. });
  468. const map = this.getUserRequestMap(dependencies);
  469. const fakeMap = this.getFakeMap(dependencies);
  470. const thenFunction =
  471. fakeMap !== 9
  472. ? `function(id) {
  473. ${this.getReturnModuleObjectSource(fakeMap)};
  474. }`
  475. : "__webpack_require__";
  476. return `var map = ${JSON.stringify(map, null, "\t")};
  477. ${this.getFakeMapInitStatement(fakeMap)}
  478. function webpackAsyncContext(req) {
  479. return webpackAsyncContextResolve(req).then(${thenFunction});
  480. }
  481. function webpackAsyncContextResolve(req) {
  482. return ${promise}.then(function() {
  483. if(!__webpack_require__.o(map, req)) {
  484. var e = new Error("Cannot find module '" + req + "'");
  485. e.code = 'MODULE_NOT_FOUND';
  486. throw e;
  487. }
  488. return map[req];
  489. });
  490. }
  491. webpackAsyncContext.keys = function webpackAsyncContextKeys() {
  492. return Object.keys(map);
  493. };
  494. webpackAsyncContext.resolve = webpackAsyncContextResolve;
  495. webpackAsyncContext.id = ${JSON.stringify(id)};
  496. module.exports = webpackAsyncContext;`;
  497. }
  498. getLazySource(blocks, id) {
  499. let hasMultipleOrNoChunks = false;
  500. let hasNoChunk = true;
  501. const fakeMap = this.getFakeMap(blocks.map(b => b.dependencies[0]));
  502. const hasFakeMap = typeof fakeMap === "object";
  503. const map = blocks
  504. .filter(block => block.dependencies[0].module)
  505. .map(block => {
  506. const chunks = block.chunkGroup ? block.chunkGroup.chunks : [];
  507. if (chunks.length > 0) {
  508. hasNoChunk = false;
  509. }
  510. if (chunks.length !== 1) {
  511. hasMultipleOrNoChunks = true;
  512. }
  513. return {
  514. dependency: block.dependencies[0],
  515. block: block,
  516. userRequest: block.dependencies[0].userRequest,
  517. chunks
  518. };
  519. })
  520. .sort((a, b) => {
  521. if (a.userRequest === b.userRequest) return 0;
  522. return a.userRequest < b.userRequest ? -1 : 1;
  523. })
  524. .reduce((map, item) => {
  525. const chunks = item.chunks;
  526. if (hasNoChunk && !hasFakeMap) {
  527. map[item.userRequest] = item.dependency.module.id;
  528. } else {
  529. const arrayStart = [item.dependency.module.id];
  530. if (typeof fakeMap === "object") {
  531. arrayStart.push(fakeMap[item.dependency.module.id]);
  532. }
  533. map[item.userRequest] = arrayStart.concat(
  534. chunks.map(chunk => chunk.id)
  535. );
  536. }
  537. return map;
  538. }, Object.create(null));
  539. const shortMode = hasNoChunk && !hasFakeMap;
  540. const chunksStartPosition = hasFakeMap ? 2 : 1;
  541. const requestPrefix = hasNoChunk
  542. ? "Promise.resolve()"
  543. : hasMultipleOrNoChunks
  544. ? `Promise.all(ids.slice(${chunksStartPosition}).map(__webpack_require__.e))`
  545. : `__webpack_require__.e(ids[${chunksStartPosition}])`;
  546. const returnModuleObject = this.getReturnModuleObjectSource(
  547. fakeMap,
  548. shortMode ? "invalid" : "ids[1]"
  549. );
  550. const webpackAsyncContext =
  551. requestPrefix === "Promise.resolve()"
  552. ? `${shortMode ? "" : ""}
  553. function webpackAsyncContext(req) {
  554. return Promise.resolve().then(function() {
  555. if(!__webpack_require__.o(map, req)) {
  556. var e = new Error("Cannot find module '" + req + "'");
  557. e.code = 'MODULE_NOT_FOUND';
  558. throw e;
  559. }
  560. ${shortMode ? "var id = map[req];" : "var ids = map[req], id = ids[0];"}
  561. ${returnModuleObject}
  562. });
  563. }`
  564. : `function webpackAsyncContext(req) {
  565. if(!__webpack_require__.o(map, req)) {
  566. return Promise.resolve().then(function() {
  567. var e = new Error("Cannot find module '" + req + "'");
  568. e.code = 'MODULE_NOT_FOUND';
  569. throw e;
  570. });
  571. }
  572. var ids = map[req], id = ids[0];
  573. return ${requestPrefix}.then(function() {
  574. ${returnModuleObject}
  575. });
  576. }`;
  577. return `var map = ${JSON.stringify(map, null, "\t")};
  578. ${webpackAsyncContext}
  579. webpackAsyncContext.keys = function webpackAsyncContextKeys() {
  580. return Object.keys(map);
  581. };
  582. webpackAsyncContext.id = ${JSON.stringify(id)};
  583. module.exports = webpackAsyncContext;`;
  584. }
  585. getSourceForEmptyContext(id) {
  586. return `function webpackEmptyContext(req) {
  587. var e = new Error("Cannot find module '" + req + "'");
  588. e.code = 'MODULE_NOT_FOUND';
  589. throw e;
  590. }
  591. webpackEmptyContext.keys = function() { return []; };
  592. webpackEmptyContext.resolve = webpackEmptyContext;
  593. module.exports = webpackEmptyContext;
  594. webpackEmptyContext.id = ${JSON.stringify(id)};`;
  595. }
  596. getSourceForEmptyAsyncContext(id) {
  597. return `function webpackEmptyAsyncContext(req) {
  598. // Here Promise.resolve().then() is used instead of new Promise() to prevent
  599. // uncaught exception popping up in devtools
  600. return Promise.resolve().then(function() {
  601. var e = new Error("Cannot find module '" + req + "'");
  602. e.code = 'MODULE_NOT_FOUND';
  603. throw e;
  604. });
  605. }
  606. webpackEmptyAsyncContext.keys = function() { return []; };
  607. webpackEmptyAsyncContext.resolve = webpackEmptyAsyncContext;
  608. module.exports = webpackEmptyAsyncContext;
  609. webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`;
  610. }
  611. getSourceString(asyncMode, runtimeTemplate) {
  612. if (asyncMode === "lazy") {
  613. if (this.blocks && this.blocks.length > 0) {
  614. return this.getLazySource(this.blocks, this.id);
  615. }
  616. return this.getSourceForEmptyAsyncContext(this.id);
  617. }
  618. if (asyncMode === "eager") {
  619. if (this.dependencies && this.dependencies.length > 0) {
  620. return this.getEagerSource(this.dependencies, this.id);
  621. }
  622. return this.getSourceForEmptyAsyncContext(this.id);
  623. }
  624. if (asyncMode === "lazy-once") {
  625. const block = this.blocks[0];
  626. if (block) {
  627. return this.getLazyOnceSource(
  628. block,
  629. block.dependencies,
  630. this.id,
  631. runtimeTemplate
  632. );
  633. }
  634. return this.getSourceForEmptyAsyncContext(this.id);
  635. }
  636. if (asyncMode === "async-weak") {
  637. if (this.dependencies && this.dependencies.length > 0) {
  638. return this.getAsyncWeakSource(this.dependencies, this.id);
  639. }
  640. return this.getSourceForEmptyAsyncContext(this.id);
  641. }
  642. if (asyncMode === "weak") {
  643. if (this.dependencies && this.dependencies.length > 0) {
  644. return this.getWeakSyncSource(this.dependencies, this.id);
  645. }
  646. }
  647. if (this.dependencies && this.dependencies.length > 0) {
  648. return this.getSyncSource(this.dependencies, this.id);
  649. }
  650. return this.getSourceForEmptyContext(this.id);
  651. }
  652. getSource(sourceString) {
  653. if (this.useSourceMap) {
  654. return new OriginalSource(sourceString, this.identifier());
  655. }
  656. return new RawSource(sourceString);
  657. }
  658. source(dependencyTemplates, runtimeTemplate) {
  659. return this.getSource(
  660. this.getSourceString(this.options.mode, runtimeTemplate)
  661. );
  662. }
  663. size() {
  664. // base penalty
  665. const initialSize = 160;
  666. // if we dont have dependencies we stop here.
  667. return this.dependencies.reduce((size, dependency) => {
  668. const element = /** @type {ContextElementDependency} */ (dependency);
  669. return size + 5 + element.userRequest.length;
  670. }, initialSize);
  671. }
  672. }
  673. // TODO remove in webpack 5
  674. Object.defineProperty(ContextModule.prototype, "recursive", {
  675. configurable: false,
  676. get: util.deprecate(
  677. /**
  678. * @deprecated
  679. * @this {ContextModule}
  680. * @returns {boolean} is recursive
  681. */
  682. function() {
  683. return this.options.recursive;
  684. },
  685. "ContextModule.recursive has been moved to ContextModule.options.recursive"
  686. ),
  687. set: util.deprecate(
  688. /**
  689. * @deprecated
  690. * @this {ContextModule}
  691. * @param {boolean} value is recursive
  692. * @returns {void}
  693. */
  694. function(value) {
  695. this.options.recursive = value;
  696. },
  697. "ContextModule.recursive has been moved to ContextModule.options.recursive"
  698. )
  699. });
  700. // TODO remove in webpack 5
  701. Object.defineProperty(ContextModule.prototype, "regExp", {
  702. configurable: false,
  703. get: util.deprecate(
  704. /**
  705. * @deprecated
  706. * @this {ContextModule}
  707. * @returns {RegExp} regular expression
  708. */
  709. function() {
  710. return this.options.regExp;
  711. },
  712. "ContextModule.regExp has been moved to ContextModule.options.regExp"
  713. ),
  714. set: util.deprecate(
  715. /**
  716. * @deprecated
  717. * @this {ContextModule}
  718. * @param {RegExp} value Regular expression
  719. * @returns {void}
  720. */
  721. function(value) {
  722. this.options.regExp = value;
  723. },
  724. "ContextModule.regExp has been moved to ContextModule.options.regExp"
  725. )
  726. });
  727. // TODO remove in webpack 5
  728. Object.defineProperty(ContextModule.prototype, "addon", {
  729. configurable: false,
  730. get: util.deprecate(
  731. /**
  732. * @deprecated
  733. * @this {ContextModule}
  734. * @returns {string} addon
  735. */
  736. function() {
  737. return this.options.addon;
  738. },
  739. "ContextModule.addon has been moved to ContextModule.options.addon"
  740. ),
  741. set: util.deprecate(
  742. /**
  743. * @deprecated
  744. * @this {ContextModule}
  745. * @param {string} value addon
  746. * @returns {void}
  747. */
  748. function(value) {
  749. this.options.addon = value;
  750. },
  751. "ContextModule.addon has been moved to ContextModule.options.addon"
  752. )
  753. });
  754. // TODO remove in webpack 5
  755. Object.defineProperty(ContextModule.prototype, "async", {
  756. configurable: false,
  757. get: util.deprecate(
  758. /**
  759. * @deprecated
  760. * @this {ContextModule}
  761. * @returns {boolean} is async
  762. */
  763. function() {
  764. return this.options.mode;
  765. },
  766. "ContextModule.async has been moved to ContextModule.options.mode"
  767. ),
  768. set: util.deprecate(
  769. /**
  770. * @deprecated
  771. * @this {ContextModule}
  772. * @param {ContextMode} value Context mode
  773. * @returns {void}
  774. */
  775. function(value) {
  776. this.options.mode = value;
  777. },
  778. "ContextModule.async has been moved to ContextModule.options.mode"
  779. )
  780. });
  781. // TODO remove in webpack 5
  782. Object.defineProperty(ContextModule.prototype, "chunkName", {
  783. configurable: false,
  784. get: util.deprecate(
  785. /**
  786. * @deprecated
  787. * @this {ContextModule}
  788. * @returns {string} chunk name
  789. */
  790. function() {
  791. return this.options.chunkName;
  792. },
  793. "ContextModule.chunkName has been moved to ContextModule.options.chunkName"
  794. ),
  795. set: util.deprecate(
  796. /**
  797. * @deprecated
  798. * @this {ContextModule}
  799. * @param {string} value chunk name
  800. * @returns {void}
  801. */
  802. function(value) {
  803. this.options.chunkName = value;
  804. },
  805. "ContextModule.chunkName has been moved to ContextModule.options.chunkName"
  806. )
  807. });
  808. module.exports = ContextModule;