Webpack 5, кеш и его проблемы
В посте про пайплайн Авиасейлс я кратко рассказывал о том, за счет чего мы так сильно ускорили пайплайн. Сегодня подробней расскажу про кеш вебпака и сторибука.
Сам по себе, кеш в вебпаке появился достаточно давно: 5 альфа версия вышла почти 3.5 года назад, а офицальный релиз пару лет назад. Но судя по всему, это достаточно непопулярная (а зря) фича, т.к. в процесе настройки я столкнулся с достаточно базовыми проблемами.
1. Кеширование по относительным путям
Вебпак использует абсолютные пути для кеширования. Т.е. кеш для модуля будет записан как
2. Инвалидация кеша при использовании import/require.ensure
Тут всё немного проще: кеш инвалидровался на динамических импортах типа
3. Ре-экспорты из пустого файла в сочетании с опцией usedExports
Кажется, что этот пункт будет объяснить сложнее всего, но я попробую. В вебпаке есть опция optimization.usedExports. Она отвечает за три-шейкинг, т.е. определяет какие экспорты из модуля действительно используются и маркирует их, позволяя не тащить неиспользуемые в бандл.
А в сторибуке активно используется ре-экспорт модулей, чтобы импортировать модули было удобней. Но есть модули, в которых лежат только типы и при компиляции в JS такой модуль получается пустым. Если взглянуть на пул-ревест, то станет понятней о каком кейсе идёт речь.
В итоге сочетание usedExports и ре-экспортов из пустых модулей вело к инвалидации. Этот баг тоже уже починили.
4. webpack-virtuals-modules не совместим с кешом
Сторибук использует webpack-virtuals-modules. Этот плагин позволяет создавать файлы в оперативной памяти, а вебпак видит их как обычные модули. Надо ли говорить, что оно плохо работает с кешом? Непредсказуемые инвалидации, двойные компиляции и т.д. На самом деле тут даже несколько проблем: раз, два, три.
Но для начала давайте разберемся зачем оно в принципе нужно. Сторибук использует этот плагин, чтобы на основе шаблонов сгенерировать точки входа, которые зависят от текущей конфигурации (путей до сторис, фреймворка и т.д.). Генерация файла происходит в памяти, ничего на диск не попадает, пользователям не нужно ничего добавлять в .gitignore и т.д. Всё просто и красиво.
Но команда webpack не рекомендует использовать такие плагины в принципе. По этой причине мы решили избавиться от этого плагина: каждый билд мы пробегаемся по опциям этого плагина и просто сохраняем файлы на диск. Вроде как, в сторибуке была инициатива об уходе от использования этого плагина, но я найти её не смог.
В посте про пайплайн Авиасейлс я кратко рассказывал о том, за счет чего мы так сильно ускорили пайплайн. Сегодня подробней расскажу про кеш вебпака и сторибука.
Сам по себе, кеш в вебпаке появился достаточно давно: 5 альфа версия вышла почти 3.5 года назад, а офицальный релиз пару лет назад. Но судя по всему, это достаточно непопулярная (а зря) фича, т.к. в процесе настройки я столкнулся с достаточно базовыми проблемами.
1. Кеширование по относительным путям
Вебпак использует абсолютные пути для кеширования. Т.е. кеш для модуля будет записан как
/some/abosulte/path/project/src/module.ts
, а не относительный src/module.ts
. Из-за этого становится невозможно шарить кеш между разными машинами разработчиков, но вы вряд ли хотите это делать. Но так же это становится проблемой в некоторых CI. Jenkins (а мы используем именно его), например, использует пути /home/jenkins/agent/workspace/$PROJECT_NAME_$GIT_BRANCH
. Т.е. на каждую ветку мы получаем новую директорию и кеш перестаёт работать. Такой подход удобен, когда у вас есть некий общий хост (например какой-нибудь Mac mini для сборки iOS приложения) и для каждой ветки нужна отдельная директория, т.к. это самый дешевый способ изоляции билдов. В случае веб-разработки почти везде используется докер и это разделение становится бесмыссленым. Благо, в каждом CI пути можно настроить (в дженкинсе это customWorkspace) и это решает проблему. В самом вебпаке всё решили оставить как есть, т.к. относительные пути для кеша будут сильно влиять на перформанс.2. Инвалидация кеша при использовании import/require.ensure
Тут всё немного проще: кеш инвалидровался на динамических импортах типа
import(`./flags/${country}.svg`)
. Особенно неприятно становится, когда такие импорты где-то в самом начальной точке графа зависимостей. Например, в storybook используются require.ensure (это такой webpack-specific модуль, который придумали ещё до import()) для импорта сторис прям в точке входа, что делало кеш особенно бесполезным, т.к. рекомпилировалось всё и вся. Этот баг уже починили.3. Ре-экспорты из пустого файла в сочетании с опцией usedExports
Кажется, что этот пункт будет объяснить сложнее всего, но я попробую. В вебпаке есть опция optimization.usedExports. Она отвечает за три-шейкинг, т.е. определяет какие экспорты из модуля действительно используются и маркирует их, позволяя не тащить неиспользуемые в бандл.
А в сторибуке активно используется ре-экспорт модулей, чтобы импортировать модули было удобней. Но есть модули, в которых лежат только типы и при компиляции в JS такой модуль получается пустым. Если взглянуть на пул-ревест, то станет понятней о каком кейсе идёт речь.
В итоге сочетание usedExports и ре-экспортов из пустых модулей вело к инвалидации. Этот баг тоже уже починили.
4. webpack-virtuals-modules не совместим с кешом
Сторибук использует webpack-virtuals-modules. Этот плагин позволяет создавать файлы в оперативной памяти, а вебпак видит их как обычные модули. Надо ли говорить, что оно плохо работает с кешом? Непредсказуемые инвалидации, двойные компиляции и т.д. На самом деле тут даже несколько проблем: раз, два, три.
Но для начала давайте разберемся зачем оно в принципе нужно. Сторибук использует этот плагин, чтобы на основе шаблонов сгенерировать точки входа, которые зависят от текущей конфигурации (путей до сторис, фреймворка и т.д.). Генерация файла происходит в памяти, ничего на диск не попадает, пользователям не нужно ничего добавлять в .gitignore и т.д. Всё просто и красиво.
Но команда webpack не рекомендует использовать такие плагины в принципе. По этой причине мы решили избавиться от этого плагина: каждый билд мы пробегаемся по опциям этого плагина и просто сохраняем файлы на диск. Вроде как, в сторибуке была инициатива об уходе от использования этого плагина, но я найти её не смог.