Vendor chunkhash changes when app code changes

I’m trying to split my vendor code from my app code and got it all working. However, every time I change some code in my app and create a new build, the vendor file gets a new chunkhash and thus is downloaded by the clients again. The contents are exactly the same though.

Here is a fully working small example showing the problem: https://github.com/kevinrenskers/chunkhash-problem

And as you can see, the contents of these files are 100%% identical even though the chunkhash keeps changing:

screen shot 2015-07-30 at 22 47 59

Author: Fantashit

13 thoughts on “Vendor chunkhash changes when app code changes

  1. But if the contents of the vendor file don’t change then its hash shouldn’t change right? How else are we supposed to have long term caching if the filename changes every time I make a change in my app code?

  2. I don’t really understand. Isn’t the whole point of chunk-manifest-webpack-plugin to remove the child chunk hashes exactly so that the contents of the entry chunk don’t change and thus its hash should stay identical? It does work like that with 1.10.1.

    Yet, you’re saying that 1.10.2 have actually fixed this rather then breaking it. So, is the chunk-manifest-webpack-plugin doing something wrong? Or webpack? Or in other words, how am I supposed to have a working setup where changing the app code does not change the vendor’s file name? 馃檪 Like I said it seems to work with 1.10.1 but your comments confuse me..

    Are you able to get such a setup working with the latest webpack, as I’ve tried in the example project (linked above)?

  3. This all seems a little broken to me. Shouldn’t the hash be applied at the file level instead of the chunk level? If a chunk produces an app.js and an app.css, I don’t care if the chunk changed. I care if app.js and/or app.css files changed, because this ultimately determines if the client needs a new copy.

  4. Hmm, not seeing this behavior in my toy example. are you using OccurenceOrderPlugin ?
    My plugin list:
    new webpack.optimize.CommonsChunkPlugin({
    name: ‘vendor’,
    minChunks: Infinity
    }),
    new webpack.optimize.DedupePlugin(),
    new ManifestPlugin(),
    new ChunkManifestPlugin({
    filename: ‘chunk-manifest.json’,
    manifestVariable: ‘webpackManifest’
    }),
    new ChunkManifestPluginWriter(),
    new WebpackMd5Hash(),
    new ManifestPlugin(),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin({
    compress: {
    warnings: false
    }})

    Hack to get around watch not triggering :
    // Force output chunk-manifest after each build.
    // TODO: figure out bug chunk-manifest-webpack-plugin that makes it miss
    // webpack watches
    class ChunkManifestPluginWriter {
    apply(compiler) {
    compiler.plugin(’emit’, (compilation, compileCallback) => {
    const stats = compilation.getStats().toJson();
    const result = {};
    stats.assets.filter((asset) => {
    return asset.name.endsWith(‘.js’) & (asset.chunks[0] > 0);
    }).forEach((asset) => {
    result[String(asset.chunks[0])] = asset.name;
    });
    compilation.assets[‘chunk-manifest.json’] = new RawSource(JSON.stringify(result));
    compilation.mainTemplate.plugin(‘require’, (_, chunk, hash, chunkIdVar) => {
    return _.replace(‘”CHUNK_MANIFEST“‘,
    ‘window[“webpackManifest”][‘ + chunkIdVar + ‘]’);
    });
    compileCallback();
    });
    }
    }

  5. The saga continues…

    I followed the official documentation on caching and it (thankfully) works fine. Then I added UglifyJS for tree shaking and compression, the output files themselves changed but the hashes didn’t. That was surprising to me, since it can lead to complications (you minify but clients don’t receive the new files since hashes don’t change.)

    Found out that chunkhash with the recommended method does the hashing before any other optimisations (like the ones done by UglifyJS.)

    Then I found this: #4659

    The proposed webpack-plugin-hash-output plugin seems to work, it does the hashing on top of the processed output (as far as I can understand) and seems to solve the issue… For now.

    It’s plugins on top of plugins on top of plugins at this point and I’ve been burned by this so many times over the years. Just when you think it all works, you change one config and it all crashes and burns until you add yet another plugin. The process is so so brittle.

    Maybe this is not the right place but after all these years I’m convinced that this won’t get any better, and the design is fundamentally flawed for this type of thing. Are there any commonly used solutions for long term caching outside of webpack? Like using webpack just for the vanilla bundling, and then something else goes through the HTML and linked resources to hash them separately and change the references in files?

    In any case, if webpack-plugin-hash-output is the recommended solution now, is it worth adding to the documentation? The current documentation is leading people down a dangerous path (i.e. if they add anything to the plugin chain that processes / changes the files, the hashes won’t change and at best people will waste their time diagnosing the issue like I did.)

  6. earslap, I hear what you’re saying, but it just reminds me of (https://nolanlawson.com/2017/03/05/what-it-feels-like-to-be-an-open-source-maintainer/).

    To answer your question, perhaps the best way to minimize the danger of getting burned by this type of thing, you should cache for a shorter amount of time. That way, if they accidentally cache the non-minimized version, it won’t stay cached forever.

    Sorry, I can’t offer you more, but at least it’s better than nothing. Patches are certainly welcome.

  7. Oh no, I wasn’t trying to put a blame on anyone involved with this project, sorry if my frustration made it sound that way.

    I still think this is a fundamental design issue with the way webpack is architected. Brightest minds working on this deceptively simple issue for 2.5+ years, coming up with various solutions but none sticks. I don’t know much about the internals of webpack but I assume something in there makes this extremely tricky.

    If you strip all my frustrations from my earlier post, the meat should have been this: The documented method of cache busting (which I think summarises a happy path gathered from the discussions in this thread the past 2.5 years) will not work if any other plugin modifies the files along the way due to a config change, the hashes won’t change – and that is dangerous (worse than hashes changing when they shouldn’t as this can actually break things.) If my understanding is correct, there is a proposed solution that tries to fix this (here: #4659). Is this recommended, and if so should that be added to the documentation?

  8. Just named the vendor can solve this problem 馃槅

    code:

    路路路
    new webpack.optimize.CommonsChunkPlugin({
          names: 'vendor',
          minChunks: Infinity,
          filename: 'vendor.bundle.js',
     })
    路路路
    
  9. @earslap if your cache does not invalidate when the contents of a file changes than perhaps you should look into fixing that.

    Personally, I don’t understand the obsession with using hashes in file names. There are far more simple, and easy to use methods of versioning files, and cache busting. This really isn’t even an issue in webpack’s wheel house to solve for you.

    I feel like this is not something the webpack maintainers should worry about. This is not really webpack’s role to fill.

  10. @maksimsemenov ~

    First off we didn’t get this working as intended, this issue is still open.

    Basically we found that the vendor file has a reference of the app.js and that caused an error breaking JS.

Comments are closed.