<h3 dir="auto">Problem</h3>
<p dir="auto">Currently loader context provides an opaque API for error reporting: only<br>
<code class="notranslate">message</code> , <code class="notranslate">stack</code> and (undocumented?) <code class="notranslate">hideStack</code> error object<br>
properties are used to report an error to a user.</p>
<p dir="auto">Thus the appearance of error varies widely between different loaders. Babel,<br>
eslint, css, postcss, sass loaders for example all have different error<br>
reporting styles.</p>
<p dir="auto">In addition to that there's a lot of duplicated info, some loaders render<br>
filename of the module which is unnecessary as Webpack does so too and in a more<br>
concise manner (it uses request shortener).</p>
<p dir="auto">I believe this overwhelms users of Webpack and takes a lot more cognitive efforts<br>
to recognize and process errors.</p>
<h3 dir="auto">Solution</h3>
<p dir="auto">The solution I propose is to enhance error reporting API of loaders, namely:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="this.emitError(err)                     // emit error
let cb = this.async(); cb(err, result)  // emit error via cb
throw new Error(...)                    // emit error via throw"><pre class="notranslate"><code class="notranslate">this.emitError(err)                     // emit error
let cb = this.async(); cb(err, result)  // emit error via cb
throw new Error(...)                    // emit error via throw
</code></pre></div>
<p dir="auto">To accept an <code class="notranslate">Error</code> object with the following properties:</p>
<ul dir="auto">
<li><code class="notranslate">name: string</code> — name of the error. Already present on errors but is not used explicitly.</li>
<li><code class="notranslate">reason: string</code> — a human readable error message <strong>without</strong> filename of the<br>
module happened into. If not provided then <code class="notranslate">message</code> property is used as<br>
before.</li>
<li><code class="notranslate">loc?: {line: number, column: number}</code> — <em>optional default: <code class="notranslate">undefined</code></em>, a<br>
location within the module error happened into. If provided it is used to<br>
render a code frame (similar to how babel-loader and css-loader do).</li>
<li><code class="notranslate">hideStack?: boolean</code> — <em>optional, default <code class="notranslate">false</code></em>, a boolean flag which<br>
indicates that webpack shouldn't render stack trace. Note that <code class="notranslate">hideStack</code><br>
already works but is undocumented.</li>
</ul>
<p dir="auto">With presence of such structured error messages Webpack could render errors in a<br>
consistent way:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="ERROR in {moduleName}
${err.name}: ${err.reason}

  ${err.loc ? formatCodeFrame(source, err.loc.line, err.loc.column) : ''}"><pre class="notranslate"><code class="notranslate">ERROR in {moduleName}
${err.name}: ${err.reason}

  ${err.loc ? formatCodeFrame(source, err.loc.line, err.loc.column) : ''}
</code></pre></div>
<p dir="auto">Note that <code class="notranslate">moduleName</code> and <code class="notranslate">source</code> are available to Webpack already.</p>
<p dir="auto">Also webpack could provide plugin hooks for different error reporting UIs.</p>
<p dir="auto">Example of loader API usage:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="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;
  }
}"><pre class="notranslate"><code class="notranslate">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;
  }
}
</code></pre></div>
<h3 dir="auto">Alternative solutions</h3>
<p dir="auto">Such work could be done by loaders themselves (normalizing <code class="notranslate">message</code> property<br>
and formatting code frames). But:</p>
<ol dir="auto">
<li>This is more fragile as it is easy to drift away from<br>
consistence if error appearance would be controlled separately by loaders.</li>
<li>Loader will have to do more to get better error reporting.</li>
<li>Webpack provides UI but leaves error reporting UI to loaders. This leads to<br>
inconsistent developer experience.</li>
</ol>
<p dir="auto">I made the following PRs to loaders:</p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="171159796" data-permission-text="Title is private" data-url="https://github.com/babel/babel-loader/issues/287" data-hovercard-type="pull_request" data-hovercard-url="/babel/babel-loader/pull/287/hovercard" href="https://github.com/babel/babel-loader/pull/287">babel/babel-loader#287</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="171210841" data-permission-text="Title is private" data-url="https://github.com/webpack-contrib/css-loader/issues/319" data-hovercard-type="pull_request" data-hovercard-url="/webpack-contrib/css-loader/pull/319/hovercard" href="https://github.com/webpack-contrib/css-loader/pull/319">webpack-contrib/css-loader#319</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="171209935" data-permission-text="Title is private" data-url="https://github.com/webpack-contrib/postcss-loader/issues/87" data-hovercard-type="pull_request" data-hovercard-url="/webpack-contrib/postcss-loader/pull/87/hovercard" href="https://github.com/webpack-contrib/postcss-loader/pull/87">webpack-contrib/postcss-loader#87</a></li>
</ul>
<p dir="auto">But I believe if we enhance error reporting API it would be a much cleaner<br>
solution.</p>
<p dir="auto">Also see what <a href="https://github.com/facebookincubator/create-react-app/blob/25a0b66fcf480eb9361867596c1db58490f1b720/scripts/start.js#L46-L67">create-react-app is doing</a>: we can get rid of this with this proposal &amp; a couple of PRs to loadrs too.</p>
<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong></p>

<p dir="auto">I'd like to report a bug.</p>
<p dir="auto"><strong>What is the current behavior?</strong><br>
I'm having this code and I need a way to specify the public path in a dynamic fashion:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="
// main.js
__webpack_public_path__ = '/some-custom-public-path';

import css from './main.css';

