Proposal to enhance loader error reporting API: structured error reporting #2878

Open
andreypopp opened this Issue Aug 16, 2016 · 5 comments

Projects

Idea in Proposals / RFC's

5 participants

@andreypopp
Contributor

Problem

Currently loader context provides an opaque API for error reporting: only
message , stack and (undocumented?) hideStack error object
properties are used to report an error to a user.

Thus the appearance of error varies widely between different loaders. Babel,
eslint, css, postcss, sass loaders for example all have different error
reporting styles.

In addition to that there's a lot of duplicated info, some loaders render
filename of the module which is unnecessary as Webpack does so too and in a more
concise manner (it uses request shortener).

I believe this overwhelms users of Webpack and takes a lot more cognitive efforts
to recognize and process errors.

Solution

The solution I propose is to enhance error reporting API of loaders, namely:

this.emitError(err)                     // emit error
let cb = this.async(); cb(err, result)  // emit error via cb
throw new Error(...)                    // emit error via throw

To accept an Error object with the following properties:

  • name: string — name of the error. Already present on errors but is not used explicitly.
  • reason: string — a human readable error message without filename of the
    module happened into. If not provided then message property is used as
    before.
  • loc?: {line: number, column: number}optional default: undefined, a
    location within the module error happened into. If provided it is used to
    render a code frame (similar to how babel-loader and css-loader do).
  • hideStack?: booleanoptional, default false, a boolean flag which
    indicates that webpack shouldn't render stack trace. Note that hideStack
    already works but is undocumented.

With presence of such structured error messages Webpack could render errors in a
consistent way:

ERROR in {moduleName}
${err.name}: ${err.reason}

  ${err.loc ? formatCodeFrame(source, err.loc.line, err.loc.column) : ''}

Note that moduleName and source are available to Webpack already.

Also webpack could provide plugin hooks for different error reporting UIs.

Example of loader API usage:

try {
  return babelTransform(source)
catch (internalError) {
  // only normalize known errors
  if (internalError instanceof BabelSyntaxError) {

    let error = new Error()

    // readable name of the error type
    error.name = 'Syntax error';

    // strip filename from here if needed or use some other property
    error.reason = internalError.message;

    // location
    error.loc = internalError.location;

    // stack trace from parser isn't useful for end users
    error.hideStack = true;

    throw error;

  // throw all other errors as-is
  } else {
    throw internalError;
  }
}

Alternative solutions

Such work could be done by loaders themselves (normalizing message property
and formatting code frames). But:

  1. This is more fragile as it is easy to drift away from
    consistence if error appearance would be controlled separately by loaders.
  2. Loader will have to do more to get better error reporting.
  3. Webpack provides UI but leaves error reporting UI to loaders. This leads to
    inconsistent developer experience.

I made the following PRs to loaders:

But I believe if we enhance error reporting API it would be a much cleaner
solution.

Also see what create-react-app is doing: we can get rid of this with this proposal & a couple of PRs to loadrs too.

@bebraw bebraw added the enhancement label Aug 16, 2016
@TheLarkInn
Member

Did we discuss we would want loader name reported as well?

@andreypopp
Contributor

@TheLarkInn yep, totally. Webpack is already aware of that info: it could print loader request.

@TheLarkInn
Member

💯. A nice to have but can this be architected as a default template? That can be plugged into? Or enforce the default error layout. I'm okay with either decision.

@andreypopp
Contributor

@TheLarkInn as I understood current webpack UI isn't written with plugins in mind (only compiler allows plugins). I think the first step would be to improve on default UI and only then modify it to allow plugins.

@dmitriid
dmitriid commented Nov 2, 2016

Also:

  • an error in loader:
    -- should not pollute output with stacktraces from loader
    -- should not pollute output with stacktraces from webpack
  • an error reported by loader:
    -- should be clearly shown as produced by the loader
  • an error reported by webpack:
    -- should be clearly shown as produced by webpack
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment