ModuleParseError.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const makeSerializable = require("../util/makeSerializable");
  7. const WebpackError = require("./WebpackError");
  8. /** @import { DependencyLocation, SourcePosition } from "../Dependency" */
  9. /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext<[Error]>} ObjectDeserializerContext */
  10. /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext<[Error]>} ObjectSerializerContext */
  11. const WASM_HEADER = Buffer.from([0x00, 0x61, 0x73, 0x6d]);
  12. class ModuleParseError extends WebpackError {
  13. /**
  14. * Creates an instance of ModuleParseError.
  15. * @param {string | Buffer} source source code
  16. * @param {Error & { loc?: SourcePosition }} err the parse error
  17. * @param {string[]} loaders the loaders used
  18. * @param {string} type module type
  19. */
  20. constructor(source, err, loaders, type) {
  21. let message = `Module parse failed: ${err && err.message}`;
  22. /** @type {undefined | DependencyLocation} */
  23. let loc;
  24. if (
  25. ((Buffer.isBuffer(source) && source.subarray(0, 4).equals(WASM_HEADER)) ||
  26. (typeof source === "string" && /^\0asm/.test(source))) &&
  27. !type.startsWith("webassembly")
  28. ) {
  29. message +=
  30. "\nThe module seem to be a WebAssembly module, but module is not flagged as WebAssembly module for webpack.";
  31. message +=
  32. "\nBREAKING CHANGE: Since webpack 5 WebAssembly is not enabled by default and flagged as experimental feature.";
  33. message +=
  34. "\nYou need to enable one of the WebAssembly experiments via 'experiments.asyncWebAssembly: true' (based on async modules) or 'experiments.syncWebAssembly: true' (like webpack 4, deprecated).";
  35. message +=
  36. "\nFor files that transpile to WebAssembly, make sure to set the module type in the 'module.rules' section of the config (e. g. 'type: \"webassembly/async\"').";
  37. } else {
  38. message += `\nFile was parsed as module type '${type}'.`;
  39. // `loaders` is undefined when the serializer re-runs this constructor
  40. // during cache deserialization — keep that branch so it never throws.
  41. if (!loaders) {
  42. message +=
  43. "\nYou may need an appropriate loader to handle this file type. " +
  44. "See https://webpack.js.org/concepts/loaders";
  45. } else if (loaders.length >= 1) {
  46. message += `\nFile was processed with these loaders:${loaders
  47. .map((loader) => `\n * ${loader}`)
  48. .join("")}`;
  49. message +=
  50. "\nYou may need an additional loader to handle the result of these loaders.";
  51. } else {
  52. message +=
  53. "\nYou may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders";
  54. }
  55. }
  56. if (
  57. err &&
  58. err.loc &&
  59. typeof err.loc === "object" &&
  60. typeof err.loc.line === "number"
  61. ) {
  62. const lineNumber = err.loc.line;
  63. if (
  64. Buffer.isBuffer(source) ||
  65. // eslint-disable-next-line no-control-regex
  66. /[\0\u0001\u0002\u0003\u0004\u0005\u0006\u0007]/.test(source)
  67. ) {
  68. // binary file
  69. message += "\n(Source code omitted for this binary file)";
  70. } else {
  71. const sourceLines = source.split(/\r?\n/);
  72. if (lineNumber >= 1 && lineNumber <= sourceLines.length) {
  73. // babel-like code frame: numbered gutter, `>` on the error line
  74. // and a `^` caret at the error column
  75. const column =
  76. typeof err.loc.column === "number" ? err.loc.column : undefined;
  77. const start = Math.max(1, lineNumber - 1);
  78. const end = Math.min(sourceLines.length, lineNumber + 1);
  79. const width = `${end}`.length;
  80. for (let n = start; n <= end; n++) {
  81. const line = sourceLines[n - 1];
  82. const gutter = `${n}`.padStart(width);
  83. message +=
  84. n === lineNumber
  85. ? `\n> ${gutter} | ${line}`
  86. : `\n ${gutter} | ${line}`;
  87. if (n === lineNumber && column !== undefined) {
  88. // keep tabs so the caret stays aligned under tab-indented code
  89. const align = line.slice(0, column).replace(/[^\t]/g, " ");
  90. message += `\n ${" ".repeat(width)} | ${align}^`;
  91. }
  92. }
  93. }
  94. }
  95. loc = { start: err.loc };
  96. } else if (err && err.stack) {
  97. message += `\n${err.stack}`;
  98. }
  99. super(message);
  100. /** @type {string} */
  101. this.name = "ModuleParseError";
  102. /** @type {undefined | DependencyLocation} */
  103. this.loc = loc;
  104. /** @type {Error} */
  105. this.error = err;
  106. }
  107. /**
  108. * Serializes this instance into the provided serializer context.
  109. * @param {ObjectSerializerContext} context context
  110. */
  111. serialize(context) {
  112. context.write(this.error);
  113. super.serialize(context);
  114. }
  115. /**
  116. * Restores this instance from the provided deserializer context.
  117. * @param {ObjectDeserializerContext} context context
  118. */
  119. deserialize(context) {
  120. this.error = context.read();
  121. super.deserialize(context.rest);
  122. }
  123. }
  124. makeSerializable(ModuleParseError, "webpack/lib/errors/ModuleParseError");
  125. module.exports = ModuleParseError;