Представляем вашему вниманию Skeleton: Полнофункциональная библиотека компонентов для Svelte.

Недавно мне выпала честь написать статью для Smashing Magazine о Skeleton, новой библиотеке компонентов пользовательского интерфейса с открытым исходным кодом для Svelte и Tailwind. Если вы ищете краткое введение, я бы рекомендовал начать здесь:

Smashing Magazine: Meet Skeleton: Svelte + Tailwind для реактивных пользовательских интерфейсов

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

Происхождение Skeleton

Последние два года я работал в технологическом стартапе под названием Brain & Bones, состоящем из небольшой команды из пяти человек. Как и в большинстве стартапов, вам приходится носить много шляп, поэтому моя работа охватывала все — от технологий до дизайна: определение технологического стека, дизайн продукта, реализация фронтенд-приложений, руководство разработкой API нашей платформы, а также управление двумя очень талантливыми разработчиками.

Изо дня в день мы управляли множеством веб-приложений, поэтому выбор фронтенд-фреймворка оказывал большое влияние на нашу способность создавать и поддерживать платформу для компании. Angular был для меня очевидным выбором, поскольку я профессионально использую его уже около 10 лет. Я наблюдал, как он развивался с первых дней версии 1.x, через запуск версии 2.x и в конечном итоге превратился в зрелый фреймворк, который мы знаем сегодня. Я по-прежнему являюсь поклонником философии дизайна Angular, а также Angular Material, их официального ответвления Material Design. Эстетика Material обеспечивает простой, но чистый интерфейс, а их система компонентов позволяет быстро разрабатывать крупномасштабные веб-приложения.

В прошлом году мы приняли в нашу команду молодого начинающего разработчика по имени Томас Йесперсен. Томас присоединился к нам с задачей улучшить наши усилия по обеспечению качества (QA) и тестированию, но сразу же заинтересовался разработкой фронтенда. Поэтому я выделил время и начал обучать его всему, чему мог, опираясь на свой 20-летний опыт работы в этой области.

Мы изучали основы HTML/CSS/JS, различные фронтенд-фреймворки, такие как React/Vue/Svelte, и нашей конечной целью было знакомство с Angular. Однако на этом пути произошла интересная вещь. После изучения Svelte мы испытали некоторое откровение. Как и многие в области фронтенда, мы были очарованы превосходным DX (опытом разработчика) Svelte. Мы знали, что наша платформа основана на Angular, но жаждали возможности внедрить и использовать Svelte и SvelteKit (фреймворк приложений Svelte) в нашей производственной среде. К сожалению, в то время мы не знали, как их внедрить.

В феврале этого года мы приступили к планированию следующего поколения и эволюции нашей платформы. Мы сразу же начали мозговой штурм по поводу перехода от Angular к Svelte/Kit. Однако в процессе поиска библиотек пользовательского интерфейса для замены Angular Material мы столкнулись с проблемой. Конечно, такие варианты, как Svelte Material UI, были доступны. Однако у нас росло беспокойство по поводу траектории развития Material Design. Material Design v3 не был действительно ошеломляющим успехом, имея лишь небольшое количество компонентов (даже сегодня), и в настоящее время ограничен исключительно Android. Даже Angular Material, проект, принадлежащий Google, не спешит внедрять v3. Прогресс двигался со скоростью улитки. Это поставило нас перед дилеммой.

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

Это позволило бы нам легко создавать компоненты, отвечающие требованиям каждого из наших продуктов, сохраняя полный контроль над их внешним видом и работой. К сожалению, это потребовало бы дополнительных усилий по разработке, но после внутренних дебатов мы решили, что в долгосрочной перспективе это справедливый компромисс. Так родился Skeleton!

В поисках вдохновения

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

Вот небольшая выборка библиотек, которые мы рассмотрели:

  • Material Design
  • Bootstrap
  • Bulma
  • Chakra
  • MUI
  • Vuetify
  • Carbon

После некоторого времени и усилий этот процесс привел нас к библиотеке Mantine, ориентированной на React, которая предлагает огромный набор компонентов, глубокую кастомизацию, все это размещено в первоклассной интерактивной документации. Эта библиотека быстро стала нашим основным источником вдохновения и повлияла на многие решения по дизайну нашей библиотеки, особенно на презентацию.

Использование Tailwind

Мы с самого начала знали, что хотим воспользоваться преимуществами Tailwind CSS. Его мощная система классов, основанная на утилитах, соответствовала соглашениям, используемым в нашем собственном проекте на протяжении многих лет, но могла помочь стандартизировать процесс. Это позволило бы нам разработать систему дизайна «под ключ» и управлять стилизацией как внутри компонентов, так и во всех приложениях. Первая проблема заключалась в том, как правильно использовать Tailwind в компонентах Svelte. Было не так много прецедентов, которые можно было бы взять из других библиотек. Многие библиотеки, которые мы рассмотрели, использовали либо ванильный CSS, либо препроцессоры вроде SASS.

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

