Кэширование
Примеры в этом руководстве взяты из начального руководства, управления выводом и разбиения кода.
Итак, мы используем webpack для сборки нашей модульной программы, что даёт нам каталог для развёртывания /dist. После того, как содержимое /dist будет развернуто на сервере, клиенты (обычно браузеры) обратятся к этому серверу для получения сайта и его ресурсов. Последний шаг может занять много времени, поэтому браузеры используют технику, называемую кэшированием. Это позволяет сайтам загружаться быстрее с меньшим количеством ненужных сетевых запросов. Однако это также может вызвать проблемы, когда требуется загрузка нового кода.
Это руководство фокусируется на настройке, необходимой для обеспечения того, чтобы файлы, созданные webpack, оставались в кэше, если их содержимое не изменилось.
Имена выходных файлов
Мы можем использовать output.filename подстановки для определения имён выходных файлов. webpack предоставляет способ шаблонизации имён файлов с использованием скобочных строк, называемых подстановками. Подстановка [contenthash] добавит уникальный хеш, основанный на содержимом ресурса. Когда содержимое ресурса меняется, [contenthash] также изменится.
Давайте настроим наш проект, используя пример из начального руководства с plugins из управления выводом, чтобы нам не приходилось вручную поддерживать файл index.html.
project
webpack-demo |- package.json |- webpack.config.js |- /dist |- /src |- index.js |- /node_modules
webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
// new CleanWebpackPlugin(['dist/*']) for < v2 versions of CleanWebpackPlugin
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
- title: 'Output Management',
+ title: 'Caching',
}),
],
output: {
- filename: 'bundle.js',
+ filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
}; Выполнение нашей команды сборки, 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 включает определённый шаблон, в частности, runtime и manifest, в пакет начального модуля.
Результат может отличаться в зависимости от вашей текущей версии webpack. Более новые версии могут не иметь всех тех же проблем с хэшированием, что и некоторые более старые версии, но мы по-прежнему рекомендуем выполнить следующие шаги для безопасности.
Извлечение вспомогательного кода
Как мы узнали в разбиении кода, SplitChunksPlugin можно использовать для разделения модулей в отдельные пакеты. webpack предоставляет функцию оптимизации для разделения кода runtime в отдельный пакет с помощью параметра optimization.runtimeChunk. Установите его в значение single для создания одного пакета runtime для всех пакетов:
webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
// new CleanWebpackPlugin(['dist/*']) for < v2 versions of CleanWebpackPlugin
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Caching',
}),
],
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
+ 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 { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
// new CleanWebpackPlugin(['dist/*']) for < v2 versions of CleanWebpackPlugin
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Caching',
}),
],
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
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 |- 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 с параметром 'hashed':
webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
// new CleanWebpackPlugin(['dist/*']) for < v2 versions of CleanWebpackPlugin
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Caching',
}),
],
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
optimization: {
+ moduleIds: 'hashed',
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 в имени файла пакета vendor.
Заключение
Кэширование может быть сложным, но выгода для пользователей приложения или сайта делает это стоящим усилий. См. раздел Дополнительные материалы ниже, чтобы узнать больше.
© JS Foundation and other contributors
Licensed under the Creative Commons Attribution License 4.0.
https://v4.webpack.js.org/guides/caching