Longterm caching

In notebook:
FrontEndMasters Webpack Deep Dive
Created at:
2017-01-04
Updated:
2017-01-05
Tags:
JavaScript Webpack libraries
The problem is now that once you update one bundle (the hash) then it will change the hash for all of the bundles. The reason is because the modules have to import one and other, so if one chunk id changes, all the other modules have to be updated to import the latest version, so in the they change too.

branch FEM/06.1-longterm-caching

​$ npm run build

For example he just inserts a ​console.log()​ in one file, and now all the chunks have a different hash value in the filename. 

Extract the id hashing

The solution is to extract the id hashing outside of the source files. Create a mapping object that references the modules that we would inline in the html file. We will use the html webpack plugin. 
We need to install this plugin in the devDependencies: 
"inline-manifest-webpack-plugin": "3.0.1",
And use it in the webpack config:
  // ****   webpack.config.babel.js   ****

/* eslint no-console:"off" */
const {resolve} = require('path')
const webpack = require('webpack')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 1. ++++ import it
const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin')
const webpackValidator = require('webpack-validator')
const {getIfUtils, removeEmpty} = require('webpack-config-utils')

module.exports = env => {
  const {ifProd, ifNotProd} = getIfUtils(env)
  const config = webpackValidator({
    context: resolve('src'),
    entry: {..},
    output: {...},
    devtool: ifProd('source-map', 'eval'),
    module: {..},
    plugins: removeEmpty([
      new ProgressBarPlugin(),
      // 2. ++++ use the plugin
      // only use it for prod
      ifProd(new InlineManifestWebpackPlugin()),
      ifProd(new webpack.optimize.CommonsChunkPlugin({
        // 3. ++-- convert to an array
        // and add manifest
        // this will create a global variable
        // in the html file for the mapping
        names: ['vendor', 'manifest'],
      })),
      new HtmlWebpackPlugin({
        template: './index.html',
        inject: 'head',
      }),
    ]),
  })
  if (env.debug) {..}
  return config
}
Finally we need to update our index.html template file. Webpack uses the EJS templating syntax. 
  <!--****  index.html    ****-->

<!doctype html>
<html lang="en" data-framework="javascript">
  <head>
    <meta charset="utf-8">
    <title>VanillaJS • TodoMVC</title>
    <!--1. ++++ add the template-->
    <%=htmlWebpackPlugin.files.webpackManifest%>
  </head>
  <body>
This is just copy paste from the dos. 

Now, the generated index.html includes the generated Webpack runtime and the mapping of the imports of the bundle files. It uses JSONP format for the mapping (if I understood correctly)

Now everything works perfectly. We can set the servers to set the cache headers to forever.