Пробная статья!
Данная статья является пробной! Это значит, что качество содержания может оказаться низким...

Не судите строго! Путь в тысячу ли начинается с первого шага!

Есть очень популярный webpack-плагин для сборки HTML-страниц, называется он: html-webpack-plugin. Основной мотивацией этого плагина, судя по лозунгу, является "упрощение создания HTML-страниц для бандлов". В моем случае как раз это и нужно было, так как мне требовалось создать статический сайт, состоящий только из html/css/js файлов + различные ресурсы, типа картинок, шрифтов и т.п.

Попробовав этот плагин в работе, меня все устроило. Для шаблонизации я использовал Pug, но никаких проблем с этим не возникло. Рендер pug-шаблонов осуществлялся с помощью pug-лоадерa для webpack. Конфигурация плагина была достаточно простой, нужно было указать относительный путь для сгенерированного HTML-файла filename, путь до шаблона страницы template, и массив бандлов chunks, которые должны быть вставлены в страницу.

Пример конфигурации:
new HtmlWebpackPlugin({
    filename: 'relative/path/to/file.html',
    template: '/path/to/template.pug',
    chunks: ['chunk1', 'chunk2']
});

На выходе мы получали готовые HTML-страницы с уже прописанными страничными бандлами. Но, по непонятной мне причине, создание одной страницы занимало слишком много времени, что-то около 3000мс. Чем больше становилось страниц, тем дольше приходилось ждать сборку. Это меня никак не устраивало, так как в случае статических сайтов, количество страниц постоянно растет!

До такой картины дошло дело, когда в моем сайте было 34 страницы. Сборка занимала почти 2 минуты...
До такой картины дошло дело, когда в моем сайте было 34 страницы. Сборка занимала почти 2 минуты...

Почитав статьи по ускорению сборки, я обнаружил, что можно распараллелить этот процесс. То есть в зависимости от возможностей вашего процессора, будет запущенно несколько параллельных процессов для сборки. Таким образом, если у вас 6-ядерный процессор, то теоретически, вы можете ускорить сборку в 6 раз. Первой попыткой был thread-loader, но результата от этого лоадера я, к сожалению, не получил, уже даже не помню почему... Благо в статьях я наткнулся на плагин happypack. С помощью happypack мне удалось сократить время сборки примерно в 3,5 раза, что не могло не радовать!

Время сократилось примерно в 3,5 раза. Я ожидал 6-кратного ускорения (6-ядерный процессор), но все же издержки создания отдельных процессов взяли свое...
Время сократилось примерно в 3,5 раза. Я ожидал 6-кратного ускорения (6-ядерный процессор), но все же издержки создания отдельных процессов взяли свое...

Однако, общее время сборки напрямую зависело от количества страниц, а на генерацию каждой страницы до сих пор уходило от 500 до 1000 миллисекунд. То есть 100 страниц => 100 секунд, 1000 страниц => 1000 секунд. Очевидно, что с такими цифрами возникает вопрос о целесообразности выбранного способа генерации сайта, но мне не хотелось отказываться от webpack и я не мог смириться с тем, что на простой рендер pug-шаблона уходит столько времени! Погружаться в исходники плагина html-webpack-plugin не хотелось, поэтому я искал ему замену.

И тут я встретил в документации вебпака упоминание об одном совсем непопулярном плагине, назывался он htmls-webpack-plugin. Разница в названиях лишь в одной букве: htmlS-.... Фичи плагина внушали надежду:

  • Простой и гибкий, вы можете контролировать все, что угодно, не нужно настраивать множество плагинов;
  • Поддержка множественной сборки HTML по-умолчанию;
  • Быстрый, почти в 20 раз быстрее html-webpack-plugin для 20+ страниц.

Пример конфигурации:
new HtmlsWebpackPlugin({
	htmls: [{
	    src: '/path/to/template.pug',
	    filename: 'relative/path/to/file.html',
	    render: (file, params) => {
		    return pug.renderFile(file, params);
		}
	}]
});

После интеграции и проверки, мои ожидание оправдались, скорость сборки сократилась еще в 5 раз! Теперь генерация одной страницы занимала всего около 170мс – в основном, это время тратилось на генерацию HTML из pug-шаблона с помощью pug.renderFile(). Но, к сожалению, процесс генерации выпал из loader-флоу и happypack не мог оптимизировать этот процесс... То есть параллельная сборка шаблонов на данный момент не работала.

Для распараллеливания в данном подходе я решил воспользоваться npm-пакетом worker-farm. Разработчик htmls-webpack-plugin предусмотрел асинхронный режим рендера HTML, что позволило легко организовать ферму pug-рендеров, которые также, как с happypack, параллельно, в несколько потоков, генерировали HTML. Прирост скорости оказался почти 2-кратным, что снизило время необходимое для сборки одной HTML-страницы до заветных 100мс.

Мы приблизились к заветным 100мс на страницу!
Мы приблизились к заветным 100мс на страницу!

Заключение

Таким образом, в итоге, я сократил сборку одной страницы с изначальных 3000мс, до 100мс, что очень хороший результат по-моему. Если вам и этого мало, в таком случае можно либо поискать более быстрый шаблонизатор (возможно Pug не самый быстрый, не сравнивал), либо вообще работать с чистым html!

Сводная таблица результатов для 34 страниц.
Сводная таблица результатов для 34 страниц.
Нюансы:
  • Так как мы собственноручно занимаемся созданием HTML-страниц, webpack теперь ничего не знает о наших шаблонах. К чему это ведет:
    1. При изменении именно файлов шаблонов, необходимо перезапустить сборку, потому что сама она не отловит факт изменения файла и HMR не сработает;
    2. В режиме разработки нужно кэшировать сгенерированный HTML, чтобы при изменении файлов сборки (js/css и т. п.) заново не рендерить шаблоны, которые не изменились. В продакшн-билде кэш не нужен.
  • Ради интереса я провел стресс-тест своей конфигурации. Сборка 1088 страниц заняла 1 минуту 27 секунд, то есть время сборки одной страницы снизилось до рекордных 80мс! Но последующее увеличение страниц прироста больше не дало. Сборка 2176 страниц заняла 3 минуты и те же 80мс на одну страницу... Видимо это все на что был способен мой процессор!
Версии:
{
    "webpack": "4.41.2",
    "html-webpack-plugin": "3.2.0",
    "htmls-webpack-plugin": "1.0.9"
    "happypack": "5.0.1",
    "worker-farm": "1.7.0"
}
Лучшие статьи
Программирование