Павел Гринченко в блоге Злых Марсиан описал способ разработки маркетинговых сайтов с использованием веб-компонентов и разработанного для них инструмента под названием nanotags, в основе которого другое решение от Марсиан — nanostores.
Маркетинговый сайт — это не приложение с тяжёлой логикой и большим количеством интерактивности. Это статический контент с точечными интерактивными элементами. Такие сайты создаются с использованием генераторов статики, в частности Astro.
Остаётся вопрос с тем, как добавлять ту самую интерактивность. Павел считает API веб-компонентов, встроенные в браузеры, полезными для этой задачи. Но в сыром виде API низкоуровневые и многословные. Поэтому была создана библиотека nanotags.
Это лёгкая библиотека, которая добавляет декларативный способ создания пользовательских элементов, поиска узлов, объявления реактивных свойств на основе nanostores и обработки событий. Цель — скрыть шаблонный код под капот.
nanotags рассчитан на работу с готовой разметкой, генерируемой на сервере или при сборке. Шаблонизатор отсутствует, Shadow DOM не используется. Это отличает nanotags от популярной библиотеки для веб-компонентов — Lit.
<my-counter count="0">
<span data-ref="display">0</span>
<button data-ref="button">+1</button>
</my-counter>
<script>
import { define } from "nanotags"
define("my-counter")
.withProps(p => ({
count: p.number(0)
}))
.withRefs(r => ({
display: r.one("span"),
button: r.one("button")
}))
.setup(ctx => {
ctx.on(ctx.refs.button, "click", () => {
ctx.props.$count.set(ctx.props.$count.get() + 1)
})
ctx.effect(ctx.props.$count, val => {
ctx.refs.display.textContent = String(val)
})
})
</script>
В разметке пользовательский элемент
<my-counter>, внутри которого <span> и <button>. Разметка генерируется Astro на этапе сборки. Вместо Astro может быть любой генератор статики или серверное решение, которое отдаёт готовый HTML.Затем подключается nanotags. Функция
define() определяет пользовательский элемент. В withProps() указываются реактивные свойства, их тип и начальное значение. В withRefs() задаются ссылки на узлы, которые должны быть в разметке.В
setup() идёт установка обработчиков событий и эффектов, которые меняют значения реактивных свойств. Доступен объект контекста ctx, в котором хранятся свойства, ссылки на узлы и прочая информация о компоненте.Библиотека хорошо интегрирована с TypeScript, выводит типы, поддерживает Standard Schema валидаторы (Valibot, Zod, ArkType) для свойств, работает с данными в формате JSON, делает проверки в рантайме на основе схем.
Больше возможностей nanotags описано в документации. Это интересный взгляд на то, как работать с веб-компонентами. Миграция сэкономила 100кб JS, что хорошо и позволяет лучше вписываться в бюджеты производительности.
Также я обратил внимание, что библиотека разработана с уважением к стандарту HTML. Ссылки на элементы отмечаются атрибутом
data-ref, JSON-данные хранятся в блоках данных, пользовательские элементы названы в соответствии с правилами.Маленькая деталь, которая, тем не менее, отражает отношение автора к стандартам. Все синтаксические расширения выполнены в соответствии с правилами расширения HTML, без выдуманного синтаксиса с невалидной разметкой. За это от меня респект.
#js #tools