<h2 dir="auto">Feature request</h2>
<p dir="auto"><strong>What is the expected behavior?</strong></p>
<p dir="auto">The documentation says that</p>
<blockquote>
<p dir="auto">The <code class="notranslate">[contenthash]</code> substitution will add a unique hash based on the content of an asset. When the asset's content changes, <code class="notranslate">[contenthash]</code> will change as well.</p>
</blockquote>
<p dir="auto">However, the <code class="notranslate">[contenthash]</code> does <strong>not</strong> actually match the hash of the file, i.e. the result you would get if you ran <code class="notranslate">md5sum</code> or <code class="notranslate">sha256sum</code> on the file.</p>
<p dir="auto">This <a href="https://stackoverflow.com/questions/50224845/why-is-the-contenthash-different-in-webpack" rel="nofollow">StackOverflow answer</a> explains why: the <code class="notranslate">[contenthash]</code> is computed before minification.</p>
<p dir="auto">The feature request is to compute the <code class="notranslate">[contenthash]</code> <em>after</em> minification/any other post-processing steps, or at least provide an option to do so.</p>
<p dir="auto"><strong>What is motivation or use case for adding/changing the behavior?</strong></p>
<p dir="auto">This would have nice properties, such as allowing proxies to validate the integrity of a file just by comparing its hash to the filename.</p>
<p dir="auto"><strong>How should this be implemented in your opinion?</strong></p>
<p dir="auto">Change the point in the process where the <code class="notranslate">[contenthash]</code> is computed. I don't know anything about webpack's architecture so I have no idea how hard this is.</p>
<p dir="auto"><strong>Are you willing to work on this yourself?</strong></p>
<p dir="auto">I'm not a webpack developer but if there was some guidance from an expert I could take a stab at it.</p>
<h2 dir="auto">Feature request</h2>
<p dir="auto">Please natively support output chunk hashing that is based on chunks <em>output</em> rather than their <em>input</em> (i.e., <code class="notranslate">output.filename = "[name]-[chunkhash].js"</code>).</p>
<p dir="auto"><em>Why?</em> you may ask? Because hashing is mainly used for production asset caching. Right now, there are at least three ways the content of a chunk can change, and only one of those causes the <code class="notranslate">[chunkhash]</code> value to change.</p>
<p dir="auto">When you deploy a new version of your code, you want browsers not to use old, stale assets. In theory, hashes should be based on the content of the files, such that when the files changes, the hash changes, and you can leverage the asset manifest to write out a new <code class="notranslate">&lt;script&gt;</code> or <code class="notranslate">&lt;link&gt;</code> tag with the new hash. And obviously, the advantage of <code class="notranslate">[chunkhash]</code> vs <code class="notranslate">[hash]</code> is that if you make a change that only changes a single chunk, you do not "invalidate" the cache of unchanged chunks, thus improving the performance for end users who have already downloaded unchanged chunks.</p>
<p dir="auto">Going back to those three ways a chunk's content can change:</p>
<ol dir="auto">
<li>You make a change to your entrypoint or its dependencies.</li>
<li>You make a change to the webpack config (e.g. adding/removing/changing a plugin/loader).</li>
<li>You upgrade a loader/plugin version.</li>
</ol>
<p dir="auto">Right now, only <strong>1</strong> is supported, which leaves a pretty glaring hole. You may, say, add source maps (<strong>2</strong>) only to discover that your CDN is still serving a stale version of your code without source maps because the <code class="notranslate">[chunkhash]</code> was not updated.</p>
<p dir="auto">It seems like tools like <a href="https://github.com/erm0l0v/webpack-md5-hash">https://github.com/erm0l0v/webpack-md5-hash</a> <em>may</em> address this, but this seems like a pretty huge flaw in the expected behavior out-of-the-box.</p>





<p dir="auto"><strong>What is the expected behavior?</strong></p>
<p dir="auto">The expected behavior is that when the content of a chunk changes, the hash for that chunk should change too.</p>
<p dir="auto"><strong>What is motivation or use case for adding/changing the behavior?</strong></p>
<p dir="auto">As explained above, the motivation is the principle of least surprise. Right now, it's surprising that changing configuration, which may have profound effects on the output, silently slips by as an output asset with the same name as a stale version of the asset.</p>
<p dir="auto"><strong>How should this be implemented in your opinion?</strong></p>
<p dir="auto">I think there are a few options:</p>
<ol dir="auto">
<li>Reimplement <code class="notranslate">[chunkhash]</code>, though I seem to remember reading issues about challenges with sourcemaps.</li>
<li>Implement a new token value (e.g. <code class="notranslate">output.filename = "[name]-[chunkhash]-[webpackhash].js"</code>) such that changing anything about your webpack config or its dependencies allows you to bust the cache.</li>
</ol>
<p dir="auto"><strong>Other Considerations</strong></p>
<p dir="auto">To hack around this in the mean time, I've employed a custom hashing function that uses the final JSONified value of the webpack config as hash salt:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// webpack.config.js
const config = {};

class Hasher {
  constructor() {
    const hash = require(&quot;crypto&quot;).createHash(&quot;sha256&quot;);
    hash.update(JSON.stringify(config));
    return hash;
  }
}

Object.assign(config, {
  output: {
    filename: isProd ? &quot;[name]-[chunkhash].js&quot; : &quot;[name].js&quot;,
    hashFunction: Hasher
  },
  ...
})

module.exports = config;"><pre class="notranslate"><span class="pl-c">// webpack.config.js</span>
<span class="pl-k">const</span> <span class="pl-s1">config</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span><span class="pl-kos">}</span><span class="pl-kos">;</span>

<span class="pl-k">class</span> <span class="pl-v">Hasher</span> <span class="pl-kos">{</span>
  <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">const</span> <span class="pl-s1">hash</span> <span class="pl-c1">=</span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-s">"crypto"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">createHash</span><span class="pl-kos">(</span><span class="pl-s">"sha256"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-s1">hash</span><span class="pl-kos">.</span><span class="pl-en">update</span><span class="pl-kos">(</span><span class="pl-c1">JSON</span><span class="pl-kos">.</span><span class="pl-en">stringify</span><span class="pl-kos">(</span><span class="pl-s1">config</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-k">return</span> <span class="pl-s1">hash</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span>

<span class="pl-v">Object</span><span class="pl-kos">.</span><span class="pl-en">assign</span><span class="pl-kos">(</span><span class="pl-s1">config</span><span class="pl-kos">,</span> <span class="pl-kos">{</span>
  <span class="pl-c1">output</span>: <span class="pl-kos">{</span>
    <span class="pl-c1">filename</span>: <span class="pl-s1">isProd</span> ? <span class="pl-s">"[name]-[chunkhash].js"</span> : <span class="pl-s">"[name].js"</span><span class="pl-kos">,</span>
    <span class="pl-c1">hashFunction</span>: <span class="pl-v">Hasher</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</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">config</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">This creates a custom hashing function that injects a JSONified version of the webpack config such that changes to webpack's configuration cause the hash to change. In theory, we could use <code class="notranslate">output.hashSalt</code>, but that cannot be lazily evaluated once the entire webpack config has been constructed. Furthermore, output.hashSalt does not get used for MiniCssExtractPlugin's [contenthash], but (confusingly) output.hashFunction does. Finally, this only accounts for changes in the webpack config itself—it does not account for underlying changes in plugins/loaders due to, e.g., version upgrades.</p>
<p dir="auto"><strong>Are you willing to work on this yourself?</strong><br>
Yes! But I think I need help.</p>