From 9bb8fbf535378d1684e37afc1d94278461d79c11 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 14 Feb 2019 11:13:35 -0500 Subject: [PATCH] Update webpack message formatter (#6299) --- .../format-webpack-messages.js | 149 ++++++++---------- 1 file changed, 66 insertions(+), 83 deletions(-) diff --git a/packages/next/client/dev-error-overlay/format-webpack-messages.js b/packages/next/client/dev-error-overlay/format-webpack-messages.js index d26bcb39..86dcc319 100644 --- a/packages/next/client/dev-error-overlay/format-webpack-messages.js +++ b/packages/next/client/dev-error-overlay/format-webpack-messages.js @@ -1,7 +1,7 @@ /** MIT License -Copyright (c) 2013-present, Facebook, Inc. +Copyright (c) 2015-present, Facebook, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21,16 +21,12 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -// This file is based on https://github.com/facebook/create-react-app/blob/v1.1.4/packages/react-dev-utils/formatWebpackMessages.js -// It's been edited to remove chalk +// This file is based on https://github.com/facebook/create-react-app/blob/7b1a32be6ec9f99a6c9a3c66813f3ac09c4736b9/packages/react-dev-utils/formatWebpackMessages.js +// It's been edited to remove chalk and CRA-specific logic 'use strict' -// Some custom utilities to prettify Webpack output. -// This is quite hacky and hopefully won't be needed when Webpack fixes this. -// https://github.com/webpack/webpack/issues/2878 - -var friendlySyntaxErrorLabel = 'Syntax error:' +const friendlySyntaxErrorLabel = 'Syntax error:' function isLikelyASyntaxError (message) { return message.indexOf(friendlySyntaxErrorLabel) !== -1 @@ -39,112 +35,99 @@ function isLikelyASyntaxError (message) { // Cleans up webpack error messages. // eslint-disable-next-line no-unused-vars function formatMessage (message, isError) { - var lines = message.split('\n') + let lines = message.split('\n') - if (lines.length > 2 && lines[1] === '') { - // Remove extra newline. + // Strip Webpack-added headers off errors/warnings + // https://github.com/webpack/webpack/blob/master/lib/ModuleError.js + lines = lines.filter(line => !/Module [A-z ]+\(from/.test(line)) + + // Transform parsing error into syntax error + // TODO: move this to our ESLint formatter? + lines = lines.map(line => { + const parsingError = /Line (\d+):(?:(\d+):)?\s*Parsing error: (.+)$/.exec( + line + ) + if (!parsingError) { + return line + } + const [, errorLine, errorColumn, errorMessage] = parsingError + return `${friendlySyntaxErrorLabel} ${errorMessage} (${errorLine}:${errorColumn})` + }) + + message = lines.join('\n') + // Smoosh syntax errors (commonly found in CSS) + message = message.replace( + /SyntaxError\s+\((\d+):(\d+)\)\s*(.+?)\n/g, + `${friendlySyntaxErrorLabel} $3 ($1:$2)\n` + ) + // Remove columns from ESLint formatter output (we added these for more + // accurate syntax errors) + message = message.replace(/Line (\d+):\d+:/g, 'Line $1:') + // Clean up export errors + message = message.replace( + /^.*export '(.+?)' was not found in '(.+?)'.*$/gm, + `Attempted import error: '$1' is not exported from '$2'.` + ) + 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').` + ) + message = message.replace( + /^.*export '(.+?)' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm, + `Attempted import error: '$1' is not exported from '$3' (imported as '$2').` + ) + lines = message.split('\n') + + // Remove leading newline + if (lines.length > 2 && lines[1].trim() === '') { lines.splice(1, 1) } - - // Remove webpack-specific loader notation from filename. - // Before: - // ./~/css-loader!./~/postcss-loader!./src/App.css - // After: - // ./src/App.css - if (lines[0].lastIndexOf('!') !== -1) { - lines[0] = lines[0].substr(lines[0].lastIndexOf('!') + 1) - } - - // Remove unnecessary stack added by `thread-loader` - var threadLoaderIndex = -1 - lines.forEach(function (line, index) { - if (threadLoaderIndex !== -1) { - return - } - if (/thread.loader/i.test(line)) { - threadLoaderIndex = index - } - }) - - if (threadLoaderIndex !== -1) { - lines = lines.slice(0, threadLoaderIndex) - } - - lines = lines.filter(function (line) { - // Webpack adds a list of entry points to warning messages: - // @ ./src/index.js - // @ multi react-scripts/~/react-dev-utils/webpackHotDevClient.js ... - // It is misleading (and unrelated to the warnings) so we clean it up. - // It is only useful for syntax errors but we have beautiful frames for them. - return line.indexOf(' @ ') !== 0 - }) - - // line #0 is filename - // line #1 is the main error message - if (!lines[0] || !lines[1]) { - return lines.join('\n') - } + // Clean up file name + lines[0] = lines[0].replace(/^(.*) \d+:\d+-\d+$/, '$1') // Cleans up verbose "module not found" messages for files and packages. - if (lines[1].indexOf('Module not found: ') === 0) { + if (lines[1] && lines[1].indexOf('Module not found: ') === 0) { lines = [ lines[0], - // Clean up message because "Module not found: " is descriptive enough. lines[1] - .replace("Cannot resolve 'file' or 'directory' ", '') - .replace('Cannot resolve module ', '') .replace('Error: ', '') - .replace('[CaseSensitivePathsPlugin] ', '') + .replace('Module not found: Cannot find file:', 'Cannot find file:') ] } - // Cleans up syntax error messages. - if (lines[1].indexOf('Module build failed: ') === 0) { - lines[1] = lines[1].replace( - 'Module build failed: SyntaxError:', - friendlySyntaxErrorLabel - ) - } - - // Clean up export errors. - // TODO: we should really send a PR to Webpack for this. - var exportError = /\s*(.+?)\s*(")?export '(.+?)' was not found in '(.+?)'/ - if (lines[1].match(exportError)) { - lines[1] = lines[1].replace( - exportError, - "$1 '$4' does not contain an export named '$3'." - ) - } - - // Reassemble the message. message = lines.join('\n') // Internal stacks are generally useless so we strip them... with the // exception of stacks containing `webpack:` because they're normally - // from user code generated by WebPack. For more information see + // from user code generated by Webpack. For more information see // https://github.com/facebook/create-react-app/pull/1050 message = message.replace( /^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm, '' ) // at ... ...:x:y + message = message.replace(/^\s*at\s(\n|$)/gm, '') // at + lines = message.split('\n') + // Remove duplicated newlines + lines = lines.filter( + (line, index, arr) => + index === 0 || line.trim() !== '' || line.trim() !== arr[index - 1].trim() + ) + + // Reassemble the message + message = lines.join('\n') return message.trim() } function formatWebpackMessages (json) { - var formattedErrors = json.errors.map(function (message) { + const formattedErrors = json.errors.map(function (message) { return formatMessage(message, true) }) - var formattedWarnings = json.warnings.map(function (message) { + const formattedWarnings = json.warnings.map(function (message) { return formatMessage(message, false) }) - var result = { - errors: formattedErrors, - warnings: formattedWarnings - } + const result = { errors: formattedErrors, warnings: formattedWarnings } if (result.errors.some(isLikelyASyntaxError)) { // If there are any syntax errors, show just them. - // This prevents a confusing ESLint parsing error - // preceding a much more useful Babel syntax error. result.errors = result.errors.filter(isLikelyASyntaxError) } return result