提交学习笔记专用
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.

371 lines
12 KiB

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