Путем экспериментов мы пришли к творческому подходу — мы определяем все классы CSS в теге сценария компонента, а затем используем многоуровневые или условные операторы для управления классами, определенными для каждого элемента.

В теге сценария компонента мы определяем наши базовые (читай: стандартные) стили для элемента, как показано на рисунке:

const let cBase: string = `p-4 space-y-4`;
Вход в полноэкранный режим Выход из полноэкранного режима

Мы также разрешаем передавать настраиваемые классы Tailwind в качестве реквизитов компонента Svelte:

export let background: string = `bg-slate-900`;
export let color: string = `text-white`;
Войти в полноэкранный режим Выход из полноэкранного режима

Затем мы создали реактивные свойства Svelte, чтобы объединить их в «плоскую» строку класса:

$: classesBase = `${cBase} ${background} ${color}`;
Войти в полноэкранный режим Выйти из полноэкранного режима

Таким образом, мы объединяем значения базовых и пользовательских свойств и определяем порядок, в котором определяются классы, а также открываем возможность для условных классов, например, так:

export let hover: boolean = true;

$: classesHover = hover ? 'bg-emerald-500' : '';
$: classesBase = `${cBase} ${classesHover}`;
Войти в полноэкранный режим Выйти из полноэкранного режима

Это позволило избежать нагромождения тонны условной логики в разметке HTML-шаблона компонента. Абстрагирование этого обеспечивает простую и четко определенную парадигму, которой можно следовать.

Используя логику JavaScript, мы можем перехватывать и изменять наши классы, обеспечивая глубокий уровень контроля над представлением. Мы даже можем принимать отдельные значения реквизитов, которые расширяются до набора классов Tailwind:

export let size: string = 'sm'; // small

let cSize: string = '';

switch (size) {
    case ('sm'): cSize = 'p-2 text-sm'; break;
    case ('md'): cSize = 'p-4 text-base'; break;
    case ('lg'): cSize = 'p-5 text-lg'; break;
}

$: classesBase: `... ${cSize}`;
Вход в полноэкранный режим Выйти из полноэкранного режима

Наконец, мы добавляем значение реактивного класса к элементу. Это сохраняет чистоту наших шаблонов и уменьшает «раздутость» классов Tailwind, которая отталкивает многих пользователей:

<div class={classesBase}>...</div>
Вход в полноэкранный режим Выход из полноэкранного режима

Однако следует отметить, что компилятор Tailwind НЕ позволяет динамически конструировать классы. Если вы попытаетесь передать частичное значение, например, название цвета (например: emerald) и сгенерировать bg-${colorName}-500, это не удастся. Компилятор Tailwind ищет точное совпадение строк в каждом файле, но Tailwind читает значение буквально и не распознает его. Это было источником многих головных болей для нас в начале работы, так что будьте осторожны!

Темы

Следующая проблема, с которой мы столкнулись, заключалась в том, как правильно работать с темами. Перезаписывать одно и то же значение реквизита снова и снова для каждого компонента было бы не очень удобно. К счастью, Tailwind предлагает отличное решение с помощью пользовательских определений цвета. Они лучше всего работают со значениями цветов RGBA, позволяя настраивать альфа-прозрачность для каждого цвета. Другими словами, bg-emerald-500/40 означает, что цвет установлен на 40% непрозрачности.

Для работы с тематическими цветами мы создаем четыре уникально названных значения:

  • Основной — основной цвет бренда
  • Акцент — вторичный цвет для смещения или нейтральных действий
  • Предупреждение — для предупреждений и критических элементов
  • Поверхностный — основа, например, цвета фона

Мы вручную создали нашу тему по умолчанию, используя цветовую палитру Tailwind по умолчанию (изумрудный, индиго, розовый и серый), но преобразовали каждый оттенок цвета из шестнадцатеричного в RGBA. Они были определены с помощью пользовательских свойств CSS (читай: переменных CSS) и введены в файл конфигурации Tailwind с помощью пользовательского плагина Tailwind. С тех пор мы значительно упростили этот процесс, предложив набор предустановленных тем и генератор тем.

Это означает, что цвета в компонентах не закодированы. Мы черпаем из каждого из этих наборов и логично применяем цветовые стили.

Нужно определить фон компонента Card? Используйте его по умолчанию:

export let background: string = 'bg-surface-800';
Войти в полноэкранный режим Выйти из полноэкранного режима

Нужно стилизовать компонент Button, используя основной цвет брендинга? Используйте это:

export let background: string = 'bg-primary-500';
Войти в полноэкранный режим Выйти из полноэкранного режима

Темный режим

Наконец, нам потребовалось решение для интеллектуальной адаптации темы каждого компонента для темных режимов Tailwind. Решение заключалось в балансировке цветов, как на взвешенной шкале. Мы объединили цвета с обеих сторон спектра.

