EvalDevToolModulePlugin.js 4.2 KB

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