Movatterモバイル変換


[0]ホーム

URL:


webpack logo
ag grid
ag charts

Caching

tip

The examples in this guide stem fromgetting started,output management andcode splitting.

So we're using webpack to bundle our modular application which yields a deployable/dist directory. Once the contents of/dist have been deployed to a server, clients (typically browsers) will hit that server to grab the site and its assets. The last step can be time consuming, which is why browsers use a technique calledcaching. This allows sites to load faster with less unnecessary network traffic. However, it can also cause headaches when you need new code to be picked up.

This guide focuses on the configuration needed to ensure files produced by webpack compilation can remain cached unless their content has changed.

Output Filenames

We can use theoutput.filenamesubstitutions setting to define the names of our output files. Webpack provides a method of templating the filenames using bracketed strings calledsubstitutions. The[contenthash] substitution will add a unique hash based on the content of an asset. When the asset's content changes,[contenthash] will change as well.

Let's get our project set up using the example fromgetting started with theplugins fromoutput management, so we don't have to deal with maintaining ourindex.html file manually:

project

webpack-demo|- package.json|- package-lock.json|- webpack.config.js|- /dist|- /src |- index.js|- /node_modules

webpack.config.js

 const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = {   entry: './src/index.js',   plugins: [     new HtmlWebpackPlugin({-       title: 'Output Management',+       title: 'Caching',     }),   ],   output: {-     filename: 'bundle.js',+     filename: '[name].[contenthash].js',     path: path.resolve(__dirname, 'dist'),     clean: true,   }, };

Running our build script,npm run build, with this configuration should produce the following output:

...                       Asset       Size  Chunks                    Chunk Namesmain.7e2c49a622975ebd9b7e.js544 kB0[emitted][big]  main                  index.html197 bytes[emitted]...

As you can see the bundle's name now reflects its content (via the hash). If we run another build without making any changes, we'd expect that filename to stay the same. However, if we were to run it again, we may find that this is not the case:

...                       Asset       Size  Chunks                    Chunk Namesmain.205199ab45963f6a62ec.js544 kB0[emitted][big]  main                  index.html197 bytes[emitted]...

This is because webpack includes certain boilerplate, specifically the runtime and manifest, in the entry chunk.

warning

Output may differ depending on your current webpack version. Newer versions may not have all the same issues with hashing as some older versions, but we still recommend the following steps to be safe.

Extracting Boilerplate

As we learned incode splitting, theSplitChunksPlugin can be used to split modules out into separate bundles. Webpack provides an optimization feature to split runtime code into a separate chunk using theoptimization.runtimeChunk option. Set it tosingle to create a single runtime bundle for all chunks:

webpack.config.js

 const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = {   entry: './src/index.js',   plugins: [     new HtmlWebpackPlugin({     title: 'Caching',     }),   ],   output: {     filename: '[name].[contenthash].js',     path: path.resolve(__dirname, 'dist'),     clean: true,   },+   optimization: {+     runtimeChunk: 'single',+   }, };

Let's run another build to see the extractedruntime bundle:

Hash: 82c9c385607b2150fab2Version: webpack4.12.0Time: 3027ms                          Asset       Size  Chunks             Chunk Namesruntime.cc17ae2a94ec771e9221.js1.42 KiB0[emitted]  runtime   main.e81de2cf758ada72f306.js69.5 KiB1[emitted]  main                     index.html275 bytes[emitted][1](webpack)/buildin/module.js497 bytes{1}[built][2](webpack)/buildin/global.js489 bytes{1}[built][3] ./src/index.js309 bytes{1}[built]    +1 hidden module

It's also good practice to extract third-party libraries, such aslodash orreact, to a separatevendor chunk as they are less likely to change than our local source code. This step will allow clients to request even less from the server to stay up to date.This can be done by using thecacheGroups option of theSplitChunksPlugin demonstrated inExample 2 of SplitChunksPlugin. Lets addoptimization.splitChunks withcacheGroups with next params and build:

webpack.config.js

 const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = {   entry: './src/index.js',   plugins: [     new HtmlWebpackPlugin({     title: 'Caching',     }),   ],   output: {     filename: '[name].[contenthash].js',     path: path.resolve(__dirname, 'dist'),     clean: true,   },   optimization: {     runtimeChunk: 'single',+     splitChunks: {+       cacheGroups: {+         vendor: {+           test: /[\\/]node_modules[\\/]/,+           name: 'vendors',+           chunks: 'all',+         },+       },+     },   }, };

Let's run another build to see our newvendor bundle:

