Hashing assets when server-side rendering

Webpack can generate hashes for every bundle that it outputs. If you use that hash in your bundle filenames, it gives you a way to safely serve your bundles with long-term cache headers. This is something the Rails world has done for many years to avoid some of the issues around long-term caching:

If there are no digests in the filenames, and far-future headers are set, remote clients will never know to refetch the files when their content changes.

Adding hashes to filenames requires a single-line configuration change to your Webpack config. In the output section, instead of:

Webpack Configuration

output: {
  filename: "[name].js",
}

use:

output: {
  filename: "[name].[chunkhash].js",
}

You could use [hash] instead, but generally that has some caveats around unexpected hash changes - a big problem if you're trying to avoid expiring all of your assets each time you build.

What about providing a map of bundle names to their hashed counterparts? That can be useful on the server when trying to match a route to a specific bundle. There are a few different options out there, but I like the "Manifest Plugin". Use it like this:

Webpack Configuration

...
const ManifestPlugin = require('webpack-manifest-plugin');
...
module.exports = {
  ...
  plugins: [
    new ManifestPlugin({
      map(file) {
        file.name = file.chunk.name;
        return file;
      }
    })
  ],
  ...
};

That will output a file named "manifest.json" in the bundle output directory, with contents similar to:

JSON

{
  "homepage": "homepage.98ead8bdd620bf142c80.js"
}

Now if you import that JSON file into your server code, you'll be able to determine the compiled asset name for any bundle.