Найти в Дзене

Правила wb-rules и Rollup: удаляем лишний код

Деление проекта на правила и модули позволяет сформировать в модулях набор функций на все случаи жизни, охватив большинство типовых ситуаций. Если покрыть этот набор юнит-тестами, то можно в любой момент времени гарантировать, что ни один алгоритм не отклонился от своего изначального замысла: Обычно пожелания клиента задействуют лишь часть возможностей, поэтому при установке правил на контроллер многие модули остаются не у дел - кто-то решил обойтись без многоканальных счётчиков электроэнергии, а кому-то достаточно автоматизаций, ориентированных на управление освещением. Что, если бы существовал инструмент, способный готовить для отправки на контроллер Wirenboard только задействованный код? Для выключения модулей понадобится сформировать граф связей и отследить, какие части кода никогда не будут выполнены в текущем проекте. В действительности, такие инструменты существуют и называются сборщиками модулей или бандлерами (Module Bundler). При этом, процесс удаления лишнего кода носит назв
Оглавление

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

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

Что, если бы существовал инструмент, способный готовить для отправки на контроллер Wirenboard только задействованный код? Для выключения модулей понадобится сформировать граф связей и отследить, какие части кода никогда не будут выполнены в текущем проекте.

В действительности, такие инструменты существуют и называются сборщиками модулей или бандлерами (Module Bundler). При этом, процесс удаления лишнего кода носит название Tree-Shaking.

Разумеется, функционал бандлеров не ограничивается одной лишь «тряской деревьев». Остальное задействуем по мере выхода новых статей. Подпишитесь, чтобы не пропустить - будет интересно!

После изучения различных систем сборки, следует отметить - многие из них либо слишком ориентированы на web-разработку, либо очень сложны в настройке.

Первоначально должна была выйти статья о Webpack, однако на его опциях и плагинах можно спокойно защитить пару пространных диссертаций. Наши исследования носят сугубо прикладной характер, поэтому на первое место вышел сборщик под названием Rollup. Работу с ним и рассмотрим далее.

Устанавливаем и настраиваем Rollup

В открытом проекте, созданном по материалам прошлых статей, запустим терминал VS Code и выполним команду

yarn add --dev rollup @rollup/plugin-multi-entry rollup-plugin-delete

Это добавит сборщик Rollup и его плагин, позволяющий разделить файлы в папке wb-rules на независимые точки входа. Другой плагин под названием plugin-delete, применяется для очистки целевой директории от прежних файлов.

Следом выполним команду

yarn add --dev tslib @rollup/plugin-typescript

Это даст возможность работы с кодом на языке TypeScript.

ℹ️ На заметку: отдельного внимания заслуживает плагин минификации @rollup/plugin-terser, позволяющий проводить глубокую оптимизацию результирующего кода. Однако, до него ещё дойдёт черёд - сейчас конвейер сборки настроен на совместимость с правилами wb-rules 2.0, которые крутятся на ECMAScript 5, а Babel перекрывает результат работы плагина.

Конфигурация сборщика модулей

В корень проекта добавим файл с именем rollup.config.mjs - он определит, как именно Rollup будет работать с кодом правил.

Первыми строками импортируем плагины:

import multi from '@rollup/plugin-multi-entry'
import typescript from '@rollup/plugin-typescript'
import del from 'rollup-plugin-delete'

Следом экспортируем объект конфигурации:

export default {
input: ['src/wb-rules/*.ts'],
plugins: [
multi({ preserveModules: true }),
typescript(),
del({ targets: ['build/*', 'dist/*'] })
],
output: {
format: 'es',
dir: 'build',
preserveModules: true
}
}

Здесь директивой input задаём шаблон для поиска файлов правил wb-rules в каталоге src/wb-rules. Папку с модулями не указываем намеренно - тогда файлы из неё считаются зависимостями, подлежащими анализу на предмет лишнего кода.

Следом перечисляем плагины, выполняющие обработку кода - здесь используется разделение точек входа и плагин для работы с TypeScript.

В настройках выхода результирующего кода обозначаем формат сборки "ES" и целевую директорию build - в неё будем помещать сырой код, подлежащий доводке для совместимости с контроллером Wirenboard (понадобится применить к нему tsc-alias для удаления лишней части путей при разрешении модулей и Babel для конвертации в ECMAScript 5).

Готовая конфигурация Rollup
Готовая конфигурация Rollup

Оптимизация конфигурации Babel

Поскольку @rollup/plugin-multi-entry создаёт в папке build лишнюю директорию _virtual, для того чтобы Babel не тащил её в код для отправки на контроллер, откроем в корне проекта его конфигурацию babel.config.json и добавим исключение из обработки:

{
"ignore": ["*/_virtual"],
"presets": ["@babel/preset-env"]
}

Настройка команды сборки проекта

Перейдём в файл package.json и найдём в секции scripts конвейерную команду build. Заменим её содержимое на следующее:

eslint && yarn test && rollup -c && tsc-alias && babel build -d dist

Как видно, поменялся только вызов tsc - вместо него теперь работает Rollup.

Проверяем функционирование

Перед запуском команды сборки видно, что в итоговом коде правил wb-rules сохранены все конструкции модуля, включая незадействованные:

Состояние кодов до запуска новой команды сборки проекта
Состояние кодов до запуска новой команды сборки проекта

Выполняем команду проекта build и наблюдаем, как из открытого файла dist/wb-rules-modules/example-module.js исчезли лишние функции:

Результат сборки с применением технологии Tree-Shaking
Результат сборки с применением технологии Tree-Shaking

Изменим код правила src/wb-rules/example.ts таким образом, чтобы он не обращался к модулю src/wb-rules-modules/example-module.ts - поскольку больше нет правил, ссылающихся на модуль, это приведёт к полному его удалению из целевой папки dist:

Полное исключение модуля правил из целевой папки
Полное исключение модуля правил из целевой папки

Можно заметить, что структура каталога dist поменялась - из него исчезла папка wb-rules. Это можно назвать артефактом работы плагина multi-entry и связано оно с тем, что нет ни одного модуля, позволяющего сформировать иерархию каталогов.

Напишите в комментариях, как вы обошли эту особенность?

Шаблон проекта на GitHub

Настроенный проект для разработки правил wb-rules доступен на GitHub. Код основной ветки дополнен материалами данной статьи и успешно прошёл проверку на работоспособность.

GitHub - wihome-dev/wb-rules-typescript at babel-stable

Послесловие

Использование системы сборки открывает широкие возможности для ещё большей автоматизации процесса разработки.

Основываясь на технологии Tree-Shaking, можно задействовать конфигурацию окружения и добавлять или удалять целые ветки кода, в зависимости от какого-нибудь параметра вроде

USE_MASTERSWITCH=yes

Возможно также создать различные файлы конфигураций для режимов development и production. Кроме того, настройки больше не будут разбросаны по множеству файлов правил.

Работа с конфигурациями окружения рассматривается в следующей статье из серии правил wb-rules: