Чему я научился, написав библиотеку компонентов на Svelte
Попробовав Svelte в личных проектах, мне захотелось двигаться дальше, и взять фреймворк в проект побольше. Для этого написал библиотеку компонентов svelte-atoms. За основу я взял UI кит на React, который используем на работе.
Каким приемам Svelte я научился, читайте под катом.
Статья подразумевает, что вы уже знакомы с основными концепциями Svelte. Если нет, то рекомендую сначала ознакомиться с моими предыдущими статьями:
Полная жизнь на Svelte
Разрабатываем игру на Svelte 3
Библиотека находится в фазе активной доработки. Еще не хватает некоторых компонентов, не проработаны вопросы доступности, и не все баги исправлены. Сейчас делаю проект на этом ките, чтобы в боевом режиме понять, что нужно дорабатывать в первую очередь.
Итак, чему я научился, написав библиотеку компонентов на Svelte.
1. Использование свойства class
Если вы хотите добавить свойство class к параметрам своего компонента, то получите ошибку, поскольку слово является зарезервированным самим javascript.
Решить эту проблему можно, используя внутреннее api Svelte. Переменная $$props содержит все свойства, которые переданы в компонент. В компоненте-родителе можно передать свойство class
А в самом компоненте установить класс из переменной $$props.
Пример в REPL
2. Стилизация дочерних компонентов
В Svelte используется изоляция стилей. Если вы добавили класс в компоненте, то в итоге к нему добавится хеш и он будет уникальным для вашего компонента и никуда не «протечет». Но что, если нужно стилизовать дочерний компонент? Логично передать ему какой-нибудь класс и в родителе прописать стили. Решается данная задача довольно просто, с помощью директивы : global ()
Пример в REPL
При таком подходе вы все равно получите изолированный стиль, но который применяется во всей иерархии дочерних компонентов
3. Обработчики всех событий
Svelte компонент должен поддерживать событие, чтобы извне можно было назначить на него обработчик. Прописывать все варианты событий утомительно. Вместо этого можно написать универсальный обработчик, который будет искать обработчики событий, которые переданы в компонент, и добавлять их в наш компонент. Идею подсмотрел у AlexxNB в его библиотеке svelte-chota.
Пример в REPL
Этот способ не совсем легальный, поскольку использует внутреннее API Svelte, которое может измениться. Надеюсь, в будущем добавится поддержка директивы on: * Issue на github
4. Обнаружение слотов.
Если вам нужно узнать, передано ли содержимое слота, то могу предложить вам два варианта.
Способ первый, легальный.
У слотов есть фолбек, который отображается, если содержимое не передано. Сделав биндинг фолбэка в переменную, мы сможем обнаружить наш слот.
{isFooterExists ? 'Футер есть' : 'Футера нет'}
Способ второй, полулегальный.
Можно воспользоваться внутренним api Svelte
const isFooterExists = Boolean($$props.$$slots && $$props.$$slots.footer);
Пример в REPL
5. Порталы
В Svelte нет приема использования порталов, как в React, но его очень просто сделать. Для этого можно воспользоваться DOM api.
content
На монтирование компонента мы переносим его в body, а при удалении убираем и наш портал.
Важное замечание: заверните ваш портал в div, иначе Svelte может некорректно убрать компоненты при размонтировании.
6. Анимации
В Svelte большой набор готовых анимаций, которые могут пригодиться вам в работе. Очень легко анимировать появление и исчезание компонентов. Но анимация одного блока может тормозить удаление всей страницы. Svelte будет ждать завершения анимации, прежде чем удалить компонент из дерева. Чтобы избежать этого, используйте директиву local.
Пример в туториале
7. Именованные слоты и компоненты
К сожалению, передать в именованный слот сразу компонент нельзя. Issue на github
Чтобы передать компонент в именованный слот заверните его в div или любой другой html тег.
8. Получение списка свойств компонента
Если вам нужно получить список свойств, которые экспортированы из компонента, то можно воспользоваться следующей конструкцией:
{JSON.stringify(props)}
Идею подсмотрел у PaulMaly.
9. Двухсторонний биндинг
После разработки на React, концепция двухсторонней привязки кажется пугающей, но это только на первый взгляд. В итоге ваше приложение будет выглядеть лаконичней и позволит избавиться от кучи обработчиков. Вы можете использовать в качестве хранилища как обычную переменную, так и store.
Пример в REPL
10. Редактируемый контент
Если вам нужно сделать контент элемента редактируемым, то можно воспользоваться директивой contenteditable и сделать биндинг значения в переменную.
{value}
Value: {value}
Пример в REPL
Размер компонентов
Ну и куда же без React. Держите сравнение количество строк кода компонентов на Svelte и React, которые реализованы примерно одинаково. Учитываются код и стили.
Демо библиотеки
Исходный код
Если вы нашли баг, или хотите что-то предложить, создавайте issue