Всем привет! Меня зовут Виталий Ризо, я фронтенд-разработчик в «Амплифере». Мы сделали Uibook — простой инструмент для визуального тестирования React-компонентов с реальными медиа-запросами. Расскажу, как он работает и чем может быть полезен вам.
Зачем сделали и в чём польза
При создании новых компонентов мы страдали при рефакторинге — для проверки приходилось менять атрибуты через DevTools вручную, могли пропустить какие-то мелочи. Поэтому решили сделать страницу, где можно быстро тестировать компоненты.
Uibook позволяет быстро увидеть компоненты в любых состояниях и комбинациях параметров (props). Благодаря поддержке медиа-запросов, разработчик на одной странице может отобразить настольные и мобильные версии компонентов. Но Uibook полезен не только разработчикам:
- дизайнеры могут на своём устройстве, не поднимая локальный сервер, посмотреть всевозможные состояния компонентов и передать правки;
- менеджеры видят, что даже простой, на первый взгляд попап, может содержать кучу граничных состояний, которые разработчики вынуждены учитывать — это помогает им лучше понимать устройство интерфейса продукта изнутри;
- редакторы могут с помощью режима Live Text Editing примерить текст для интерфейса в реальных компонентах, чтобы он выглядел безупречно.
Чем отличается от аналогов
Вы можете спросить, зачем изобретать велосипед, когда есть готовые Storybook, Styleguidist и подобные решения? У моего проекта другой подход и я выделяю три основных отличия:
- В Uibook сразу можно смотреть компоненты в условиях ограниченной ширины и высоты устройств;
- Он не требует отдельного сборщика и легко подключается к существующему проекту парой строк в конфигурационном файле;
- Подразумевается, что страницы с компонентами будут доступны публично, чтобы любой пользователь мог найти ошибки и оставить обратную связь.
Uibook нужен в основном для визуального тестирования, а не разработки, хотя и разрабатывать «представляющую» часть проекта с ним удобно. Пришлось внести глобальные изменения в проект? Пробегитесь по всем страницам, чтобы убедиться в корректном отображении всех компонентов.
Техническая реализация
Uibook представляет собой React-приложение, в которое передаются Страницы — наборы «кейсов», то есть, состояний одного компонента (props и callbacks). Далее, Uibook рендерит выбранную Страницу на одном экране, используя два контроллера: с медиа-запросами и без них.
Поскольку эмулировать медиа-запросы средствами CSS и JavaScript невозможно, мы пошли простым путём: рендерить компонент внутри <iframe>
, если пользователь указал ширину или высоту экрана.
Главный контроллер оборачивает компонент в любую пользовательскую обёртку, а также позволяет выбирать значения в браузере. В iframe
данные передаются через ссылку. Также главный контроллер добавляет горячие клавиши и возможность редактировать текст.
Я не хотел иметь отдельные сборщики для проекта и визуального тестирования. Другие продукты вынуждают это делать, из-за чего приходится хранить больше файлов, зависимостей, всё это дольше настраивается, дольше запускается, сложнее собирается и деплоится. Uibook же интегрируется в сборщик проекта, так как просто добавляется как Webpack-плагин:
plugins: [
…
new UibookPlugin({
controller: path.join(__dirname, '../controllers/uibook.js')
})
]
webpack.config.js
Uibook создаёт отдельный чанк и не увеличивает размер основного приложения. Работает это через вебпаковские SingleEntryPlugin
или MultiEntryPlugin
. Он подтягивает стили и скрипты из основного приложения с учётом кэширования (”cachebuster”). Вот как плагин получает список нужных файлов:
let files = compilation.chunks.find(function (i) {
return i.name === 'uibook'
}).files
Затем он генерирует HTML-файл без использования зависимостей. Ведь это очень простая задача, нет необходимости тянуть библиотеки для этого. Берём шаблон, добавляем импорты, добавляем в выдачу:
compilation.assets[outputPath + '/index.html'] = { … }
Но если у вас всё же подключён HtmlWebpackPlugin
, то придётся добавить uibook
в исключения, о чём Uibook мило напомнит.
Uibook очень прост
У него в зависимостях только React, Webpack да create-react-class
. Он написан на ES5, поэтому будет работать, даже если у вас нет Babel в проекте. А если есть, то не будет конфликтов плагинов. В Uibook встроены подсказки, если в конфигурационном файле что-то не так.
Uibook гибок
Вы можете обернуть все компоненты в свой контроллер. Это может быть обёртка для Redux, Context или всего сразу. Вот пример с новым Context API:
export default UibookStarter({
wrapper: (children, props) =>
<Context.Provider value={ props }>
{ children }
</Context.Provider>,
values: {
locale: ['ru', 'en'],
theme: ['dark', 'light']
},
…
})
Список пользовательских ключей и их значений будет отображаться в верхнем навигационном меню.
Как внедрить Uibook в проект
Например, мы хотим добавить компонент Кнопка, который лежит в src/button.js
. Нужно установить пакет uibook
, создать файл-контроллер и файл-страницу. Файл-контроллер служит для импорта ваших Uibook-тестов, а файл-страница — это набор «кейсов», комбинаций параметров для одного компонента.
Вот как это сделать:
1) Приступим, $ yarn add uibook
;
2) Здесь можно воспользоваться командой $ npm init uibook
, которая создаст файлы-примеры, а можно сделать всё вручную. Приблизительно структура получится такой:
your-project
├── uibook
│ ├── button.uibook.js
│ └── uibook-controller.js
├── src
│ └── button.js
├── webpack.config.js
└── package.json
3) Подключаем плагин в конфигурационном файле Webpack:
let UibookPlugin = require('uibook/plugin')
module.exports = {
…
plugins: [
new UibookPlugin({
controller: path.join(__dirname, '../src/uibook-controller.js'),
})
],
}
webpack.config.js
4) Запишем тест в uibook/button.uibook.js
. Если вы воспользовались командой init
, то этот пример уже создан:
import UibookCase from 'uibook/case'
import Button from '../src/button.js'
const PROPS = {
onClick: UibookCase.event('onClick')
}
const ButtonUibook = {
component: Button,
name: 'Button',
cases: [
() => <UibookCase props={{ ...PROPS, isLarge: true }}>
Large Button
</UibookCase>,
() => <UibookCase props={{ ...PROPS, isDisabled: true }}>
Disabled Button
</UibookCase>
]
}
export default ButtonUibook
button.uibook.js
5) Импортируем и передаём этот uibook-тест в файле-контроллере:
import UibookStarter from 'uibook/starter'
import ButtonUibook from './button.uibook'
export default UibookStarter({
pages: {
Button: ButtonUibook,
}
})
uibook-controller.js
6) Готово! Запускаем свой проект как обычно (например, $ yarn start
) и открываем страницу /uibook
в браузере. Мы увидим три кейса с кнопкой (если у вас есть компонент /src/button.js
, конечно):
Как Uibook помог нам
Мы используем Uibook в своей работе уже больше года всей командой. Фронтендеры разрабатывают новые компоненты только через Uibook, попутно создавая тест-файл с граничными параметрами (props). Это намного быстрее, чем писать параллельно контроллер, чтобы увидеть компонент в реальном веб-приложении. Более того, этот тест-файл будет использоваться в дальнейшем для визуального тестирования после каких-либо глобальных изменений.
Андрей Ситник Iskin, ведущий фронтенд-разработчик в «Злых марсианах» отмечает, что Uibook делает работу спокойнее:
Uibook дал нам наконец-то уверенность, что после обновления normalize.css у нас ничего не сломалось. Просто открываем и просматриваем подряд все компоненты. Тут сильно помогает главная фича — поддержка @media
, так что на странице все состояния компонентов. У разработчиков меньше страхов, у менеджеров — меньше багов. Все довольны.
Да и сам процесс тестирования упростился. Теперь фронтендер пишет новый компонент (view-составляющую), попутно создавая файл с параметрами (props). Контроллер при этом не нужен — можно деплоить по ходу разработки, не внедряя компонент в само веб-приложение.
Другие фронтенд-разработчики ревьюят компонент, используя локальный или задеплоенный Uibook: можно понажимать на все кнопочки и проверить, что callback вызываются. Так мы экономим до 30 часов каждый месяц на тестировании компонентов.
Дамир Мельников, фронтенд-разработчик «Амплифера», также отмечает возможность совместной работы с дизайнерами, продактами и редакторами:
Uibook позволяет мне быстро работать над компонентами — примерять новые стили, следить за мобильной версией, изучать, как ведёт себя компонента при разных вводных. Кроме того, Uibook позволяет быстро поделиться своей работой с дизайнером (живой макет), редактором (для вычитки интерфейсных текстов) и другими фронтенд-разработчиками.
Контент-лид «Амплифера» Александр Марфицин замечает, как Uibook упростил работу по написанию интерфейсных текстов:
Когда делаешь тексты для интерфейса, то часто работаешь вслепую и не видишь, как будут выглядеть надписи в «живом» продукте. Uibook решает эту проблему. Можно не только вычитывать старые тексты, но и создавать новые, опираясь на ограничения компонентов и примеряя свои черновики на реальном интерфейсе. Все текстовые элементы редактируемы, это позволяет получать цельный результат — от заголовка до даже самой маленькой надписи.
И сам процесс работы стал более прозрачным — с Uibook лучше понимаешь устройство продукта и интерфейса изнутри, начинаешь лучше понимать важность хорошего текста для интерфейса.
⌘⌘⌘
Надеюсь, что Uibook найдёт применение в вашем проекте. Если остались вопросы, то посмотрите детальную инструкцию в репозитории на Гитхабе. Или пишите мне в твиттере или на почту.
Спасибо Александру Марфицину marfitsin за помощь в подготовке статьи.