MainTemplate.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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 { SyncWaterfallHook } = require("tapable");
  8. const RuntimeGlobals = require("./RuntimeGlobals");
  9. const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
  10. const memoize = require("./util/memoize");
  11. const getLoadScriptRuntimeModule = memoize(() =>
  12. require("./runtime/LoadScriptRuntimeModule")
  13. );
  14. const getJsonpTemplatePlugin = memoize(() =>
  15. require("./web/JsonpTemplatePlugin")
  16. );
  17. /** @import { Tap } from "tapable" */
  18. /** @import { Source } from "webpack-sources" */
  19. /** @import { Output as OutputOptions } from "../declarations/WebpackOptions" */
  20. /** @import ModuleTemplate from "./ModuleTemplate" */
  21. /** @import Chunk from "./Chunk" */
  22. /**
  23. * @import Compilation, {
  24. * AssetInfo,
  25. * InterpolatedPathAndAssetInfo,
  26. * PathData
  27. * } from "./Compilation"
  28. */
  29. /** @import Hash from "./util/Hash" */
  30. /** @import DependencyTemplates from "./DependencyTemplates" */
  31. /**
  32. * @import {
  33. * RenderBootstrapContext
  34. * } from "./javascript/JavascriptModulesPlugin"
  35. */
  36. /** @import { RenderManifestOptions, RenderManifestEntry } from "./Template" */
  37. /** @import { TemplatePath } from "./TemplatedPathPlugin" */
  38. /**
  39. * Defines the if set type used by this module.
  40. * @template T
  41. * @typedef {import("tapable").IfSet<T>} IfSet
  42. */
  43. // TODO webpack 6 remove this class
  44. class MainTemplate {
  45. /**
  46. * Creates an instance of MainTemplate.
  47. * @param {OutputOptions} outputOptions output options for the MainTemplate
  48. * @param {Compilation} compilation the compilation
  49. */
  50. constructor(outputOptions, compilation) {
  51. /** @type {OutputOptions} */
  52. this._outputOptions = outputOptions || {};
  53. this.hooks = Object.freeze({
  54. renderManifest: {
  55. tap: util.deprecate(
  56. /**
  57. * Handles the callback logic for this hook.
  58. * @template AdditionalOptions
  59. * @param {string | Tap & IfSet<AdditionalOptions>} options options
  60. * @param {(renderManifestEntries: RenderManifestEntry[], renderManifestOptions: RenderManifestOptions) => RenderManifestEntry[]} fn fn
  61. */
  62. (options, fn) => {
  63. compilation.hooks.renderManifest.tap(
  64. options,
  65. (entries, options) => {
  66. if (!options.chunk.hasRuntime()) return entries;
  67. return fn(entries, options);
  68. }
  69. );
  70. },
  71. "MainTemplate.hooks.renderManifest is deprecated (use Compilation.hooks.renderManifest instead)",
  72. "DEP_WEBPACK_MAIN_TEMPLATE_RENDER_MANIFEST"
  73. )
  74. },
  75. modules: {
  76. tap: () => {
  77. throw new Error(
  78. "MainTemplate.hooks.modules has been removed (there is no replacement, please create an issue to request that)"
  79. );
  80. }
  81. },
  82. moduleObj: {
  83. tap: () => {
  84. throw new Error(
  85. "MainTemplate.hooks.moduleObj has been removed (there is no replacement, please create an issue to request that)"
  86. );
  87. }
  88. },
  89. require: {
  90. tap: util.deprecate(
  91. /**
  92. * Handles the callback logic for this hook.
  93. * @template AdditionalOptions
  94. * @param {string | Tap & IfSet<AdditionalOptions>} options options
  95. * @param {(value: string, renderBootstrapContext: RenderBootstrapContext) => string} fn fn
  96. */
  97. (options, fn) => {
  98. JavascriptModulesPlugin.getCompilationHooks(
  99. compilation
  100. ).renderRequire.tap(options, fn);
  101. },
  102. "MainTemplate.hooks.require is deprecated (use JavascriptModulesPlugin.getCompilationHooks().renderRequire instead)",
  103. "DEP_WEBPACK_MAIN_TEMPLATE_REQUIRE"
  104. )
  105. },
  106. beforeStartup: {
  107. tap: () => {
  108. throw new Error(
  109. "MainTemplate.hooks.beforeStartup has been removed (use RuntimeGlobals.startupOnlyBefore instead)"
  110. );
  111. }
  112. },
  113. startup: {
  114. tap: () => {
  115. throw new Error(
  116. "MainTemplate.hooks.startup has been removed (use RuntimeGlobals.startup instead)"
  117. );
  118. }
  119. },
  120. afterStartup: {
  121. tap: () => {
  122. throw new Error(
  123. "MainTemplate.hooks.afterStartup has been removed (use RuntimeGlobals.startupOnlyAfter instead)"
  124. );
  125. }
  126. },
  127. render: {
  128. tap: util.deprecate(
  129. /**
  130. * Handles the callback logic for this hook.
  131. * @template AdditionalOptions
  132. * @param {string | Tap & IfSet<AdditionalOptions>} options options
  133. * @param {(source: Source, chunk: Chunk, hash: string | undefined, moduleTemplate: ModuleTemplate, dependencyTemplates: DependencyTemplates) => Source} fn fn
  134. */
  135. (options, fn) => {
  136. JavascriptModulesPlugin.getCompilationHooks(compilation).render.tap(
  137. options,
  138. (source, renderContext) => {
  139. if (
  140. renderContext.chunkGraph.getNumberOfEntryModules(
  141. renderContext.chunk
  142. ) === 0 ||
  143. !renderContext.chunk.hasRuntime()
  144. ) {
  145. return source;
  146. }
  147. return fn(
  148. source,
  149. renderContext.chunk,
  150. compilation.hash,
  151. compilation.moduleTemplates.javascript,
  152. compilation.dependencyTemplates
  153. );
  154. }
  155. );
  156. },
  157. "MainTemplate.hooks.render is deprecated (use JavascriptModulesPlugin.getCompilationHooks().render instead)",
  158. "DEP_WEBPACK_MAIN_TEMPLATE_RENDER"
  159. )
  160. },
  161. renderWithEntry: {
  162. tap: util.deprecate(
  163. /**
  164. * Handles the callback logic for this hook.
  165. * @template AdditionalOptions
  166. * @param {string | Tap & IfSet<AdditionalOptions>} options options
  167. * @param {(source: Source, chunk: Chunk, hash: string | undefined) => Source} fn fn
  168. */
  169. (options, fn) => {
  170. JavascriptModulesPlugin.getCompilationHooks(compilation).render.tap(
  171. options,
  172. (source, renderContext) => {
  173. if (
  174. renderContext.chunkGraph.getNumberOfEntryModules(
  175. renderContext.chunk
  176. ) === 0 ||
  177. !renderContext.chunk.hasRuntime()
  178. ) {
  179. return source;
  180. }
  181. return fn(source, renderContext.chunk, compilation.hash);
  182. }
  183. );
  184. },
  185. "MainTemplate.hooks.renderWithEntry is deprecated (use JavascriptModulesPlugin.getCompilationHooks().render instead)",
  186. "DEP_WEBPACK_MAIN_TEMPLATE_RENDER_WITH_ENTRY"
  187. )
  188. },
  189. assetPath: {
  190. tap: util.deprecate(
  191. /**
  192. * Handles the callback logic for this hook.
  193. * @template AdditionalOptions
  194. * @param {string | Tap & IfSet<AdditionalOptions>} options options
  195. * @param {(value: string, path: PathData, assetInfo: AssetInfo | undefined) => string} fn fn
  196. */
  197. (options, fn) => {
  198. compilation.hooks.assetPath.tap(options, fn);
  199. },
  200. "MainTemplate.hooks.assetPath is deprecated (use Compilation.hooks.assetPath instead)",
  201. "DEP_WEBPACK_MAIN_TEMPLATE_ASSET_PATH"
  202. ),
  203. call: util.deprecate(
  204. /**
  205. * Handles the call callback for this hook.
  206. * @param {TemplatePath} filename used to get asset path with hash
  207. * @param {PathData} options context data
  208. * @returns {string} interpolated path
  209. */
  210. (filename, options) => compilation.getAssetPath(filename, options),
  211. "MainTemplate.hooks.assetPath is deprecated (use Compilation.hooks.assetPath instead)",
  212. "DEP_WEBPACK_MAIN_TEMPLATE_ASSET_PATH"
  213. )
  214. },
  215. hash: {
  216. tap: util.deprecate(
  217. /**
  218. * Handles the callback logic for this hook.
  219. * @template AdditionalOptions
  220. * @param {string | Tap & IfSet<AdditionalOptions>} options options
  221. * @param {(hash: Hash) => void} fn fn
  222. */
  223. (options, fn) => {
  224. compilation.hooks.fullHash.tap(options, fn);
  225. },
  226. "MainTemplate.hooks.hash is deprecated (use Compilation.hooks.fullHash instead)",
  227. "DEP_WEBPACK_MAIN_TEMPLATE_HASH"
  228. )
  229. },
  230. hashForChunk: {
  231. tap: util.deprecate(
  232. /**
  233. * Handles the callback logic for this hook.
  234. * @template AdditionalOptions
  235. * @param {string | Tap & IfSet<AdditionalOptions>} options options
  236. * @param {(hash: Hash, chunk: Chunk) => void} fn fn
  237. */
  238. (options, fn) => {
  239. JavascriptModulesPlugin.getCompilationHooks(
  240. compilation
  241. ).chunkHash.tap(options, (chunk, hash) => {
  242. if (!chunk.hasRuntime()) return;
  243. return fn(hash, chunk);
  244. });
  245. },
  246. "MainTemplate.hooks.hashForChunk is deprecated (use JavascriptModulesPlugin.getCompilationHooks().chunkHash instead)",
  247. "DEP_WEBPACK_MAIN_TEMPLATE_HASH_FOR_CHUNK"
  248. )
  249. },
  250. globalHashPaths: {
  251. tap: util.deprecate(
  252. () => {},
  253. "MainTemplate.hooks.globalHashPaths has been removed (it's no longer needed)",
  254. "DEP_WEBPACK_MAIN_TEMPLATE_HASH_FOR_CHUNK"
  255. )
  256. },
  257. globalHash: {
  258. tap: util.deprecate(
  259. () => {},
  260. "MainTemplate.hooks.globalHash has been removed (it's no longer needed)",
  261. "DEP_WEBPACK_MAIN_TEMPLATE_HASH_FOR_CHUNK"
  262. )
  263. },
  264. hotBootstrap: {
  265. tap: () => {
  266. throw new Error(
  267. "MainTemplate.hooks.hotBootstrap has been removed (use your own RuntimeModule instead)"
  268. );
  269. }
  270. },
  271. // for compatibility:
  272. /** @type {SyncWaterfallHook<[string, Chunk, string, ModuleTemplate, DependencyTemplates]>} */
  273. bootstrap: new SyncWaterfallHook([
  274. "source",
  275. "chunk",
  276. "hash",
  277. "moduleTemplate",
  278. "dependencyTemplates"
  279. ]),
  280. /** @type {SyncWaterfallHook<[string, Chunk, string]>} */
  281. localVars: new SyncWaterfallHook(["source", "chunk", "hash"]),
  282. /** @type {SyncWaterfallHook<[string, Chunk, string]>} */
  283. requireExtensions: new SyncWaterfallHook(["source", "chunk", "hash"]),
  284. /** @type {SyncWaterfallHook<[string, Chunk, string, string]>} */
  285. requireEnsure: new SyncWaterfallHook([
  286. "source",
  287. "chunk",
  288. "hash",
  289. "chunkIdExpression"
  290. ]),
  291. get jsonpScript() {
  292. const hooks =
  293. getLoadScriptRuntimeModule().getCompilationHooks(compilation);
  294. return hooks.createScript;
  295. },
  296. get linkPrefetch() {
  297. const hooks = getJsonpTemplatePlugin().getCompilationHooks(compilation);
  298. return hooks.linkPrefetch;
  299. },
  300. get linkPreload() {
  301. const hooks = getJsonpTemplatePlugin().getCompilationHooks(compilation);
  302. return hooks.linkPreload;
  303. }
  304. });
  305. this.renderCurrentHashCode = util.deprecate(
  306. /**
  307. * Handles the require ensure callback for this hook.
  308. * @deprecated
  309. * @param {string} hash the hash
  310. * @param {number=} length length of the hash
  311. * @returns {string} generated code
  312. */
  313. (hash, length) => {
  314. if (length) {
  315. return `${RuntimeGlobals.getFullHash} ? ${
  316. RuntimeGlobals.getFullHash
  317. }().slice(0, ${length}) : ${hash.slice(0, length)}`;
  318. }
  319. return `${RuntimeGlobals.getFullHash} ? ${RuntimeGlobals.getFullHash}() : ${hash}`;
  320. },
  321. "MainTemplate.renderCurrentHashCode is deprecated (use RuntimeGlobals.getFullHash runtime function instead)",
  322. "DEP_WEBPACK_MAIN_TEMPLATE_RENDER_CURRENT_HASH_CODE"
  323. );
  324. this.getPublicPath = util.deprecate(
  325. /**
  326. * Handles the callback logic for this hook.
  327. * @param {PathData} options context data
  328. * @returns {string} interpolated path
  329. */ (options) =>
  330. compilation.getAssetPath(compilation.outputOptions.publicPath, options),
  331. "MainTemplate.getPublicPath is deprecated (use Compilation.getAssetPath(compilation.outputOptions.publicPath, options) instead)",
  332. "DEP_WEBPACK_MAIN_TEMPLATE_GET_PUBLIC_PATH"
  333. );
  334. this.getAssetPath = util.deprecate(
  335. /**
  336. * Handles the callback logic for this hook.
  337. * @param {TemplatePath} path used to get asset path with hash
  338. * @param {PathData} options context data
  339. * @returns {string} interpolated path
  340. */
  341. (path, options) => compilation.getAssetPath(path, options),
  342. "MainTemplate.getAssetPath is deprecated (use Compilation.getAssetPath instead)",
  343. "DEP_WEBPACK_MAIN_TEMPLATE_GET_ASSET_PATH"
  344. );
  345. this.getAssetPathWithInfo = util.deprecate(
  346. /**
  347. * Handles the callback logic for this hook.
  348. * @param {TemplatePath} path used to get asset path with hash
  349. * @param {PathData} options context data
  350. * @returns {InterpolatedPathAndAssetInfo} interpolated path and asset info
  351. */
  352. (path, options) => compilation.getAssetPathWithInfo(path, options),
  353. "MainTemplate.getAssetPathWithInfo is deprecated (use Compilation.getAssetPath instead)",
  354. "DEP_WEBPACK_MAIN_TEMPLATE_GET_ASSET_PATH_WITH_INFO"
  355. );
  356. }
  357. }
  358. Object.defineProperty(MainTemplate.prototype, "requireFn", {
  359. get: util.deprecate(
  360. () => RuntimeGlobals.require,
  361. `MainTemplate.requireFn is deprecated (use "${RuntimeGlobals.require}")`,
  362. "DEP_WEBPACK_MAIN_TEMPLATE_REQUIRE_FN"
  363. )
  364. });
  365. Object.defineProperty(MainTemplate.prototype, "outputOptions", {
  366. get: util.deprecate(
  367. /**
  368. * Returns output options.
  369. * @this {MainTemplate}
  370. * @returns {OutputOptions} output options
  371. */
  372. function outputOptions() {
  373. return this._outputOptions;
  374. },
  375. "MainTemplate.outputOptions is deprecated (use Compilation.outputOptions instead)",
  376. "DEP_WEBPACK_MAIN_TEMPLATE_OUTPUT_OPTIONS"
  377. )
  378. });
  379. module.exports = MainTemplate;