MainTemplate.js 13 KB

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