kimsagro
kimsagro

Reputation: 17365

Webpack long term caching

Scenario

I'm attempting to use webpack to bundle my vendor scripts separately from my application scripts.

Attempt 1

index.js

var _ = require('lodash');
console.log(_)

webpack.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

var config = {
  entry: {
    vendor: ['lodash'],
    app: './index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  plugins: [

    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      minChunks: Infinity,
    }),

    new HtmlWebpackPlugin({
        filename: 'index.html',
        inject: true
    })
  ]
};

module.exports = config;

results

                         Asset       Size  Chunks             Chunk Names
       app.3437c5da57e0c6671675.js  145 bytes       0  [emitted]  app
    vendor.72c95e21a8d7096d53bc.js     428 kB       1  [emitted]  vendor
                        index.html  232 bytes          [emitted]

Now if I make a change to index.js

index.js

var _ = require('lodash');
console.log('changed index');
console.log(_)

results

                Asset       Size  Chunks             Chunk Names
   app.c724350371b50a9afeb2.js  177 bytes       0  [emitted]  app
vendor.0e76f9c86cbe02606265.js     428 kB       1  [emitted]  vendor
                    index.html  232 bytes          [emitted]

Both hashes change even though I only updated the index file.

The difference between the two vendor files is

vendor.72c95e21a8d7096d53bc.js

script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"app"}[chunkId]||chunkId) + "." + {"0":"3437c5da57e0c6671675"}[chunkId] + ".js";

vendor.0e76f9c86cbe02606265.js

script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"app"}[chunkId]||chunkId) + "." + {"0":"c724350371b50a9afeb2"}[chunkId] + ".js";

Attempt 2

After doing some research I found the article below which explains that webpack generates a chuck manifest that contains the chunk identifiers which is placed in the entry chunk. This explains the diff above. The solution is to extract the chuck manifest to a seperate file.

https://medium.com/@okonetchnikov/long-term-caching-of-static-assets-with-webpack-1ecb139adb95

index.js

var _ = require('lodash');
console.log(_)

webpack.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');

var config = {
  entry: {
    vendor: ['lodash'],
    app: './index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  plugins: [

    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      minChunks: Infinity,
    }),

    new ChunkManifestPlugin({
      filename: "manifest.json",
      manifestVariable: "webpackManifest"
    }),

    new HtmlWebpackPlugin({
        filename: 'index.html',
        inject: true
    })
  ]
};

module.exports = config;

results

               Asset       Size  Chunks             Chunk Names
app.3437c5da57e0c6671675.js  145 bytes       0  [emitted]  app
             manifest.json   35 bytes          [emitted]
vendor.72c95e21a8d7096d53bc.js     428 kB       1  [emitted]  vendor

Now if I make a change to index.js

index.js

var _ = require('lodash');
console.log('changed index');
console.log(_)

results

               Asset       Size  Chunks             Chunk Names
app.c724350371b50a9afeb2.js  177 bytes       0  [emitted]  app
             manifest.json   35 bytes          [emitted]
vendor.0e76f9c86cbe02606265.js     428 kB       1  [emitted]  vendor

Once again both hashes change even though I only updated the index file.

This time however, there are no differences between the two vendor files

Questions

Is there a reason why the above scenario is not working or am I fundamentally approaching this problem incorrectly.

Is there is an easier way with webpack to achieve what I'm trying to do, because even if I get the step above working, I'll have to read the manifest and then inject it into my index.html page?

Upvotes: 8

Views: 2978

Answers (2)

x'ES
x'ES

Reputation: 574

Try https://github.com/zhenyong/webpack-stable-module-id-and-hash which is appears to work fine.

first buid js/app-379075f0ea0b0e0148f3.js 2.19 kB 0 [emitted] app js/react-da22e98119ee46232ff7.js 747 kB 1 [emitted] react

rebuild, only app changed js/app-fc7ca0df6dfcf7ca77f7.js 2.21 kB 0 [emitted] app js/react-da22e98119ee46232ff7.js 747 kB 1 [emitted] react

Upvotes: 0

arturkin
arturkin

Reputation: 957

It seems to be a problem with latest webpack version, please see open issue https://github.com/webpack/webpack/issues/1315

So for now you can't rely on [chunkhash], simplest solution is to use custom hash, something like <script src="vendor.js?v=001">, and change it on backend every time when you releasing.

Upvotes: 1

Related Questions