В этой статье я бы хотел поделиться своим опытом по разбиению бандлов для многостраничного сайта с помощью Webpack 4. Cначала создадим для каждой страницы свою точку входа. Рассмотрим на примере 4 страниц:


const path = require("path");

const PATHS = {
  src: path.resolve(process.cwd(), "src"),
  dist: path.resolve(process.cwd(), "dist")
};

module.exports = {
  entry: {
    common: `${PATHS.src}/js/common`,
    index: `${PATHS.src}/js/index`,
    contacts: `${PATHS.src}/js/contacts`,
    about: `${PATHS.src}/js/about`,
  }
}

При сборке для каждой страницы будет создан свой бандл. В точку входа common я вынес общие скрипты для всех страниц. Чтобы подключить наши бандлы на страницы воспользуемся плагином Webpack'a HtmlWebpackPlugin.


Рассмотрим на примере:


  module.exports = {
  ...
  plugins: [
    new HtmlWebpackPlugin({
      filename: `${PATHS.dist}/index.html`,
      template: `${PATHS.dist}/index.html`,
      chunks: ["index", "common"]
    })
    ...
  ]
  ...
};

В chunks указываем бандлы, необходимые для этой страницы (очередность: справа на лево). Таким образом на страницу будет подключены сначала общие скрипты, а потом скрипты необходимые отдельно для этой страницы.


Если мы имеем общие модули/сторонние библиотеки подключенные на разных страницах, создадим общие бандлы для этих страниц.


Воспользуемся Webpack плагином SplitChunksPlugin. Собственно вот конфигурация:


module.exports = {
  optimization: {
    splitChunks: {
      chunks: "all",
      minSize: 1,
      minChunks: 2
    }
  }
}

После сборки мы получим бандлы отдельно для каждой странички и бандлы, которые делят между собой наши страницы.


index.js
contacts.js
common.js
about.js
vendors~about-us~index.js
vendors~about-us~contacts.js

В бандл vendors~about-us~index.js буду вынесены общие скрипты для about-us и index, которые закешируються браузером, и при переходе со страницы index на about будут уже скачены браузером, и потребуеться только загрузить бандл about.js.


Имена чанков можно изменить в конфиге этого плагина.


Чтобы подключить эти бандлы правильно на каждую нашу странцу воспользуемся HtmlWebpackPlugin. Конфигурация та же что и в начале статьи. Только вот вам прийдеться поставить альфа версию этого плагина, потому что на момент написания статьи этот плагин не подключал наши разделенные чанки, а подключал только точки входа.


npm i --save-dev html-webpack-plugin@next

После сборки мы получим вот такой код в index.html:


<script src="js/common.js"></script>
<script src="js/vendors~about-us~index.js"></script>
<script src="js/index.js"></script>

Комментарии (4)


  1. noodles
    21.02.2019 00:38

    После сборки мы получим вот такой код в index.html:

    <script src="js/common.js"></script>
    <script src="js/vendors~about-us~index.js"></script>
    <script src="js/index.js"></script>
    



    Есть ли какой-то профит по сравнению с такой схемой:

    в index.js каждой страницы (например домашней) подключаем

    import common from 'js/common.js';
    import vendor from 'js/vendors/index.js';
    
    import module_1_ofHomePage from 'js/home/module_1.js';
    import module_2_ofHomePage from 'js/home/module_2.js';
    import module_3_ofHomePage from 'js/home/module_3.js';
    


    Один бандл, один запрос. Чуть больше объём, но без танцев с вебпаком.


    1. Machinez
      21.02.2019 20:17

      Да есть
      При таком подходе, если у тебя изменится содержимое бандла, то пользователю придется перекачивать его полностью заново на замену закэшированному.
      Обычно vendors выносят в отдельный бандл, т.к он крайне редко меняется, в отличии от кода самого приложения.


  1. Enverest
    21.02.2019 10:11

    Тоже так использую. И мне не понятно почему нельзя просто прописать entry как параметр для HtmlWebpackPlugin. Имена chunks могут меняться например при добавления нового entry, его имя будет дописывать к существующим chunks. А если бы использовался entry — мне, как пользователю плагина, не пришлось бы менять существующий код.


  1. Enverest
    21.02.2019 10:23

    И HtmlWebpackPlugin stable версии работает с чанками, просто Webpack сломал обратную совместимость на минорной версии (4.6.1). Если поставить Webpack 4.6.0 и html-webpack-plugin 3.2.0, то текущий webpack конфиг так же будет работать.