Spec-Zone.ru › webpack 5

Кэширование

подсказка

Примеры в этом руководстве взяты из начального руководства, управления выводом и разделения кода.

Итак, мы используем 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 включает некоторые вспомогательные файлы, в частности, исполняемую среду и манифест, в блоке входа.

предупреждение

Вывод может отличаться в зависимости от вашей текущей версии 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API