// main.css
body {
  background: url(./webpack.svg);
}"><pre class="notranslate"><span class="pl-c">// main.js</span>
<span class="pl-s1">__webpack_public_path__</span> <span class="pl-c1">=</span> <span class="pl-s">'/some-custom-public-path'</span><span class="pl-kos">;</span>

<span class="pl-k">import</span> <span class="pl-s1">css</span> <span class="pl-k">from</span> <span class="pl-s">'./main.css'</span><span class="pl-kos">;</span>

<span class="pl-c">// main.css</span>
<span class="pl-s1">body</span><span class="pl-kos"></span> <span class="pl-kos">{</span>
  background: <span class="pl-en">url</span><span class="pl-kos">(</span><span class="pl-kos">.</span><span class="pl-c1">/</span><span class="pl-s1">webpack</span><span class="pl-kos">.</span><span class="pl-c1">svg</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">The problem with that is the fact that the resulting bundle does not make a correct reference to the image, with respect for <code class="notranslate">__webpack_public_path__</code>. <a href="https://webpack.js.org/configuration/output/#output-publicpath" rel="nofollow"><code class="notranslate">publicPath</code></a> does work fine, indeed.</p>
<p dir="auto"><strong>If the current behavior is a bug, please provide the steps to reproduce.</strong></p>

<p dir="auto">I've recreated the reproduction repo:<br>
<a href="https://github.com/andreiglingeanu/wugebpack-public-path-b">https://github.com/andreiglingeanu/wugebpack-public-path-b</a></p>
<p dir="auto">I've modified the resulting bundle a bit in order to print the resulting url to the console. It really does not namespace the <code class="notranslate">src</code> correctly. And when I open the <code class="notranslate">bundle/index.html</code> file in browser it's not printing the desired URL.</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="console.log(&quot;public path&quot;, __webpack_require__.p);
module.exports = __webpack_require__.p + &quot;cd0bb358c45b584743d8ce4991777c42.svg&quot;;"><pre class="notranslate"><span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">"public path"</span><span class="pl-kos">,</span> <span class="pl-s1">__webpack_require__</span><span class="pl-kos">.</span><span class="pl-c1">p</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-smi">module</span><span class="pl-kos">.</span><span class="pl-c1">exports</span> <span class="pl-c1">=</span> <span class="pl-s1">__webpack_require__</span><span class="pl-kos">.</span><span class="pl-c1">p</span> <span class="pl-c1">+</span> <span class="pl-s">"cd0bb358c45b584743d8ce4991777c42.svg"</span><span class="pl-kos">;</span></pre></div>
<hr>
<p dir="auto">A way to fix this:</p>
<p dir="auto">The resulting module for <code class="notranslate">main.js</code> is this:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="/* 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';"><pre class="notranslate"><span class="pl-c">/* harmony import */</span> <span class="pl-k">var</span> <span class="pl-s1">__WEBPACK_IMPORTED_MODULE_0__main_css__</span> <span class="pl-c1">=</span> <span class="pl-en">__webpack_require__</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">/* harmony import */</span> <span class="pl-k">var</span> <span class="pl-s1">__WEBPACK_IMPORTED_MODULE_0__main_css___default</span> <span class="pl-c1">=</span> <span class="pl-s1">__webpack_require__</span><span class="pl-kos">.</span><span class="pl-en">n</span><span class="pl-kos">(</span><span class="pl-s1">__WEBPACK_IMPORTED_MODULE_0__main_css__</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-s1">__webpack_require__</span><span class="pl-kos">.</span><span class="pl-c1">p</span> <span class="pl-c1">=</span> <span class="pl-s">'/some-custom-public-path'</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">Hope you can see how the CSS is attached to the DOM <em>before</em> assigning the <code class="notranslate">p</code> field into the <code class="notranslate">__webpack_require__</code> object, thus the namespacing is not taking place. The <code class="notranslate">publicPath</code> option <a href="https://github.com/andreiglingeanu/wugebpack-public-path-b/blob/master/bundle/main.js#L63">is attached a lot earlier</a> and that's why it works!</p>
<p dir="auto">If I'll swap those lines manually in bundle - it'll work just fine, like that!</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="
// 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__);
"><pre class="notranslate"><span class="pl-c">// first assign the webpack public path</span>
<span class="pl-s1">__webpack_require__</span><span class="pl-kos">.</span><span class="pl-c1">p</span> <span class="pl-c1">=</span> <span class="pl-s">'/some-custom-public-path'</span><span class="pl-kos">;</span>

<span class="pl-c">// then do the stuff</span>
<span class="pl-c">/* harmony import */</span> <span class="pl-k">var</span> <span class="pl-s1">__WEBPACK_IMPORTED_MODULE_0__main_css__</span> <span class="pl-c1">=</span> <span class="pl-en">__webpack_require__</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">/* harmony import */</span> <span class="pl-k">var</span> <span class="pl-s1">__WEBPACK_IMPORTED_MODULE_0__main_css___default</span> <span class="pl-c1">=</span> <span class="pl-s1">__webpack_require__</span><span class="pl-kos">.</span><span class="pl-en">n</span><span class="pl-kos">(</span><span class="pl-s1">__WEBPACK_IMPORTED_MODULE_0__main_css__</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">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?</p>
<p dir="auto">Is there a quick work-around for this till the proper fix will come?</p>
<p dir="auto"><strong>Please mention other relevant information such as the browser version, Node.js version, Operating System and programming language.</strong><br>
Node version: <code class="notranslate">v6.0.0</code> on OS X<br>
Webpack version: <code class="notranslate">Version: webpack 2.2.0-rc.0</code></p>
<p dir="auto">Thank you in advance!</p>