MainTemplate.js 13 KB

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