...                          Asset       Size  Chunks             Chunk Namesruntime.cc17ae2a94ec771e9221.js1.42 KiB0[emitted]  runtimevendors.a42c3ca0d742766d7a28.js69.4 KiB1[emitted]  vendors   main.abf44fedb7d11d4312d7.js240 bytes2[emitted]  main                     index.html353 bytes[emitted]...

We can now see that ourmain bundle does not containvendor code fromnode_modules directory and is down in size to240 bytes!

Module Identifiers

Let's add another module,print.js, to our project:

project

webpack-demo|- package.json|- package-lock.json|- webpack.config.js|- /dist|- /src |- index.js+ |- print.js|- /node_modules

print.js

+ export default function print(text) {+   console.log(text);+ };

src/index.js

 import _ from 'lodash';+ import Print from './print'; function component() {   const element = document.createElement('div');   // Lodash, now imported by this script   element.innerHTML = _.join(['Hello', 'webpack'], ' ');+   element.onclick = Print.bind(null, 'Hello webpack!');   return element; } document.body.appendChild(component());

Running another build, we would expect only ourmain bundle's hash to change, however...

...                           Asset       Size  Chunks                    Chunk Names  runtime.1400d5af64fc1b7b3a45.js5.85 kB0[emitted]         runtime  vendor.a7561fb0e9a071baadb9.js541 kB1[emitted][big]  vendor    main.b746e3eb72875af2caa9.js1.22 kB2[emitted]         main                      index.html352 bytes[emitted]...

... we can see that all three have. This is because eachmodule.id is incremented based on resolving order by default. Meaning when the order of resolving is changed, the IDs will be changed as well. To recap:

  • Themain bundle changed because of its new content.
  • Thevendor bundle changed because itsmodule.id was changed.
  • And, theruntime bundle changed because it now contains a reference to a new module.

The first and last are expected, it's thevendor hash we want to fix. Let's useoptimization.moduleIds with'deterministic' option:

webpack.config.js

 const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = {   entry: './src/index.js',   plugins: [     new HtmlWebpackPlugin({       title: 'Caching',     }),   ],   output: {     filename: '[name].[contenthash].js',     path: path.resolve(__dirname, 'dist'),     clean: true,   },   optimization: {+     moduleIds: 'deterministic',     runtimeChunk: 'single',     splitChunks: {       cacheGroups: {         vendor: {           test: /[\\/]node_modules[\\/]/,           name: 'vendors',           chunks: 'all',         },       },     },   }, };

Now, despite any new local dependencies, ourvendor hash should stay consistent between builds:

...                          Asset       Size  Chunks             Chunk Names   main.216e852f60c8829c2289.js340 bytes0[emitted]  mainvendors.55e79e5927a639d21a1b.js69.5 KiB1[emitted]  vendorsruntime.725a1a51ede5ae0cfde0.js1.42 KiB2[emitted]  runtime                     index.html353 bytes[emitted]Entrypoint main= runtime.725a1a51ede5ae0cfde0.js vendors.55e79e5927a639d21a1b.js main.216e852f60c8829c2289.js...

And let's modify oursrc/index.js to temporarily remove that extra dependency:

src/index.js

 import _ from 'lodash';- import Print from './print';+ // import Print from './print'; function component() {   const element = document.createElement('div');   // Lodash, now imported by this script   element.innerHTML = _.join(['Hello', 'webpack'], ' ');-   element.onclick = Print.bind(null, 'Hello webpack!');+   // element.onclick = Print.bind(null, 'Hello webpack!');   return element; } document.body.appendChild(component());

And finally run our build again:

...                          Asset       Size  Chunks             Chunk Names   main.ad717f2466ce655fff5c.js274 bytes0[emitted]  mainvendors.55e79e5927a639d21a1b.js69.5 KiB1[emitted]  vendorsruntime.725a1a51ede5ae0cfde0.js1.42 KiB2[emitted]  runtime                     index.html353 bytes[emitted]Entrypoint main= runtime.725a1a51ede5ae0cfde0.js vendors.55e79e5927a639d21a1b.js main.ad717f2466ce655fff5c.js...

We can see that both builds yielded55e79e5927a639d21a1b in thevendor bundle's filename.

Conclusion

Caching can be complicated, but the benefit to application or site users makes it worth the effort. See theFurther Reading section below to learn more.

Further Reading

12 Contributors

okonetjouni-kantolaskipjackdannycjonesfadysamirsadekafontcurosavagesaiprasad2595EugeneHlushkoAnayaDesignaholznersnitin315

[8]ページ先頭

©2009-2025 Movatter.jp