Issue 1:
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?: boolean — optional, 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:

This is more fragile as it is easy to drift away from

consistence if error appearance would be controlled separately by loaders.

Loader will have to do more to get better error reporting.

Webpack provides UI but leaves error reporting UI to loaders. This leads to

inconsistent developer experience.

I made the following PRs to loaders:

babel/babel-loader#287

webpack-contrib/css-loader#319

webpack-contrib/postcss-loader#87

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.

Issue 2:
Do you want to request a feature or report a bug?

I'd like to report a bug.

What is the current behavior?

I'm having this code and I need a way to specify the public path in a dynamic fashion:

// main.js
__webpack_public_path__ = '/some-custom-public-path';

import css from './main.css';

// main.css
body {
background: url(./webpack.svg);
}

The problem with that is the fact that the resulting bundle does not make a correct reference to the image, with respect for __webpack_public_path__. publicPath does work fine, indeed.

If the current behavior is a bug, please provide the steps to reproduce.

I've recreated the reproduction repo:

https://github.com/andreiglingeanu/wugebpack-public-path-b

I've modified the resulting bundle a bit in order to print the resulting url to the console. It really does not namespace the src correctly. And when I open the bundle/index.html file in browser it's not printing the desired URL.

console.log("public path", __webpack_require__.p);
module.exports = __webpack_require__.p + "cd0bb358c45b584743d8ce4991777c42.svg";

A way to fix this:

The resulting module for main.js is this:

/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__main_css__ = __webpack_require__(0);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__main_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__main_css__);
__webpack_require__.p = '/some-custom-public-path';

Hope you can see how the CSS is attached to the DOM before assigning the p field into the __webpack_require__ object, thus the namespacing is not taking place. The publicPath option is attached a lot earlier and that's why it works!

If I'll swap those lines manually in bundle - it'll work just fine, like that!

// first assign the webpack public path
__webpack_require__.p = '/some-custom-public-path';

// then do the stuff
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__main_css__ = __webpack_require__(0);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__main_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__main_css__);

Is there any specific reason for this order? Is there a way to tell compiler to insert this assignment at the begining of the current scope?

Is there a quick work-around for this till the proper fix will come?

Please mention other relevant information such as the browser version, Node.js version, Operating System and programming language.

Node version: v6.0.0 on OS X

Webpack version: Version: webpack 2.2.0-rc.0

Thank you in advance!