Кэширование
Итак, мы используем webpack для сборки нашей модульной программы, что приводит к каталогу /dist, готовому к развертыванию. После развертывания содержимого /dist на сервер, клиенты (как правило, браузеры) будут обращаться к этому серверу для получения сайта и его ресурсов. Последний шаг может быть длительным, поэтому браузеры используют метод, называемый кэшированием. Это позволяет сайтам загружаться быстрее с меньшим количеством ненужного сетевого трафика. Однако это также может создать проблемы, когда требуется подгрузка нового кода.
Это руководство фокусируется на настройке, необходимой для обеспечения того, чтобы файлы, сгенерированные webpack-компиляцией, оставались в кэше, пока их содержимое не изменится.
Имена файлов вывода
Мы можем использовать параметр output.filename замены, чтобы определить имена наших файлов вывода. Webpack предоставляет способ шаблонизации имён файлов с помощью скобочных строк, называемых заменами. Замена [contenthash] добавит уникальный хэш, основанный на содержимом ресурса. При изменении содержимого ресурса, [contenthash] также изменится.
Давайте настроим наш проект, используя пример из начального руководства с plugins из управления выводом, чтобы не нужно было вручную поддерживать файл %%%CODE_BLOCK_6%%:
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,
},
}; Выполнение нашей команды сборки, npm run build, с этой настройкой должно привести к следующему выводу:
...
Asset Size Chunks Chunk Names
main.7e2c49a622975ebd9b7e.js 544 kB 0 [emitted] [big] main
index.html 197 bytes [emitted]
... Как видите, имя пакета теперь отражает его содержимое (через хэш). Если мы запустим другую сборку без внесения изменений, мы ожидаем, что имя файла останется прежним. Однако, если мы запустим её снова, мы можем обнаружить, что это не так:
...
Asset Size Chunks Chunk Names
main.205199ab45963f6a62ec.js 544 kB 0 [emitted] [big] main
index.html 197 bytes [emitted]
... Это связано с тем, что webpack включает некоторые вспомогательные файлы, в частности, исполняемую среду и манифест, в блоке входа.
Извлечение вспомогательного кода
Как мы узнали в разделении кода, SplitChunksPlugin можно использовать для разделения модулей на отдельные пакеты. Webpack предоставляет функцию оптимизации для разделения кода исполняемой среды в отдельный блок с помощью параметра optimization.runtimeChunk. Установите его в значение single, чтобы создать единый пакет исполнения для всех блоков:
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',
+ },
}; Давайте запустим другую сборку, чтобы увидеть извлечённый runtime пакет:
Hash: 82c9c385607b2150fab2
Version: webpack 4.12.0
Time: 3027ms
Asset Size Chunks Chunk Names
runtime.cc17ae2a94ec771e9221.js 1.42 KiB 0 [emitted] runtime
main.e81de2cf758ada72f306.js 69.5 KiB 1 [emitted] main
index.html 275 bytes [emitted]
[1] (webpack)/buildin/module.js 497 bytes {1} [built]
[2] (webpack)/buildin/global.js 489 bytes {1} [built]
[3] ./src/index.js 309 bytes {1} [built]
+ 1 hidden module Также рекомендуется извлекать сторонние библиотеки, такие как lodash или react, в отдельный vendor блок, так как они менее подвержены изменениям, чем наш локальный исходный код. Это позволит клиентам запрашивать ещё меньше с сервера, чтобы оставаться в актуальном состоянии. Это можно сделать с помощью параметра cacheGroups плагина SplitChunksPlugin, показанного в примере 2 SplitChunksPlugin. Добавим optimization.splitChunks с cacheGroups с последующими параметрами и выполним сборку:
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',
+ },
+ },
+ },
},
}; Давайте запустим другую сборку, чтобы увидеть наш новый vendor пакет:
...
Asset Size Chunks Chunk Names
runtime.cc17ae2a94ec771e9221.js 1.42 KiB 0 [emitted] runtime
vendors.a42c3ca0d742766d7a28.js 69.4 KiB 1 [emitted] vendors
main.abf44fedb7d11d4312d7.js 240 bytes 2 [emitted] main
index.html 353 bytes [emitted]
... Теперь мы видим, что наш main пакет не содержит vendor код из каталога node_modules и уменьшился до 240 bytes!
Идентификаторы модулей
Давайте добавим ещё один модуль, print.js, в наш проект:
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()); Запустив другую сборку, мы ожидали, что изменится только хэш нашего main пакета, однако...
...
Asset Size Chunks Chunk Names
runtime.1400d5af64fc1b7b3a45.js 5.85 kB 0 [emitted] runtime
vendor.a7561fb0e9a071baadb9.js 541 kB 1 [emitted] [big] vendor
main.b746e3eb72875af2caa9.js 1.22 kB 2 [emitted] main
index.html 352 bytes [emitted]
... ...мы видим, что все три изменились. Это связано с тем, что каждый module.id увеличивается в зависимости от порядка разрешения по умолчанию. Это означает, что при изменении порядка разрешения идентификаторы также будут изменены. Подведём итоги:
- Пакет
mainизменился из-за нового содержимого. - Пакет
vendorизменился, потому что егоmodule.idбыл изменён. - И пакет
runtimeизменился, потому что теперь содержит ссылку на новый модуль.
Первый и последний пункты ожидаемы, именно хэш vendor мы хотим исправить. Давайте используем optimization.moduleIds с параметром %%%CODE_BLOCK_45%%:
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',
},
},
},
},
}; Теперь, несмотря на новые локальные зависимости, наш vendor хэш должен оставаться постоянным между сборками:
...
Asset Size Chunks Chunk Names
main.216e852f60c8829c2289.js 340 bytes 0 [emitted] main
vendors.55e79e5927a639d21a1b.js 69.5 KiB 1 [emitted] vendors
runtime.725a1a51ede5ae0cfde0.js 1.42 KiB 2 [emitted] runtime
index.html 353 bytes [emitted]
Entrypoint main = runtime.725a1a51ede5ae0cfde0.js vendors.55e79e5927a639d21a1b.js main.216e852f60c8829c2289.js
... И давайте изменим наш src/index.js чтобы временно удалить эту дополнительную зависимость:
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()); И наконец, снова выполним нашу сборку:
...
Asset Size Chunks Chunk Names
main.ad717f2466ce655fff5c.js 274 bytes 0 [emitted] main
vendors.55e79e5927a639d21a1b.js 69.5 KiB 1 [emitted] vendors
runtime.725a1a51ede5ae0cfde0.js 1.42 KiB 2 [emitted] runtime
index.html 353 bytes [emitted]
Entrypoint main = runtime.725a1a51ede5ae0cfde0.js vendors.55e79e5927a639d21a1b.js main.ad717f2466ce655fff5c.js
... Мы видим, что обе сборки дали 55e79e5927a639d21a1b в имени файла пакета %%%CODE_BLOCK_53%%:
Заключение
Кэширование может быть сложным, но преимущества для пользователей приложений или сайтов делают его того стоит. Обратитесь к разделу «Дополнительное чтение» ниже, чтобы узнать больше.
© JS Foundation and other contributors
Licensed under the Creative Commons Attribution License 4.0.
https://webpack.js.org/guides/caching