Tramvai CLI
cli интерфейс которые решает актуальные проблемы и задачи CI части фронтенда. Позволяет уменьшить сложность настройки webpack, typescript, babel, postcss и множества других необходимых инструментов.
Инструмент позволяет собирать проекты для продашена, запускать код в режиме разработки с автоматической пересборкой если изменился файл, анализ приложений и генерация кода.
Установка
Глобальная установка на машине разработчика. В терминале будет доступна команда tramvai.
npm i -g --registry https://registry.npmjs.org/ @tramvai/cli
Локальная установка в проекте
npm i --save-dev @tramvai/cli
Команды
После любой команды можно набрать --help
, к примеру tramvai --help
или tramvai start --help
. После это в консоли появится описание команды и возможные параметры для использования.
tramvai new
- генерация нового репозитория с tramvai/cli и tramvaitramvai start
- запуск приложений в режиме разработкиtramvai start-prod
- запуск приложений в режиме разработки, при этом статика собрана в production режимеtramvai build
- сборка приложений для сервера и клиентаtramvai analyze
- анализ размер приложенияtramvai generate
- кодогенерация различных компонентов. К примеру новых проектов, react компонентов, экшенов, сервис и так далееtramvai update
- обновление @tramvai/cli
и всех @tramvai
и @tramvai/tinkoff
зависимостей в приложении
Конфигурация
Для работы tramvai-cli обязательно должен в корне проекта быть создан конфигурационный файл в формате json
, с описанием используемых проектов. tramvai-cli поддерживает следующие названия конфигурационных файлов:
platform.json
tramvai.json
Формат файла конфигурации
{
"projects": {
"react-app": {
"name": "new-app",
"root": "src",
"type": "application",
"commands": {
"build": {
"options": { ... },
"configurations": { ... }
},
"serve": {
"configurations": { ... }
}
}
}
}
}
projects
- описание всех проектов, которые доступны в этом репозитории. Поддерживает множество различных приложений в одном репозитории. Реализовывая концепцию монорепы.
Поддержка JSON схемы файла конфигурации в IDE
Ссылка на актуальную JSON схему для tramvai.json
- ./node_modules/@tramvai/cli/schema.json
Самый простой способ добавить валидацию и автокомплит схемы - добавить ссылку в поле $schema
для tramvai.json
:
{
"$schema": "./node_modules/@tramvai/cli/schema.json",
"projects": {}
}
Другой способ - добавление схемы в настройках IDE:
Как добавить схему в JetBrains IDE можно посмотреть в официальной документации, кроме добавления ссылки на схему, надо добавить tramvai.json
как file path pattern.
Как добавить схему в VSCode можно посмотреть в официальной документации
Новое приложение, созданное через tramvai new
, уже содержит поле $schema
в tramvai.json
.
Настройки для build этапа
Общее описание механизма сборки артефактов и их доставки
"options": {
"vendor": "", // Путь до vendor файла, если не указан, то не генерируется
"polyfill": "", // Путь до полифилов необходимых для работы приложения, если не указан, то не генерируется
"server": "src/server", // Путь до стартвой точки серверного файла, который будет отдельно собран
"outputServer": "dist/server", // Директория, куда после сборки скопируется серверный код
"outputClient": "dist/client" // Директория, куда после сборки скопируется клиенский код
},
"configurations": {
"commonChunk": true, // включает генерацию js файла с общим кодом между чанками
"commonChunkSplitNumber": 3, // количество дубликатов, для выноса в common чанк
"sourceMap": false, // будут ли сгенерированны сорсмапы для клиентских чанков
"sourceMapServer": false, // будут ли сгенерированны сорсмапы для серверных чанков
"modern": true, // Включение отдельной сборки для новых браузеров без дополнительной компиляции
"checkAsyncTs": false, // включает проверку в фоне типов, подробное описание ниже
"terserParallel": true, // включает параллельное сжатие
"granularChunks": false, // Включает разбитие common chunk на множество мелких частей. Потенциально может снизить размер js в сборке
"granularChunksSplitNumber": 2, // количество дубликатов, для выноса в granular чанки
"generateDataQaTag": false, // автоматическая генерация уникальных id для реакт компонентов. Депрекейтед!
"definePlugin": { // конфигурация параметров сборки приложения. Позволяет во время сборки заменить значения на преданные ниже
"prod": {},
"dev": {}
},
"threadLoader": { // конфигурация параметров многопоточной сборки приложения (https://webpack.js.org/loaders/thread-loader/).
},
"postcss": { // конфигурация postcss лоадера
"cssLocalIdentName": "[hash:base64:5]", // какой будет идентификатор
"config": "postcss.config" // где расположен конфиг для postcss
},
"alias": {}, // объект с алисами внутри приложения. Документация подробнее о формате можно прочитать в https://www.npmjs.com/package/babel-plugin-module-resolver
"removeTypeofWindow": true, // настраивает babel плагин transform-define на замену всех конструкций typeof window на 'undefined' или 'object' в зависимости от окружения
"dedupe": "equality" | "semver" | false, // подключение плагина для дедупликации зависимостей, с которыми не справился пакетный менеджер
"svgo": {
"plugins": [{ "cleanupIDs": false }, { "collapseGroups": false }], // плагины для svgo (https://github.com/svg/svgo#what-it-can-do)
},
"imageOptimization": { // конфигурация процесса оптимизации изображений
enabled: true, // включение оптимизации изображений
options: {} // опции для гибкой настройки оптимизации (https://github.com/tcoopman/image-webpack-loader#options)
}
}
Добавление новых параметров конфигурации
Параметры конфигурации CLI описаны в TypeScript интерфейсах, из них автоматически генерируется JSON Schema. Схема используется для валидации конфига, и применения значений по умолчанию, с помощью ajv.
Например, если мы хотим добавить параметр для команды build, для приложения:
- Описываем параметр в интерфейсе
ApplicationBuild
Возможности
Генерация кода
Для упрощения жизни разработчиков в tramvai cli
доступна возможность кодогенерации, которая позволяет при выполнении команды сгенерировать шаблонный код. Для запуска генератора, введи в консоли npm tramvai generate
и выберете из списка то, что нужно сгенерировать:
- action
- bundle
- reducer
- page
- component
- module
После ввода названия, будет сгенерирован шаблонный файл
Генерация нового проекта
Для быстрого старта нового проекта добавлена команда tramvai new
которая позволяет сгенерировать чистый проект с tramvai и tramvai-cli
- Установите глобального tramvai-cli
- Введите команду
tramvai new NAME_YOUR_APP
- И выберете опции: будет ли это монорепа, нужен ли CI и какие используются тестовые фреймворки
После выполнения команды и установки зависимостей, для вас сгенерируется проект
Сборка библиотек
Команда tramvai build
позволяет собирать библиотеки в отдельные бандлы под разные окружения:
- CommonJS модули + код стандарта ES2015 (для NodeJS без поддержки ES модулей) - поле
main
в package.json
- ES модули + код стандарта ES2015 (для NodeJS с поддержкой ES модулей) - поле
module
в package.json
- ES модули + код стандарта ES5 (для legacy браузеров) - поле
browser
в package.json
- ES модули + код стандарта ES2017 (для современных браузеров) - поле
es2017
в package.json
Для создания библиотеки в tramvai.json
необходимо добавить проект с типом package
:
{
"projects": {
"{{packageName}}": {
"name": "{{packageName}}",
"type": "package",
"root": "libs/{{packageName}}"
}
}
}
Все дополнительные настройки необходимо указать в package.json
библиотеки:
{
"name": "{{packageName}}",
"version": "1.0.0",
"source": "src/index.ts",
"browserSource": "src/browser.ts",
"main": "dist/index.js",
"module": "dist/index.es.js",
"browser": "dist/browser.js",
"es2017": "dist/browser.es2017.js",
"sideEffects": false,
"scripts": {
"start": "tramvai build {{packageName}} --watch",
"build": "tramvai build {{packageName}}"
}
}
Hot refresh в dev-режиме
Есть возможность включить обновление react-компонентов на странице без перезагрузки страницы, аналогичный фиче из React Native.
Помимо быстрой перезагрузки страницы (hot-reload), в этом режиме сохраняется значение в хуках useState
и useRef
.
Для возможности принудительно сбросить значения, можно добавить комментарий // @refresh reset
- он действует на весь файл.
При различных синтаксических и рантайм ошибках, fast-refresh плагин ждет исправления ошибки, затем разработка продолжается в обычном режиме.
Ограничения режима:
- state у классовых компонентов не сохраняется
useEffect
, useMemo
, и useCallback
обновляются при каждом изменении кода, независимо от списка их зависимостей, в том числе если список пустой, т.е. useEffect(() => {}, [])
будет выполняться постоянно - это не ожидаемое поведение, но приучает писать устойчивый к холостым ререндерам код
Подключение режима:
"commands": {
"serve": {
"configurations": {
"hotRefresh": true
}
}
}
Конфигурация режима через настройку hotRefreshOptions
, подробная конфигурация в доке react-refresh:
"commands": {
"serve": {
"configurations": {
"hotRefresh": true,
"hotRefreshOptions": {
"overlay": false
}
}
}
}
Анализ бандлов приложений
Посмотреть что попадает в бандл
Для это существует отличный плагин webpack-bundle-analyzer который позволяет показать наглядно все файлы
Для запуска необходимо выполнить команду
npx tramvai analyze APP_ID
после этого приложение соберется в проде и откроется новая вкладка в браузере
Найти причину попадания зависимости в бандл
Для решения этого кейса существует утилита whybundled которая позволяет распарсить stats.json файл webpack и отобразить причину попадения файла
Для использования необходимо выполнить команду
npx tramvai analyze APP_ID --plugin whybundled
После этого сгенерируется json файл сборки который можно будет анализировать с помощью whybundled. Путь до файла будет отображен в терминале
# Хочу найти причину попадания зависимости debug в сборку
npx whybundled ./dist/client/stats.json debug
# Хочу узнать что за собой потянула зависимость debug в сборку
npx whybundled ./dist/client/stats.json --by debug
Больше возможностей можно найти в whybundled
Настройка нотификаций при сборке\пересборке проекта
В файле platform.json можно задать настройки для нотификации по пути commands.serve.notifications
. Параметры задаются для пакета webpack-build-notifier. Можно задать как общую конфигурацию, так и отдельную для клиента\сервера.
"commands": {
"serve": {
"notifications": {
"suppressSuccess": "always",
"server": {
"suppressWarning": true
},
"client": {
"activateTerminalOnError": true
}
}
}
}
Включение сорсмапов в дев-режиме
В platform.json
"commands": {
"serve": {
"configurations": {
"sourceMap": true
}
}
}
Работа modern в дев-режиме
В деве возможно работать только с одним режимом: modern или legacy. По умолчанию выставлен legacy. Для включения modern режима в деве необходимо в platform.json добавить опцию modern: true
:
"commands": {
"serve": {
"configurations": {
"modern": true
}
}
}
Настройка генерации имен css классов
Генерация настраивается через свойства cssLocalIdentNameDev
и cssLocalIdentNameProd
(или общее cssLocalIdentName
которое будет использовано если явно не заданы prod или dev).
"commands": {
"build": {
"configurations": {
"postcss": {
"cssLocalIdentName": "[hash:base64:5]",
"cssLocalIdentNameDev": "[name]__[local]_[minicss]",
"cssLocalIdentNameProd": "[minicss]",
};
};
};
};
Полифиллы для страндартных NodeJS модулей
По умолчанию, webpack
начиная с 5й версии, больше не добавляет в бандл полифиллы для браузера, при использовании стандартных NodeJS модулей в универсальном коде, пример таких модулей - crypto, path, process, buffer, etc.
В @tramvai/cli
явно подключены полифиллы для path и process. Эти модули часто используются, а их полифиллы имеют небольшой размер.
Проверка типов checkAsyncTs
Включается по флагу
“checkAsyncTs”: true
При запуске tramvai start
будет происходить компиляция ts и проверка типов.
Можно задать в формате объекта:
"checkAsyncTs": {
"failOnBuild": true, // необязательная опция
"pluginOptions": {} // необязательная опция
},
failOnBuild добавит компиляцию ts при работе tramvai build.
Таким образом команда build не будет проходить при невалидном ts.
pluginOptions – список дополнительных опций плагина fork-ts-checker-webpack-plugin
Если вы хотите переопределить путь до конфига в pluginOptions.tsconfig, его нужно рассчитать относительно папки c tramvai cli, т.е. node_modules/@tramvai/cli. По умолчанию конфиг ищется в корне проекта: <rootDir>/tsconfig.json
Дедупликация модулей
Параметр commands.build.configurations.dedupe
отвечает за подключение плагина, отвечающего за дедупликацию модулей. Возможные значения:
-
"equality"
- выбран по умолчанию, строгое сравнение версий, схлопывает импорты пакетов одинаковых версий из разных мест Например, импорты node_modules/package/index.js
и node_modules/nested-package/node_modules/package/index.js
, в обычном случае положили бы в бандл оба модуля.
-
"semver"
- сравнение версий пакетов по semver, позволяет схлопнуть дополнительно те импорты, у которых отличаются только minor или patch версии. Например, будут схлопнуты пакеты версий 1.14.0
и 1.16.2
до 1.16.2
, 0.14.1
и 0.16.5
до 0.16.5
, а пакеты версий 0.0.2
и 0.0.5
останутся без изменений.
-
false
- отключает плагин дедупликации
Explanation
Debug приложения
При разработке приложения иногда нужно напрямую продебажить node.js приложение, посмотреть потребление CPU, памяти. Для этого в команды start
и start-prod
добавлен параметр --debug
которая:
- включит сорсмапы для сборки на клиенте и сервере
- запустит процесс сервера с флагом
--inspect
.
И далее можно открыть отладчик в chrome devtools - chrome://inspect
Source Maps
webpack
предлагает несколько видов качества кода при генерации source maps, из них основные это:
- Исходный код - код до транспиляции и бандлинга, слепок наших исходников, разделенный по модулям
- Трансформированный код - код после транспиляции лоадерами (etc. babel), разделенный по модулям
- Сгенерированный код - код после транспиляции и бандлинга, разделенный по модулям, все импорты и экспорты заменены на webpack-специфичные
Для разработки используются source maps для трансформированного или сгенерированного кода, т.к. скорость их сборки выше, и показан именно тот код, который выполняется в целевом окружении, основное отличие от отладки без source map - указаны модули, в которых находится отлаживаемый код.
tramvai
генерирует большой общий бандл с серверным кодом, поэтому для отладки серверного кода лучше не увеличивать размер этого файла и использовать source maps в отдельном .js.map
файле, который генерируется с исходным кодом приложения.
Development
По умолчанию, для клиентского кода включены самые быстрые source maps, для серверного кода source-maps отключены.
Флаг --debug
активирует генерацию source map с исходным кодом для серверного бандла.
Параметр commands.serve.configurations.sourceMap
активирует генерацию source map с исходным кодом для клиентского и серверного бандлов.
Production
По умолчанию, отключены source maps для клиентского и серверного кода.
Флаг --debug
активирует генерацию source map с исходным кодом для клиентского и серверного бандлов.
Параметр commands.build.configurations.sourceMap
активирует генерацию source map с исходным кодом для клиентского бандла.
Параметр commands.build.configurations.sourceMapServer
активирует генерацию source map с исходным кодом для серверного бандла.
How to
Как можно запустить nodejs приложение в debug режиме?
Добавить при запуске приложения параметр --debug
tramvai start my-app --debug
Далее открыть chrome devTools в левом верхнем углу кликнуть на лого Node.js.
В итоге у вас откроется отдельный инспекторовщик вашего node.js приложения и вы можете снять снэпшот памяти, продебажить код и провести профилировку приложения
Получить расширенную информацию о deprecated и warnings
Может быть полезно для получения стектрейса различных предупреждений. Запускает сервер приложения с дополнительными опциями.
Например, если при работе приложения отображается лог вида
(node:2898) DeprecationWarning: ...
(Use `node --trace-deprecation ...` to show where the warning was created)
Нужно добавить при запуске приложения параметр --trace
tramvai start my-app --trace
После запуска приложения с такой опцией логи будут отображаться со стеком вызова.
Как протестировать приложение используя browserstack
Получить доступы к browserstack можно написав в слаке команду /bs
Запустите приложение как обычно командой tramvai start
и используя инструкцию browserstack настройте локальное тестирование на своей машине. Если всё сделано правильно, то теперь в browserstack можно будет получить доступ к localhost и протестировать работу приложения.
Как протестировать приложение на мобилке или другом устройстве в локальной сети
Необходимо чтобы оба устройства на котором запускается приложение и на котором требуется проверить работу находилось в одной сети.
Для организации доступа приложения в сети необходимо:
- узнать ip адрес машины на которой запускается приложение в интересующей сети
- запустить команду
tramvai start
с параметров staticHost
равным этому ip адресу (пример tramvai start tincoin --staticHost 192.168.1.3
) - с тестового устройства теперь можно будет получить доступ к приложению обратившись по адресу хоста = ip
При передаче параметров в @tramvai/cli через npm скрипты необходимо перед параметрами для cli добавить --
, т.е. команда должна выглядеть примерно так npm start -- --staticHost 192.168.1.3
Как ускорить сборку приложения при разработке
Указать только определённые бандлы для разработки
Приложение может содержать несколько бандлов и чем их больше, тем больше кода в приложении, а, следовательно, и дольше сборка и пересборка проекта в процессе разработки.
Чтобы ускорить этот процесс при запуске @tramvai/cli можно указать какие бандлы нужны сейчас для разработки и cli будет собирать только их
Бандлы должны находиться в папке bundles
и импортироваться из главного файла приложения.
При попытке запроса бандлов, которые отключены в данный момент, сервер упадёт с 500-ой ошибкой, т.к. это неожидаемое поведение для сервера, что бандла нет
tramvai start myapp --onlyBundles=account
tramvai start myapp --onlyBundle=account,trading
Возможные проблемы
При запуске команды start один из процесов node грузится > 100% на Mac OS
Возможно, причина в том, что зависает watch режим webpack. Для решения проблемы необходимо поставить локально в проекте и глобально npm i fsevents
. После этого проблема должна решиться.
При минификации CSS кода происходят ошибки вида: error GLOBAL:ERROR Error: inspwa.cdc24eaba4573ba3a27d.css from Css Minimizer
Сейчас происходит тестирование перехода на альтернативный способ сжатия CSS через css-minimizer-webpack-plugin используя cssnano, по этому могут возникать новые баги и проблемы. Если столкнулись с такой проблемой, есть возможность откатиться на старую реализацию с csso. Для это в configurations добавьте поле "cssMinimize": "csso"