Подготовительный этап пройдён - редактор Visual Studio Code установлен, проект на рабочем компьютере создан, а синхронизация с контроллером через утилиту rsync завершилась успехом. Так было в статье из прошлого выпуска:
Сегодня речь пойдёт о самих правилах wb-rules, с концепцией которых можно ознакомиться в официальном репозитории Wiren Board на GitHub:
В классическом варианте действуют стандартные ограничения ECMAScript 5 (ES5). Однако, нам так не нравится, прочь условности: добавим типизацию, поддержку конструкций const и let, лямбда-выражений, красивого и понятного динамического импорта.
Секрет задумки прост: инструменты разработки, называемые транспайлерами, знают всё о стандартах и умеют трансформировать современный код с оглядкой на требования прошлых лет.
Добавляем TypeScript
Откроем ранее созданный проект в Visual Studio Code и продолжим его настройку. В верхнем меню редактора откроем раздел Terminal и выберем пункт New Terminal.
Появится консоль PowerShell, в которой нужно выполнить команду
yarn add --dev typescript tsc-alias
Менеджер пакетов Yarn обратится к официальным репозиториям, найдёт сведения об актуальных версиях и запишет эту информацию в файл проекта package.json, после чего создаст папку node_modules и скачает туда запрошенные инструменты вместе со всеми их зависимостями.
ℹ️ Примечание: все существующие пакеты делятся на две категории, различающиеся способом взаимодействия с кодом программы:
- dependencies - встраиваются в код и используются в процессе выполнения;
- devDependencies - применяются только на этапе разработки, как вспомогательные средства.
Библиотеки typescript и tsc-alias относятся к категории инструментов, поэтому чтобы они попали в правильную секцию, в команду добавляется ключ --dev.
Пакет typescript
Содержит компилятор tsc, который мы будем применять для генерации промежуточного кода на языке JavaScript.
Почему промежуточного? При нацеливании на соответствие стандарту ES5, компилятор накидывает лишних конструкций, с которыми не готов работать движок правил wb-rules 2.0 - поручим tsc формировать качественный код JavaScript стандарта ES6, а итоговое понижение до ES5 отдадим транспилятору Babel.
Пакет tsc-alias
Изначально подходы к подключаемым модулям у компилятора TypeScript и у движка wb-rules версии 2.0 различаются. Первому для сборки требуется указывать относительный путь, а второй просто знает каталог, где у него лежат эти файлы и ему достаточно лишь названия модуля.
Инструмент tsc-alias будем применять для того, чтобы удалить из объявлений импорта информацию о путях.
Однако, это поведение и для него является нетипичным, поэтому позже напишем собственное правило трансформации по инструкции от автора библиотеки (на английском).
Конфигурируем TypeScript
Установленные в проект инструменты, обладая огромным функционалом, почти всегда требуют настройки под задачи разработчика. Когда опций слишком много, применяют специальные файлы конфигурации.
Для компилятора TypeScript таким файлом является tsconfig.json - добавим его в корень проекта, рядом с package.json, где утилита его легко обнаружит.
На файл tsconfig.json смотрит много всякого добра - даже сам VS Code даёт определения и подсветку синтаксиса TypeScript при редактировании кода, опираясь на содержащиеся там параметры.
Чтобы всё работало согласно нашей задумке, конфигурация должна в точности соответствовать той, что представлена на скриншоте выше.
Секция compilerOptions
Используется для управления поведением компилятора.
- "target": "ES6" - нацеливает компилятор на генерацию кода по стандарту ES6;
- "outDir": "./build" - сгенерированные файлы будут складываться в папку проекта под названием build;
- "paths": { "@wbm*": ["./src/wb-rules-modules*"] } - позволяет в исходных кодах указывать компилятору не относительный путь в виде "../wb-rules-modules/module-name", а использовать компактный псевдоним вида "@wbm/module-name".
Секция include
Объясняет системе, где в проекте расположены файлы, относящиеся к TypeScript. Раздельное указание двух каталогов "src/wb-rules/*" и "src/wb-rules-modules*" позволяет воссоздать их в целевом расположении build.
Не смотря на то, что в include упоминается ещё и каталог types, в нём хранятся лишь файлы определений *.d.ts, которые мы будем применять для типизации стандартных конструкций wb-rules и автодополнения кода.
Конечно же, вручную набирать директивы определений мы не станем, там слишком много строк. Возьмём готовые файлы, которые были немного доработаны при подготовке данной статьи, чтобы VS Code не ворчал на нестыковки.
Поскольку определения *.d.ts не относятся к JavaScript, а используются лишь компилятором TypeScript (и редактором VS Code), в итоговую сборку они не попадают и каталог types не создаётся в расположении build.
Секция tsc-alias
Выступает расширением конфигурации, читается добавленным ранее инструментом tsc-alias. Здесь указываем, где лежит файл с дополнительным правилом преобразования путей подключаемых модулей.
Просмотр итоговой конфигурации
Чтобы проверить, как компилятор видит созданную конфигурацию, в консоли можно набрать команду
yarn tsc --showConfig
➡️ Примечание: поскольку пакет typescript установлен локально в проекте, то и его выполнение осуществляется через обращение к yarn.
Если в открытом файле конфигурации редактор подчёркивает волнистой линией первую скобку , ворча на include/exclude, то это лишь потому, что в указанных расположениях нет ни одного файла с расширением *.ts - позже мы это исправим.
Быстро угомонить ворчуна можно через добавление в compilerOptions директивы "allowJs": true - эта настройка позволяет, наравне с файлами TypeScript, использовать при сборке ещё и исходные файлы JavaScript. В последних не будет выполняться проверка типов, что может выручить в сложных ситуациях, когда применяется настолько хитрый код, что его логику невозможно сходу переложить на правила.
Разумеется, не стоит слишком часто пользоваться этой уловкой, иначе весь смысл использования TypeScript будет сведён к нулю.
Преобразователь путей для tsc-alias
Работая в VS Code, создадим в корне проекта папку tsc-replacers и добавим в неё файл wb-replacer.js следующего содержания:
exports.default = function moduleReplacer({ orig }) {
return orig
.replace('../wb-rules-modules/', '')
.replace(/\.js'$/i, '\'');
}
Правило простое - если при перечислении путей где-то попадётся фрагмент с упоминанием каталога wb-rules-modules, удалить этот фрагмент из строки.
Добавляем Babel
Сгенерированные компилятором tsc файлы нуждаются в финишной обработке для соответствия стандарту ES5, поэтому будем использовать специальный инструмент транспиляции.
Откроем терминал VS Code и выполним в нём команду
yarn add --dev @babel/core @babel/cli @babel/preset-env
В секцию devDependencies файла package.json будут добавлены записи об актуальных версиях перечисленных пакетов.
Потребуется создать в корне проекта файл babel.config.json и внести туда короткую конструкцию:
{
"presets": ["@babel/preset-env"]
}
В этот раз обойдёмся без сложных настроек - на первое время хватит и стандартных.
Добавляем типизацию wb-rules
Отдельной библиотеки типов, доступной для инсталляции через менеджер пакетов, в настоящее время нет. Но есть пара файлов, внесение которых в проект добавит конструкции wb-rules.
Оригинальная идея взята с портала техподдержки Wiren Board:
После небольшой доработки, VS Code перестал делать замечания. Для скачивания доступны файлы wb-rules.d.ts и wb-rules-modules.d.ts, реализующие необходимый функционал:
Их нужно поместить в папку types, добавленную в корень проекта.
Модульность типизирована недостаточно, остаётся проблема с обращением к данным, сохраняемым в module.static. Но совместными усилиями можно оптимизировать и эту часть.
Настраиваем команду сборки
Чтобы получить пригодный для работы на контроллере Wiren Board код, потребуется последовательно запустить три инструмента командной строки.
К счастью, консоль поддерживает конвейерное выполнение и можно оформить эти вызовы одной командой. Откроем файл package.json и в секцию scripts внесём следующую строчку:
"build": "tsc && tsc-alias && babel build -d dist"
Здесь дополнительными параметрами дополнен лишь Babel - ему сообщаем, что исходные коды следует брать из папки build, а результат транспиляции положить в папку dist.
Сбой на любом из этапов работы конвейера приведёт к прерыванию процесса: если компилятор TypeScript обнаружит ошибку в коде, дальше дело не пойдёт.
Настраиваем команду деплоя на контроллер
Отредактируйте команду деплоя и вместо src/* укажите каталог dist/* - на контроллер теперь будем передавать не исходный, а итоговый код:
deploy": "wsl rsync -e 'ssh -I /usr/lib/librtpkcs11ecp.so' -rltzvgO --progress --delete --exclude='alarms.conf' --groupmap=*:developers dist/* 'username@10.200.200.1:/mnt/data/etc/'"
🟥 Критически важно! Не забудьте поставить звёздочку в конце конструкции dist/* - это означает перечисление каталогов и файлов, расположенных внутри папки проекта на компьютере.
Если звёздочку убрать, rsync попытается удалить всё, что расположено на контроллере в папке-приёмнике. Учитывая, что приёмником является каталог /mnt/data/etc, при наличии достаточных (читать - root) прав у пользователя, функционирование устройства будет необратимо нарушено и потребуется заводской сброс.
С целью защиты от подобных ситуаций, в одной из прошлых статей мы создали на контроллере учётную запись пользователя с обычными правами - ему даём избирательный доступ к файловой системе:
ℹ️ Напоминание: если сомневаетесь в результате работы rsync, не играйте с огнём и добавьте два ключа: --dry-run и --itemize-changes. Первый переводит утилиту в режим имитации процесса без фактического воздействия на файловую систему устройства, а второй выводит на экран перечень запланированных операций.
Пишем правила на языке TypeScript
Как уже говорилось ранее, вся работа с исходными кодами правил будет сосредоточена в каталоге проекта под названием src.
В папках build и dist ничего не редактируем, там всё автоматизировано и любые ручные правки исчезнут при запуске команды сборки. Если генерируемый код окажется неоптимальным, следует регулировать настройки системы транспиляции - например, читать про пресеты и плагины Babel.
В папке src/wb-rules создадим файл example.ts - расширением *.ts мы сообщим компилятору и VS Code, что здесь применяется TypeScript. Добавим пару строк:
import { HELLO_MESSAGE } from '@wbm/example-module';
log(HELLO_MESSAGE);
Чтобы обращаться к модулям, в конструкции импорта будем использовать настроенный ранее псевдоним пути @wbm - при сборке он автоматически меняется на относительный путь, а в итоговом коде удаляется за ненадобностью.
В папке src/wb-rules-modules создадим файл example-module.ts, в него запишем строчку
export const HELLO_MESSAGE: string = "Hello from TypeScript version!";
Принцип работы: правило example импортирует из модуля example-module константу с сообщением и выводит её значение в консоль.
Сохраним, а затем последовательно запустим в терминале две команды:
yarn build
yarn deploy
Первая сгенерирует пригодный для работы на контроллере код правил wb-rules, а вторая загрузит его на контроллер.
Шаблон проекта на GitHub
Для начала работы также можно воспользоваться готовым шаблоном проекта:
Код шаблона сопровождается открытой лицензией Unlicense и свободен от авторских прав. Он расположен в отдельной ветке под названием plain, которая соответствует материалам данной статьи и не содержит «лишнего» кода следующих выпусков.
По мере выхода очередных статей, репозиторий будет дополняться, чтобы подарить всем профессиональную основу для комфортной разработки собственных правил.
Послесловие
Следующая статья рассказывает о системе статического анализа качества кода, которая подключается в проект с целью автоматического устранения проблем и обеспечения единого стиля.
Также на очереди статья о юнит-тестах для модулей и рассказ о том, как работать с системой контроля версий, обеспечив возможность командной (параллельной) работы над кодом правил, предотвращая конфликты и коллизии.
❤️ Дорогие читатели! Спасибо, что пользуетесь кнопочкой «Поддержать автора» в Дзене. Полученные средства будут направлены на покупку оборудования для обзоров, а также на то, чтобы подготовить для вас ещё больше интересных статей о программировании контроллеров Wirenboard.