[chunkhash] doesn’t change if Uglify output changes

@scinos and I have collaborated on webpack-plugin-hash-output, which is working in our production environment without issues. See the discussion below for more details.

Original Ticket

This is a bug affecting long-term caching with CDNs.

During a recent dependency upgrade, webpack’s Uglify dependency moved from 2.8.10 to 2.8.25, which produces slightly different output.

The issue is that [chunkhash] doesn’t appear to actually hash the final file:

# Uglify 2.8.25
$ cat 4-c1bcb6390594024c54d3.js | md5
480d9646348a0cca88088c3755c54fd4
$ head -c 100 4-c1bcb6390594024c54d3.js
webpackJsonp([4],{963:function(e,a,n){!function(a,n){e.exports=n()}(0,function(){"use strict";return

Now, before the upgrade:

# Produced using Uglify 2.8.10 - manually appended `-old` to name
$ cat 4-c1bcb6390594024c54d3-old.js | md5
0103f905d3620c8af106ab46b50f9ab9  # Different hash, same chunkhash!
$ head -c 100 4-c1bcb6390594024c54d3-old.js
webpackJsonp([4],{963:function(e,a,n){!function(a,n){e.exports=n()}(this,function(){"use strict";ret

Notice the two bundles have the same [chunkhash] but different contents; specifically, uglify 2.3.25 uses (0,function rather than (this,function.

This caused a production application to load an outdated file from a CDN which then did not match subresource integrity and failed to load.

This is Node 6.10.2, Webpack 2.3.3, Uglify versions as above. I was not using NamedModulesPlugin or ChunkManifestPlugin, but I am using UglifyJsPlugin and CommonsChunkPlugin.

Resolution

The crux of the issue is that webpack/lib/Compilation.js runs hashing before optimization, which means that two different-optimized files will have the same hash.

After some work with this issue, I’ve discovered two major reasons why it’s difficult for [chunkhash] to actually equal the hash of the file:

  1. Appending a //# sourceMappingURL changes the hash, but requires the hash to determine the name of the sourceMap file (this is not a huge deal), and
  2. Chunking requires the name of the module. For this reason, the main chunk (with the manifest) must be processed after all other files so that its manifest is correct, then optimized, then hashed.

I have a work-in-progress plugin at https://gist.github.com/STRML/a9c393c9b43d726663d212600fd81320

Update: (19/5/2017): If you’ve read this far, use https://www.npmjs.com/package/webpack-plugin-hash-output which fixes this issue.

Author: Fantashit

3 thoughts on “[chunkhash] doesn’t change if Uglify output changes

  1. Wow… this is a big deal.
    I have been using [chunkHash] without this plugin with Angular 2/4 and sometimes all indexes were changed but the hashes stayed exactly the same.

    I was debugging why the chunks were loading successfully but the loadChildren mechanism in the router was crashing in Angular code.

    CDN or no CDN, this is a major issue to me. The patch is the key.

  2. This is still a bug.

    To reproduce, simply twiddle global_defs, like so:

    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          global_defs: {
            DEBUG: 'foobarbaz',
          }
        }
      },
    }

    Then compile a module:

    console.log(DEBUG);

    Notice that no matter what you change the value of the global to, the hash of the chunk is the same.

Comments are closed.