提交学习笔记专用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

528 lines
18 KiB

  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RuntimeGlobals = require("./RuntimeGlobals");
  7. const RuntimeRequirementsDependency = require("./dependencies/RuntimeRequirementsDependency");
  8. const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
  9. const AsyncModuleRuntimeModule = require("./runtime/AsyncModuleRuntimeModule");
  10. const AutoPublicPathRuntimeModule = require("./runtime/AutoPublicPathRuntimeModule");
  11. const BaseUriRuntimeModule = require("./runtime/BaseUriRuntimeModule");
  12. const CompatGetDefaultExportRuntimeModule = require("./runtime/CompatGetDefaultExportRuntimeModule");
  13. const CompatRuntimeModule = require("./runtime/CompatRuntimeModule");
  14. const CreateFakeNamespaceObjectRuntimeModule = require("./runtime/CreateFakeNamespaceObjectRuntimeModule");
  15. const CreateScriptRuntimeModule = require("./runtime/CreateScriptRuntimeModule");
  16. const CreateScriptUrlRuntimeModule = require("./runtime/CreateScriptUrlRuntimeModule");
  17. const DefinePropertyGettersRuntimeModule = require("./runtime/DefinePropertyGettersRuntimeModule");
  18. const EnsureChunkRuntimeModule = require("./runtime/EnsureChunkRuntimeModule");
  19. const GetChunkFilenameRuntimeModule = require("./runtime/GetChunkFilenameRuntimeModule");
  20. const GetMainFilenameRuntimeModule = require("./runtime/GetMainFilenameRuntimeModule");
  21. const GetTrustedTypesPolicyRuntimeModule = require("./runtime/GetTrustedTypesPolicyRuntimeModule");
  22. const GlobalRuntimeModule = require("./runtime/GlobalRuntimeModule");
  23. const HasOwnPropertyRuntimeModule = require("./runtime/HasOwnPropertyRuntimeModule");
  24. const LoadScriptRuntimeModule = require("./runtime/LoadScriptRuntimeModule");
  25. const MakeDeferredNamespaceObjectRuntime = require("./runtime/MakeDeferredNamespaceObjectRuntime");
  26. const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectRuntimeModule");
  27. const NonceRuntimeModule = require("./runtime/NonceRuntimeModule");
  28. const OnChunksLoadedRuntimeModule = require("./runtime/OnChunksLoadedRuntimeModule");
  29. const PublicPathRuntimeModule = require("./runtime/PublicPathRuntimeModule");
  30. const RelativeUrlRuntimeModule = require("./runtime/RelativeUrlRuntimeModule");
  31. const RuntimeIdRuntimeModule = require("./runtime/RuntimeIdRuntimeModule");
  32. const SystemContextRuntimeModule = require("./runtime/SystemContextRuntimeModule");
  33. const ToBinaryRuntimeModule = require("./runtime/ToBinaryRuntimeModule");
  34. const ShareRuntimeModule = require("./sharing/ShareRuntimeModule");
  35. const StringXor = require("./util/StringXor");
  36. const memoize = require("./util/memoize");
  37. /** @typedef {import("../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
  38. /** @typedef {import("./Chunk")} Chunk */
  39. /** @typedef {import("./Compiler")} Compiler */
  40. const getJavascriptModulesPlugin = memoize(() =>
  41. require("./javascript/JavascriptModulesPlugin")
  42. );
  43. const getCssModulesPlugin = memoize(() => require("./css/CssModulesPlugin"));
  44. const GLOBALS_ON_REQUIRE = [
  45. RuntimeGlobals.chunkName,
  46. RuntimeGlobals.runtimeId,
  47. RuntimeGlobals.compatGetDefaultExport,
  48. RuntimeGlobals.createFakeNamespaceObject,
  49. RuntimeGlobals.createScript,
  50. RuntimeGlobals.createScriptUrl,
  51. RuntimeGlobals.getTrustedTypesPolicy,
  52. RuntimeGlobals.definePropertyGetters,
  53. RuntimeGlobals.ensureChunk,
  54. RuntimeGlobals.entryModuleId,
  55. RuntimeGlobals.getFullHash,
  56. RuntimeGlobals.global,
  57. RuntimeGlobals.makeNamespaceObject,
  58. RuntimeGlobals.moduleCache,
  59. RuntimeGlobals.moduleFactories,
  60. RuntimeGlobals.moduleFactoriesAddOnly,
  61. RuntimeGlobals.interceptModuleExecution,
  62. RuntimeGlobals.publicPath,
  63. RuntimeGlobals.baseURI,
  64. RuntimeGlobals.relativeUrl,
  65. // TODO webpack 6 - rename to nonce, because we use it for CSS too
  66. RuntimeGlobals.scriptNonce,
  67. RuntimeGlobals.uncaughtErrorHandler,
  68. RuntimeGlobals.asyncModule,
  69. RuntimeGlobals.wasmInstances,
  70. RuntimeGlobals.instantiateWasm,
  71. RuntimeGlobals.shareScopeMap,
  72. RuntimeGlobals.initializeSharing,
  73. RuntimeGlobals.loadScript,
  74. RuntimeGlobals.systemContext,
  75. RuntimeGlobals.onChunksLoaded,
  76. RuntimeGlobals.makeDeferredNamespaceObject
  77. ];
  78. const MODULE_DEPENDENCIES = {
  79. [RuntimeGlobals.moduleLoaded]: [RuntimeGlobals.module],
  80. [RuntimeGlobals.moduleId]: [RuntimeGlobals.module]
  81. };
  82. const TREE_DEPENDENCIES = {
  83. [RuntimeGlobals.definePropertyGetters]: [RuntimeGlobals.hasOwnProperty],
  84. [RuntimeGlobals.compatGetDefaultExport]: [
  85. RuntimeGlobals.definePropertyGetters
  86. ],
  87. [RuntimeGlobals.createFakeNamespaceObject]: [
  88. RuntimeGlobals.definePropertyGetters,
  89. RuntimeGlobals.makeNamespaceObject,
  90. RuntimeGlobals.require
  91. ],
  92. [RuntimeGlobals.makeDeferredNamespaceObject]: [
  93. RuntimeGlobals.definePropertyGetters,
  94. RuntimeGlobals.makeNamespaceObject,
  95. RuntimeGlobals.createFakeNamespaceObject,
  96. RuntimeGlobals.hasOwnProperty,
  97. RuntimeGlobals.require
  98. ],
  99. [RuntimeGlobals.initializeSharing]: [RuntimeGlobals.shareScopeMap],
  100. [RuntimeGlobals.shareScopeMap]: [RuntimeGlobals.hasOwnProperty]
  101. };
  102. const PLUGIN_NAME = "RuntimePlugin";
  103. class RuntimePlugin {
  104. /**
  105. * @param {Compiler} compiler the Compiler
  106. * @returns {void}
  107. */
  108. apply(compiler) {
  109. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  110. const globalChunkLoading = compilation.outputOptions.chunkLoading;
  111. /**
  112. * @param {Chunk} chunk chunk
  113. * @returns {boolean} true, when chunk loading is disabled for the chunk
  114. */
  115. const isChunkLoadingDisabledForChunk = (chunk) => {
  116. const options = chunk.getEntryOptions();
  117. const chunkLoading =
  118. options && options.chunkLoading !== undefined
  119. ? options.chunkLoading
  120. : globalChunkLoading;
  121. return chunkLoading === false;
  122. };
  123. compilation.dependencyTemplates.set(
  124. RuntimeRequirementsDependency,
  125. new RuntimeRequirementsDependency.Template()
  126. );
  127. for (const req of GLOBALS_ON_REQUIRE) {
  128. compilation.hooks.runtimeRequirementInModule
  129. .for(req)
  130. .tap(PLUGIN_NAME, (module, set) => {
  131. set.add(RuntimeGlobals.requireScope);
  132. });
  133. compilation.hooks.runtimeRequirementInTree
  134. .for(req)
  135. .tap(PLUGIN_NAME, (module, set) => {
  136. set.add(RuntimeGlobals.requireScope);
  137. });
  138. }
  139. for (const req of Object.keys(TREE_DEPENDENCIES)) {
  140. const deps =
  141. TREE_DEPENDENCIES[/** @type {keyof TREE_DEPENDENCIES} */ (req)];
  142. compilation.hooks.runtimeRequirementInTree
  143. .for(req)
  144. .tap(PLUGIN_NAME, (chunk, set) => {
  145. for (const dep of deps) set.add(dep);
  146. });
  147. }
  148. for (const req of Object.keys(MODULE_DEPENDENCIES)) {
  149. const deps =
  150. MODULE_DEPENDENCIES[/** @type {keyof MODULE_DEPENDENCIES} */ (req)];
  151. compilation.hooks.runtimeRequirementInModule
  152. .for(req)
  153. .tap(PLUGIN_NAME, (chunk, set) => {
  154. for (const dep of deps) set.add(dep);
  155. });
  156. }
  157. compilation.hooks.runtimeRequirementInTree
  158. .for(RuntimeGlobals.definePropertyGetters)
  159. .tap(PLUGIN_NAME, (chunk) => {
  160. compilation.addRuntimeModule(
  161. chunk,
  162. new DefinePropertyGettersRuntimeModule()
  163. );
  164. return true;
  165. });
  166. compilation.hooks.runtimeRequirementInTree
  167. .for(RuntimeGlobals.makeNamespaceObject)
  168. .tap(PLUGIN_NAME, (chunk) => {
  169. compilation.addRuntimeModule(
  170. chunk,
  171. new MakeNamespaceObjectRuntimeModule()
  172. );
  173. return true;
  174. });
  175. compilation.hooks.runtimeRequirementInTree
  176. .for(RuntimeGlobals.createFakeNamespaceObject)
  177. .tap(PLUGIN_NAME, (chunk) => {
  178. compilation.addRuntimeModule(
  179. chunk,
  180. new CreateFakeNamespaceObjectRuntimeModule()
  181. );
  182. return true;
  183. });
  184. compilation.hooks.runtimeRequirementInTree
  185. .for(RuntimeGlobals.makeDeferredNamespaceObject)
  186. .tap("RuntimePlugin", (chunk, runtimeRequirement) => {
  187. compilation.addRuntimeModule(
  188. chunk,
  189. new MakeDeferredNamespaceObjectRuntime(
  190. runtimeRequirement.has(RuntimeGlobals.asyncModule)
  191. )
  192. );
  193. return true;
  194. });
  195. compilation.hooks.runtimeRequirementInTree
  196. .for(RuntimeGlobals.hasOwnProperty)
  197. .tap(PLUGIN_NAME, (chunk) => {
  198. compilation.addRuntimeModule(
  199. chunk,
  200. new HasOwnPropertyRuntimeModule()
  201. );
  202. return true;
  203. });
  204. compilation.hooks.runtimeRequirementInTree
  205. .for(RuntimeGlobals.compatGetDefaultExport)
  206. .tap(PLUGIN_NAME, (chunk) => {
  207. compilation.addRuntimeModule(
  208. chunk,
  209. new CompatGetDefaultExportRuntimeModule()
  210. );
  211. return true;
  212. });
  213. compilation.hooks.runtimeRequirementInTree
  214. .for(RuntimeGlobals.runtimeId)
  215. .tap(PLUGIN_NAME, (chunk) => {
  216. compilation.addRuntimeModule(chunk, new RuntimeIdRuntimeModule());
  217. return true;
  218. });
  219. compilation.hooks.runtimeRequirementInTree
  220. .for(RuntimeGlobals.publicPath)
  221. .tap(PLUGIN_NAME, (chunk, set) => {
  222. const { outputOptions } = compilation;
  223. const { publicPath: globalPublicPath, scriptType } = outputOptions;
  224. const entryOptions = chunk.getEntryOptions();
  225. const publicPath =
  226. entryOptions && entryOptions.publicPath !== undefined
  227. ? entryOptions.publicPath
  228. : globalPublicPath;
  229. if (publicPath === "auto") {
  230. const module = new AutoPublicPathRuntimeModule();
  231. if (scriptType !== "module") set.add(RuntimeGlobals.global);
  232. compilation.addRuntimeModule(chunk, module);
  233. } else {
  234. const module = new PublicPathRuntimeModule(publicPath);
  235. if (
  236. typeof publicPath !== "string" ||
  237. /\[(full)?hash\]/.test(publicPath)
  238. ) {
  239. module.fullHash = true;
  240. }
  241. compilation.addRuntimeModule(chunk, module);
  242. }
  243. return true;
  244. });
  245. compilation.hooks.runtimeRequirementInTree
  246. .for(RuntimeGlobals.global)
  247. .tap(PLUGIN_NAME, (chunk) => {
  248. compilation.addRuntimeModule(chunk, new GlobalRuntimeModule());
  249. return true;
  250. });
  251. compilation.hooks.runtimeRequirementInTree
  252. .for(RuntimeGlobals.asyncModule)
  253. .tap(PLUGIN_NAME, (chunk) => {
  254. const experiments = compilation.options.experiments;
  255. compilation.addRuntimeModule(
  256. chunk,
  257. new AsyncModuleRuntimeModule(experiments.deferImport)
  258. );
  259. return true;
  260. });
  261. compilation.hooks.runtimeRequirementInTree
  262. .for(RuntimeGlobals.systemContext)
  263. .tap(PLUGIN_NAME, (chunk) => {
  264. const entryOptions = chunk.getEntryOptions();
  265. const libraryType =
  266. entryOptions && entryOptions.library !== undefined
  267. ? entryOptions.library.type
  268. : /** @type {LibraryOptions} */
  269. (compilation.outputOptions.library).type;
  270. if (libraryType === "system") {
  271. compilation.addRuntimeModule(
  272. chunk,
  273. new SystemContextRuntimeModule()
  274. );
  275. }
  276. return true;
  277. });
  278. compilation.hooks.runtimeRequirementInTree
  279. .for(RuntimeGlobals.getChunkScriptFilename)
  280. .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
  281. if (
  282. typeof compilation.outputOptions.chunkFilename === "string" &&
  283. /\[(full)?hash(:\d+)?\]/.test(
  284. compilation.outputOptions.chunkFilename
  285. )
  286. ) {
  287. set.add(RuntimeGlobals.getFullHash);
  288. }
  289. compilation.addRuntimeModule(
  290. chunk,
  291. new GetChunkFilenameRuntimeModule(
  292. "javascript",
  293. "javascript",
  294. RuntimeGlobals.getChunkScriptFilename,
  295. (chunk) =>
  296. getJavascriptModulesPlugin().chunkHasJs(chunk, chunkGraph) &&
  297. (chunk.filenameTemplate ||
  298. (chunk.canBeInitial()
  299. ? compilation.outputOptions.filename
  300. : compilation.outputOptions.chunkFilename)),
  301. set.has(RuntimeGlobals.hmrDownloadUpdateHandlers)
  302. )
  303. );
  304. return true;
  305. });
  306. compilation.hooks.runtimeRequirementInTree
  307. .for(RuntimeGlobals.getChunkCssFilename)
  308. .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
  309. if (
  310. typeof compilation.outputOptions.cssChunkFilename === "string" &&
  311. /\[(full)?hash(:\d+)?\]/.test(
  312. compilation.outputOptions.cssChunkFilename
  313. )
  314. ) {
  315. set.add(RuntimeGlobals.getFullHash);
  316. }
  317. compilation.addRuntimeModule(
  318. chunk,
  319. new GetChunkFilenameRuntimeModule(
  320. "css",
  321. "css",
  322. RuntimeGlobals.getChunkCssFilename,
  323. (chunk) => {
  324. const cssModulePlugin = getCssModulesPlugin();
  325. return (
  326. cssModulePlugin.chunkHasCss(chunk, chunkGraph) &&
  327. cssModulePlugin.getChunkFilenameTemplate(
  328. chunk,
  329. compilation.outputOptions
  330. )
  331. );
  332. },
  333. set.has(RuntimeGlobals.hmrDownloadUpdateHandlers)
  334. )
  335. );
  336. return true;
  337. });
  338. compilation.hooks.runtimeRequirementInTree
  339. .for(RuntimeGlobals.getChunkUpdateScriptFilename)
  340. .tap(PLUGIN_NAME, (chunk, set) => {
  341. if (
  342. /\[(full)?hash(:\d+)?\]/.test(
  343. compilation.outputOptions.hotUpdateChunkFilename
  344. )
  345. ) {
  346. set.add(RuntimeGlobals.getFullHash);
  347. }
  348. compilation.addRuntimeModule(
  349. chunk,
  350. new GetChunkFilenameRuntimeModule(
  351. "javascript",
  352. "javascript update",
  353. RuntimeGlobals.getChunkUpdateScriptFilename,
  354. (_chunk) => compilation.outputOptions.hotUpdateChunkFilename,
  355. true
  356. )
  357. );
  358. return true;
  359. });
  360. compilation.hooks.runtimeRequirementInTree
  361. .for(RuntimeGlobals.getUpdateManifestFilename)
  362. .tap(PLUGIN_NAME, (chunk, set) => {
  363. if (
  364. /\[(full)?hash(:\d+)?\]/.test(
  365. compilation.outputOptions.hotUpdateMainFilename
  366. )
  367. ) {
  368. set.add(RuntimeGlobals.getFullHash);
  369. }
  370. compilation.addRuntimeModule(
  371. chunk,
  372. new GetMainFilenameRuntimeModule(
  373. "update manifest",
  374. RuntimeGlobals.getUpdateManifestFilename,
  375. compilation.outputOptions.hotUpdateMainFilename
  376. )
  377. );
  378. return true;
  379. });
  380. compilation.hooks.runtimeRequirementInTree
  381. .for(RuntimeGlobals.ensureChunk)
  382. .tap(PLUGIN_NAME, (chunk, set) => {
  383. const hasAsyncChunks = chunk.hasAsyncChunks();
  384. if (hasAsyncChunks) {
  385. set.add(RuntimeGlobals.ensureChunkHandlers);
  386. }
  387. compilation.addRuntimeModule(
  388. chunk,
  389. new EnsureChunkRuntimeModule(set)
  390. );
  391. return true;
  392. });
  393. compilation.hooks.runtimeRequirementInTree
  394. .for(RuntimeGlobals.ensureChunkIncludeEntries)
  395. .tap(PLUGIN_NAME, (chunk, set) => {
  396. set.add(RuntimeGlobals.ensureChunkHandlers);
  397. });
  398. compilation.hooks.runtimeRequirementInTree
  399. .for(RuntimeGlobals.shareScopeMap)
  400. .tap(PLUGIN_NAME, (chunk, set) => {
  401. compilation.addRuntimeModule(chunk, new ShareRuntimeModule());
  402. return true;
  403. });
  404. compilation.hooks.runtimeRequirementInTree
  405. .for(RuntimeGlobals.loadScript)
  406. .tap(PLUGIN_NAME, (chunk, set) => {
  407. const withCreateScriptUrl = Boolean(
  408. compilation.outputOptions.trustedTypes
  409. );
  410. if (withCreateScriptUrl) {
  411. set.add(RuntimeGlobals.createScriptUrl);
  412. }
  413. const withFetchPriority = set.has(RuntimeGlobals.hasFetchPriority);
  414. compilation.addRuntimeModule(
  415. chunk,
  416. new LoadScriptRuntimeModule(withCreateScriptUrl, withFetchPriority)
  417. );
  418. return true;
  419. });
  420. compilation.hooks.runtimeRequirementInTree
  421. .for(RuntimeGlobals.createScript)
  422. .tap(PLUGIN_NAME, (chunk, set) => {
  423. if (compilation.outputOptions.trustedTypes) {
  424. set.add(RuntimeGlobals.getTrustedTypesPolicy);
  425. }
  426. compilation.addRuntimeModule(chunk, new CreateScriptRuntimeModule());
  427. return true;
  428. });
  429. compilation.hooks.runtimeRequirementInTree
  430. .for(RuntimeGlobals.createScriptUrl)
  431. .tap(PLUGIN_NAME, (chunk, set) => {
  432. if (compilation.outputOptions.trustedTypes) {
  433. set.add(RuntimeGlobals.getTrustedTypesPolicy);
  434. }
  435. compilation.addRuntimeModule(
  436. chunk,
  437. new CreateScriptUrlRuntimeModule()
  438. );
  439. return true;
  440. });
  441. compilation.hooks.runtimeRequirementInTree
  442. .for(RuntimeGlobals.getTrustedTypesPolicy)
  443. .tap(PLUGIN_NAME, (chunk, set) => {
  444. compilation.addRuntimeModule(
  445. chunk,
  446. new GetTrustedTypesPolicyRuntimeModule(set)
  447. );
  448. return true;
  449. });
  450. compilation.hooks.runtimeRequirementInTree
  451. .for(RuntimeGlobals.relativeUrl)
  452. .tap(PLUGIN_NAME, (chunk, _set) => {
  453. compilation.addRuntimeModule(chunk, new RelativeUrlRuntimeModule());
  454. return true;
  455. });
  456. compilation.hooks.runtimeRequirementInTree
  457. .for(RuntimeGlobals.onChunksLoaded)
  458. .tap(PLUGIN_NAME, (chunk, _set) => {
  459. compilation.addRuntimeModule(
  460. chunk,
  461. new OnChunksLoadedRuntimeModule()
  462. );
  463. return true;
  464. });
  465. compilation.hooks.runtimeRequirementInTree
  466. .for(RuntimeGlobals.baseURI)
  467. .tap(PLUGIN_NAME, (chunk) => {
  468. if (isChunkLoadingDisabledForChunk(chunk)) {
  469. compilation.addRuntimeModule(chunk, new BaseUriRuntimeModule());
  470. return true;
  471. }
  472. });
  473. compilation.hooks.runtimeRequirementInTree
  474. .for(RuntimeGlobals.scriptNonce)
  475. .tap(PLUGIN_NAME, (chunk) => {
  476. compilation.addRuntimeModule(chunk, new NonceRuntimeModule());
  477. return true;
  478. });
  479. compilation.hooks.runtimeRequirementInTree
  480. .for(RuntimeGlobals.toBinary)
  481. .tap(PLUGIN_NAME, (chunk) => {
  482. compilation.addRuntimeModule(chunk, new ToBinaryRuntimeModule());
  483. return true;
  484. });
  485. // TODO webpack 6: remove CompatRuntimeModule
  486. compilation.hooks.additionalTreeRuntimeRequirements.tap(
  487. PLUGIN_NAME,
  488. (chunk, _set) => {
  489. const { mainTemplate } = compilation;
  490. if (
  491. mainTemplate.hooks.bootstrap.isUsed() ||
  492. mainTemplate.hooks.localVars.isUsed() ||
  493. mainTemplate.hooks.requireEnsure.isUsed() ||
  494. mainTemplate.hooks.requireExtensions.isUsed()
  495. ) {
  496. compilation.addRuntimeModule(chunk, new CompatRuntimeModule());
  497. }
  498. }
  499. );
  500. JavascriptModulesPlugin.getCompilationHooks(compilation).chunkHash.tap(
  501. PLUGIN_NAME,
  502. (chunk, hash, { chunkGraph }) => {
  503. const xor = new StringXor();
  504. for (const m of chunkGraph.getChunkRuntimeModulesIterable(chunk)) {
  505. xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
  506. }
  507. xor.updateHash(hash);
  508. }
  509. );
  510. });
  511. }
  512. }
  513. module.exports = RuntimePlugin;