RuntimePlugin.js 17 KB

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