format-webpack-messages.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. "use strict";
  2. var _extends = require("@swc/helpers/lib/_extends.js").default;
  3. var _interop_require_default = require("@swc/helpers/lib/_interop_require_default.js").default;
  4. var _stripAnsi = _interop_require_default(require("next/dist/compiled/strip-ansi"));
  5. // This file is based on https://github.com/facebook/create-react-app/blob/7b1a32be6ec9f99a6c9a3c66813f3ac09c4736b9/packages/react-dev-utils/formatWebpackMessages.js
  6. // It's been edited to remove chalk and CRA-specific logic
  7. const friendlySyntaxErrorLabel = 'Syntax error:';
  8. const WEBPACK_BREAKING_CHANGE_POLYFILLS = '\n\nBREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.';
  9. function isLikelyASyntaxError(message) {
  10. return (0, _stripAnsi).default(message).indexOf(friendlySyntaxErrorLabel) !== -1;
  11. }
  12. let hadMissingSassError = false;
  13. // Cleans up webpack error messages.
  14. function formatMessage(message, verbose, importTraceNote) {
  15. // TODO: Replace this once webpack 5 is stable
  16. if (typeof message === 'object' && message.message) {
  17. const filteredModuleTrace = message.moduleTrace && message.moduleTrace.filter((trace)=>!/next-(middleware|client-pages|edge-function)-loader\.js/.test(trace.originName));
  18. let body = message.message;
  19. const breakingChangeIndex = body.indexOf(WEBPACK_BREAKING_CHANGE_POLYFILLS);
  20. if (breakingChangeIndex >= 0) {
  21. body = body.slice(0, breakingChangeIndex);
  22. }
  23. message = (message.moduleName ? (0, _stripAnsi).default(message.moduleName) + '\n' : '') + (message.file ? (0, _stripAnsi).default(message.file) + '\n' : '') + body + (message.details && verbose ? '\n' + message.details : '') + (filteredModuleTrace && filteredModuleTrace.length && verbose ? (importTraceNote || '\n\nImport trace for requested module:') + filteredModuleTrace.map((trace)=>`\n${trace.moduleName}`).join('') : '') + (message.stack && verbose ? '\n' + message.stack : '');
  24. }
  25. let lines = message.split('\n');
  26. // Strip Webpack-added headers off errors/warnings
  27. // https://github.com/webpack/webpack/blob/master/lib/ModuleError.js
  28. lines = lines.filter((line)=>!/Module [A-z ]+\(from/.test(line));
  29. // Transform parsing error into syntax error
  30. // TODO: move this to our ESLint formatter?
  31. lines = lines.map((line)=>{
  32. const parsingError = /Line (\d+):(?:(\d+):)?\s*Parsing error: (.+)$/.exec(line);
  33. if (!parsingError) {
  34. return line;
  35. }
  36. const [, errorLine, errorColumn, errorMessage] = parsingError;
  37. return `${friendlySyntaxErrorLabel} ${errorMessage} (${errorLine}:${errorColumn})`;
  38. });
  39. message = lines.join('\n');
  40. // Smoosh syntax errors (commonly found in CSS)
  41. message = message.replace(/SyntaxError\s+\((\d+):(\d+)\)\s*(.+?)\n/g, `${friendlySyntaxErrorLabel} $3 ($1:$2)\n`);
  42. // Clean up export errors
  43. message = message.replace(/^.*export '(.+?)' was not found in '(.+?)'.*$/gm, `Attempted import error: '$1' is not exported from '$2'.`);
  44. message = message.replace(/^.*export 'default' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm, `Attempted import error: '$2' does not contain a default export (imported as '$1').`);
  45. message = message.replace(/^.*export '(.+?)' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm, `Attempted import error: '$1' is not exported from '$3' (imported as '$2').`);
  46. lines = message.split('\n');
  47. // Remove leading newline
  48. if (lines.length > 2 && lines[1].trim() === '') {
  49. lines.splice(1, 1);
  50. }
  51. // Cleans up verbose "module not found" messages for files and packages.
  52. if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {
  53. lines = [
  54. lines[0],
  55. lines[1].replace('Error: ', '').replace('Module not found: Cannot find file:', 'Cannot find file:'),
  56. ...lines.slice(2),
  57. ];
  58. }
  59. // Add helpful message for users trying to use Sass for the first time
  60. if (lines[1] && lines[1].match(/Cannot find module.+sass/)) {
  61. // ./file.module.scss (<<loader info>>) => ./file.module.scss
  62. const firstLine = lines[0].split('!');
  63. lines[0] = firstLine[firstLine.length - 1];
  64. lines[1] = "To use Next.js' built-in Sass support, you first need to install `sass`.\n";
  65. lines[1] += 'Run `npm i sass` or `yarn add sass` inside your workspace.\n';
  66. lines[1] += '\nLearn more: https://nextjs.org/docs/messages/install-sass';
  67. // dispose of unhelpful stack trace
  68. lines = lines.slice(0, 2);
  69. hadMissingSassError = true;
  70. } else if (hadMissingSassError && message.match(/(sass-loader|resolve-url-loader: CSS error)/)) {
  71. // dispose of unhelpful stack trace following missing sass module
  72. lines = [];
  73. }
  74. if (!verbose) {
  75. message = lines.join('\n');
  76. // Internal stacks are generally useless so we strip them... with the
  77. // exception of stacks containing `webpack:` because they're normally
  78. // from user code generated by Webpack. For more information see
  79. // https://github.com/facebook/create-react-app/pull/1050
  80. message = message.replace(/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm, '') // at ... ...:x:y
  81. ;
  82. message = message.replace(/^\s*at\s<anonymous>(\n|$)/gm, '') // at <anonymous>
  83. ;
  84. lines = message.split('\n');
  85. }
  86. // Remove duplicated newlines
  87. lines = lines.filter((line, index, arr)=>index === 0 || line.trim() !== '' || line.trim() !== arr[index - 1].trim());
  88. // Reassemble the message
  89. message = lines.join('\n');
  90. return message.trim();
  91. }
  92. function formatWebpackMessages(json, verbose) {
  93. const formattedErrors = json.errors.map(function(message) {
  94. let importTraceNote;
  95. // TODO: Shall we use invisible characters in the original error
  96. // message as meta information?
  97. if (message && message.message && /NEXT_RSC_ERR_/.test(message.message)) {
  98. // Comes from the "React Server Components" transform in SWC, always
  99. // attach the module trace.
  100. const NEXT_RSC_ERR_REACT_API = RegExp(".+NEXT_RSC_ERR_REACT_API: (.*?)\\n", "s");
  101. const NEXT_RSC_ERR_SERVER_IMPORT = RegExp(".+NEXT_RSC_ERR_SERVER_IMPORT: (.*?)\\n", "s");
  102. const NEXT_RSC_ERR_CLIENT_IMPORT = RegExp(".+NEXT_RSC_ERR_CLIENT_IMPORT: (.*?)\\n", "s");
  103. if (NEXT_RSC_ERR_REACT_API.test(message.message)) {
  104. message.message = message.message.replace(NEXT_RSC_ERR_REACT_API, `\n\nYou're importing a component that needs $1. It only works in a Client Component but none of its parents are marked with "client", so they're Server Components by default.\n\n`);
  105. importTraceNote = '\n\nMaybe one of these should be marked as a "client" entry:\n';
  106. } else if (NEXT_RSC_ERR_SERVER_IMPORT.test(message.message)) {
  107. message.message = message.message.replace(NEXT_RSC_ERR_SERVER_IMPORT, `\n\nYou're importing a component that imports $1. It only works in a Client Component but none of its parents are marked with "client", so they're Server Components by default.\n\n`);
  108. importTraceNote = '\n\nMaybe one of these should be marked as a "client" entry:\n';
  109. } else if (NEXT_RSC_ERR_CLIENT_IMPORT.test(message.message)) {
  110. message.message = message.message.replace(NEXT_RSC_ERR_CLIENT_IMPORT, `\n\nYou're importing a component that needs $1. That only works in a Server Component but one of its parents is marked with "client", so it's a Client Component.\n\n`);
  111. importTraceNote = '\n\nOne of these is marked as a "client" entry:\n';
  112. }
  113. verbose = true;
  114. }
  115. return formatMessage(message, verbose, importTraceNote);
  116. });
  117. const formattedWarnings = json.warnings.map(function(message) {
  118. return formatMessage(message, verbose);
  119. });
  120. const result = _extends({}, json, {
  121. errors: formattedErrors,
  122. warnings: formattedWarnings
  123. });
  124. if (!verbose && result.errors.some(isLikelyASyntaxError)) {
  125. // If there are any syntax errors, show just them.
  126. result.errors = result.errors.filter(isLikelyASyntaxError);
  127. result.warnings = [];
  128. }
  129. return result;
  130. }
  131. module.exports = formatWebpackMessages;
  132. if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') {
  133. Object.defineProperty(exports.default, '__esModule', { value: true });
  134. Object.assign(exports.default, exports);
  135. module.exports = exports.default;
  136. }
  137. //# sourceMappingURL=format-webpack-messages.js.map