Вот как это выглядит наглядно:

На практике это означает, что если вы установите для фона элемента body в светлой теме bg-surface-50, то для баланса эквивалент темной темы должен быть bg-surface-900. Вот как выглядит CSS на практике:

body { @apply bg-surface-50 dark:bg-surface-900; }
Вход в полноэкранный режим Выход из полноэкранного режима

Если вы хотите стилизовать компонент карточки, который немного приподнят (визуально) над фоном, вы используете:

export let background: string = 'bg-surface-100 dark:bg-surface-800';
Войти в полноэкранный режим Выйти из полноэкранного режима

Независимо от того, какой цвет surface представляет, независимо от светлого или темного режима, элемент карточки всегда дает желаемый эффект. Несмотря на то, что это тонкое балансирование, его легко проверить во время разработки. Просто не забывайте регулярно просматривать свои компоненты в разных темах и с переключением режима свет/темно по мере продвижения.

Первые четыре месяца

С февраля по май мы с Томасом определили эти условности и начали создавать каждый компонент. Внутри компании у нас был общий список компонентов, необходимых для удовлетворения требований наших проектов. Сюда входили кнопки, карточки, вкладки и т.д.

Используя Svelte, Tailwind и наши шаблоны проектирования, мы создали большую часть библиотеки в течение первых четырех месяцев. К сожалению, как это часто бывает со стартапами, мы получили известие о том, что компания закрывается, а команда будет уволена к концу месяца. Очевидно, что это было разрушительным известием. У нас была замечательная и поддерживающая культура, мы полностью вкладывались в продукты, которые создавали, и, конечно же, мы были рады начать работу над Skeleton. В некотором смысле это было похоже на то, что все закончилось еще до того, как началось.

Однако с самого начала мы обсуждали возможность сделать библиотеку с открытым исходным кодом. Мы знали, что у нас есть что-то, что может быть полезным для многих членов сообщества Svelte. Однако библиотека юридически не принадлежала нам. К счастью, у нас с Томасом сложились прекрасные рабочие отношения и дружба с основателем компании. После небольшого летнего перерыва мы собрались вместе и договорились выпустить библиотеку с открытым исходным кодом. Именно в этот момент я возобновил работу над проектом, вскоре к нам присоединился Томас, и мы начали открывать его для общественности.

Запуск публичной бета-версии

В конце июня мы внесли последние правки в документацию, добавили лицензию MIT и, наконец, опубликовали репозиторий на GitHub и пакет NPM. Затем мы начали продвигать и анонсировать проект в различных сообществах, ориентированных на Svelte.

После запуска мы получили множество полезных отзывов и положительных комментариев на Reddit и в Svelte Discord. Люди задавали трудные вопросы, делали замечательные предложения и в целом были в восторге от того, что мы создали. Это, конечно, подстегнуло наше стремление продвигать проект, особенно после задержки в мае. В некотором смысле это было похоже на восстание Феникса из пепла!

После публичного запуска мы приложили много усилий для создания сообщества Skeleton на Github, в Twitter и Discord. По своей прихоти я обратился к новым источникам, таким как Smashing Magazine. К нашему удивлению, мы получили очень приятный ответ от Виталия Фридмана. Он предложил нам написать статью, ссылка на которую находится в верхней части этой страницы. Журнал Smashing оказал огромное влияние на мою карьеру. За эти годы я узнал много нового о веб-разработке. Честно говоря, я до сих пор в шоке от того, что это вообще произошло!

Мы также были в восторге от реакции сообщества Svelte — нас поздравляли такие люди, как Бен МакКанн, второй по величине вкладчик в SvelteKit после Рича Харриса (создателя Svelte).

А также комплименты от членов основной команды Astro и даже от члена Svelte Sirens. Оба проекта состоят из хороших людей и заслуживают внимания!

Светлое будущее

Мы продолжаем продвигать Skeleton, включая большой релиз на этой неделе, добавляющий улучшения a11y и поддержку Vite и Astro. Но мы не останавливаемся на достигнутом, у нас еще много планов и мы видим светлое будущее библиотеки.

Я надеюсь, что мы сможем продолжать работать над Skeleton как можно дольше и создать лучшую библиотеку компонентов пользовательского интерфейса для Svelte. Если вы заинтересованы в том, чтобы попробовать его, ознакомьтесь с официальной документацией здесь:
https://skeleton.brainandbonesllc.com/

Присоединяйтесь к нам на Github
https://github.com/Brain-Bones/skeleton

Или загляните к нам и поздоровайтесь в Discord:
https://discord.gg/EXqV7W8MtY

Мы будем рады видеть вас и приветствуем вклад каждого, кто хочет и может! Серьезно, спасибо всем, кто продолжает помогать делать это возможным! 🙏

Оцените статью
devanswers.ru
Добавить комментарий