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.

120 lines
3.3 KiB

4 years ago
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { RawSource } = require("webpack-sources");
  7. const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
  8. const { absolutify } = require("./util/identifier");
  9. const cache = new WeakMap();
  10. class EvalSourceMapDevToolModuleTemplatePlugin {
  11. constructor(compilation, options) {
  12. this.compilation = compilation;
  13. this.sourceMapComment =
  14. options.append || "//# sourceURL=[module]\n//# sourceMappingURL=[url]";
  15. this.moduleFilenameTemplate =
  16. options.moduleFilenameTemplate ||
  17. "webpack://[namespace]/[resource-path]?[hash]";
  18. this.namespace = options.namespace || "";
  19. this.options = options;
  20. }
  21. apply(moduleTemplate) {
  22. const self = this;
  23. const options = this.options;
  24. const matchModule = ModuleFilenameHelpers.matchObject.bind(
  25. ModuleFilenameHelpers,
  26. options
  27. );
  28. moduleTemplate.hooks.module.tap(
  29. "EvalSourceMapDevToolModuleTemplatePlugin",
  30. (source, module) => {
  31. const cachedSource = cache.get(source);
  32. if (cachedSource !== undefined) {
  33. return cachedSource;
  34. }
  35. if (!matchModule(module.resource)) {
  36. return source;
  37. }
  38. /** @type {{ [key: string]: TODO; }} */
  39. let sourceMap;
  40. let content;
  41. if (source.sourceAndMap) {
  42. const sourceAndMap = source.sourceAndMap(options);
  43. sourceMap = sourceAndMap.map;
  44. content = sourceAndMap.source;
  45. } else {
  46. sourceMap = source.map(options);
  47. content = source.source();
  48. }
  49. if (!sourceMap) {
  50. return source;
  51. }
  52. // Clone (flat) the sourcemap to ensure that the mutations below do not persist.
  53. sourceMap = Object.keys(sourceMap).reduce((obj, key) => {
  54. obj[key] = sourceMap[key];
  55. return obj;
  56. }, {});
  57. const context = this.compilation.compiler.options.context;
  58. const modules = sourceMap.sources.map(source => {
  59. if (source.startsWith("webpack://")) {
  60. source = absolutify(context, source.slice(10));
  61. }
  62. const module = self.compilation.findModule(source);
  63. return module || source;
  64. });
  65. let moduleFilenames = modules.map(module => {
  66. return ModuleFilenameHelpers.createFilename(
  67. module,
  68. {
  69. moduleFilenameTemplate: self.moduleFilenameTemplate,
  70. namespace: self.namespace
  71. },
  72. moduleTemplate.runtimeTemplate.requestShortener
  73. );
  74. });
  75. moduleFilenames = ModuleFilenameHelpers.replaceDuplicates(
  76. moduleFilenames,
  77. (filename, i, n) => {
  78. for (let j = 0; j < n; j++) filename += "*";
  79. return filename;
  80. }
  81. );
  82. sourceMap.sources = moduleFilenames;
  83. sourceMap.sourceRoot = options.sourceRoot || "";
  84. sourceMap.file = `${module.id}.js`;
  85. const footer =
  86. self.sourceMapComment.replace(
  87. /\[url\]/g,
  88. `data:application/json;charset=utf-8;base64,${Buffer.from(
  89. JSON.stringify(sourceMap),
  90. "utf8"
  91. ).toString("base64")}`
  92. ) + `\n//# sourceURL=webpack-internal:///${module.id}\n`; // workaround for chrome bug
  93. const evalSource = new RawSource(
  94. `eval(${JSON.stringify(content + footer)});`
  95. );
  96. cache.set(source, evalSource);
  97. return evalSource;
  98. }
  99. );
  100. moduleTemplate.hooks.hash.tap(
  101. "EvalSourceMapDevToolModuleTemplatePlugin",
  102. hash => {
  103. hash.update("eval-source-map");
  104. hash.update("2");
  105. }
  106. );
  107. }
  108. }
  109. module.exports = EvalSourceMapDevToolModuleTemplatePlugin;