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

132 lines
4.2 KiB

  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { ConcatSource, RawSource } = require("webpack-sources");
  7. const ExternalModule = require("./ExternalModule");
  8. const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
  9. const RuntimeGlobals = require("./RuntimeGlobals");
  10. const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
  11. /** @typedef {import("webpack-sources").Source} Source */
  12. /** @typedef {import("../declarations/WebpackOptions").DevtoolNamespace} DevtoolNamespace */
  13. /** @typedef {import("../declarations/WebpackOptions").DevtoolModuleFilenameTemplate} DevtoolModuleFilenameTemplate */
  14. /** @typedef {import("./Compiler")} Compiler */
  15. /** @type {WeakMap<Source, Source>} */
  16. const cache = new WeakMap();
  17. const devtoolWarning = new RawSource(`/*
  18. * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
  19. * This devtool is neither made for production nor for readable output files.
  20. * It uses "eval()" calls to create a separate source file in the browser devtools.
  21. * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
  22. * or disable the default devtool with "devtool: false".
  23. * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
  24. */
  25. `);
  26. /**
  27. * @typedef {object} EvalDevToolModulePluginOptions
  28. * @property {DevtoolNamespace=} namespace namespace
  29. * @property {string=} sourceUrlComment source url comment
  30. * @property {DevtoolModuleFilenameTemplate=} moduleFilenameTemplate module filename template
  31. */
  32. const PLUGIN_NAME = "EvalDevToolModulePlugin";
  33. class EvalDevToolModulePlugin {
  34. /**
  35. * @param {EvalDevToolModulePluginOptions=} options options
  36. */
  37. constructor(options = {}) {
  38. this.namespace = options.namespace || "";
  39. this.sourceUrlComment = options.sourceUrlComment || "\n//# sourceURL=[url]";
  40. this.moduleFilenameTemplate =
  41. options.moduleFilenameTemplate ||
  42. "webpack://[namespace]/[resourcePath]?[loaders]";
  43. }
  44. /**
  45. * Apply the plugin
  46. * @param {Compiler} compiler the compiler instance
  47. * @returns {void}
  48. */
  49. apply(compiler) {
  50. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  51. const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
  52. hooks.renderModuleContent.tap(
  53. PLUGIN_NAME,
  54. (source, module, { chunk, runtimeTemplate, chunkGraph }) => {
  55. const cacheEntry = cache.get(source);
  56. if (cacheEntry !== undefined) return cacheEntry;
  57. if (module instanceof ExternalModule) {
  58. cache.set(source, source);
  59. return source;
  60. }
  61. const content = source.source();
  62. const namespace = compilation.getPath(this.namespace, {
  63. chunk
  64. });
  65. const str = ModuleFilenameHelpers.createFilename(
  66. module,
  67. {
  68. moduleFilenameTemplate: this.moduleFilenameTemplate,
  69. namespace
  70. },
  71. {
  72. requestShortener: runtimeTemplate.requestShortener,
  73. chunkGraph,
  74. hashFunction: compilation.outputOptions.hashFunction
  75. }
  76. );
  77. const footer = `\n${this.sourceUrlComment.replace(
  78. /\[url\]/g,
  79. encodeURI(str)
  80. .replace(/%2F/g, "/")
  81. .replace(/%20/g, "_")
  82. .replace(/%5E/g, "^")
  83. .replace(/%5C/g, "\\")
  84. .replace(/^\//, "")
  85. )}`;
  86. const result = new RawSource(
  87. `eval(${
  88. compilation.outputOptions.trustedTypes
  89. ? `${RuntimeGlobals.createScript}(${JSON.stringify(
  90. `{${content + footer}\n}`
  91. )})`
  92. : JSON.stringify(`{${content + footer}\n}`)
  93. });`
  94. );
  95. cache.set(source, result);
  96. return result;
  97. }
  98. );
  99. hooks.inlineInRuntimeBailout.tap(
  100. PLUGIN_NAME,
  101. () => "the eval devtool is used."
  102. );
  103. hooks.render.tap(
  104. PLUGIN_NAME,
  105. (source) => new ConcatSource(devtoolWarning, source)
  106. );
  107. hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash) => {
  108. hash.update(PLUGIN_NAME);
  109. hash.update("2");
  110. });
  111. if (compilation.outputOptions.trustedTypes) {
  112. compilation.hooks.additionalModuleRuntimeRequirements.tap(
  113. PLUGIN_NAME,
  114. (module, set, _context) => {
  115. set.add(RuntimeGlobals.createScript);
  116. }
  117. );
  118. }
  119. });
  120. }
  121. }
  122. module.exports = EvalDevToolModulePlugin;