Создание веб-компонентов с помощью WebC на vanilla JavaScript

Веб-компоненты - это пользовательские, многократно используемые и строго инкапсулированные HTML-компоненты, которые не зависят от библиотек и могут быть использованы в любом проекте JavaScript.
Одним из примеров популярного веб-компонента является тег <video>
. Хотя video
может показаться одним HTML-элементом, на самом деле оно состоит из нескольких HTML-элементов и пользовательской логики, определяющей его поведение.
Web-компоненты
Итак, зачем использовать веб-компоненты? На высоком уровне двумя основными преимуществами веб-компонентов являются инкапсуляция и отсутствие внешних зависимостей.
Веб-компоненты решают проблему инкапсуляции, позволяя вам ограничить влияние вашего кода CSS и JavaScript областью действия вашего компонента.
Конечно, популярные фреймворки JavaScript, такие как React и Angular, помогают вам достичь аналогичных эффектов инкапсуляции. Итак, что же делает веб-компоненты особенными? Этот вопрос подводит нас ко второму преимуществу: веб-компоненты не зависят от библиотек, и вы можете создавать их, используя только встроенные API JavaScript.
Независимый от библиотек характер веб-компонентов особенно полезен при разработке библиотеки компонентов пользовательского интерфейса. В отличие от других библиотек, созданных для конкретных фреймворков, вы можете использовать веб-компоненты для создания библиотеки, которая не связана с одним технологическим стеком. Это означает, что любой может использовать его, независимо от фреймворка JavaScript, который он использует для своего проекта.
Спецификации веб-компонентов
Как правило, при создании веб-компонентов вы будете использовать три спецификации/технологии:
- Пользовательские элементы: API для создания элементов HTML для инкапсуляции пользовательского кода HTML, JavaScript и CSS.
- Shadow DOM: API для прикрепления скрытого DOM к элементу, который не конфликтует с кодом CSS или JavaScript в других частях вашего приложения.
- Шаблоны: API для повторного использования структуры разметки. Используя тег
<template>
, вы можете определить структуру разметки, которая не отображается сразу при загрузке страницы, но предназначена для дублирования с помощью JavaScript
Ограничения веб-компонентов
Как и любая технология, веб-компоненты имеют ограничения. Давайте кратко рассмотрим их.
Веб-компоненты требуют, чтобы браузеры разрешали запуск JavaScript в вашем веб-приложении, даже если ваш веб-компонент является чисто презентационным и не содержит никакого интерактивного кода JavaScript.
Как правило, вам нужно было бы писать свои веб-компоненты императивным образом, а не декларативным. Это приводит к несколько неуклюжему опыту разработки, особенно при внедрении более продвинутых методов, таких как прогрессивное улучшение. Мы рассмотрим это более подробно в следующем разделе.
Как WebC помогает
Как вы, наверное, догадались, WebC помогает справиться с некоторыми трудностями при работе с веб-компонентами.
WebC- это сериализатор, который генерирует разметку для веб-компонентов. Он не зависит от фреймворка и предоставляет различные полезные инструменты компиляции, которые упрощают написание веб-компонентов.
Как я уже упоминал, веб-компоненты обычно требуют наличия JavaScript, даже для веб-компонентов, в которых нет никакого JavaScript. Но в случае с WebC это не так. Вы можете создавать веб-компоненты только для HTML, которые будут отображаться, даже если в браузере отключен JavaScript. Это потому, что WebC берет код вашего веб-компонента и компилирует его в простой HTML-вывод.
WebC обеспечивает лучший опыт разработки при написании веб-компонентов. С помощью WebC вы можете создавать однофайловые веб-компоненты, которые просты в написании и обслуживании. Они объединяют ваш HTML, CSS и JavaScript-код и упрощают процесс, используя такие функции, как шаблоны и Shadow DOM.
И это только на первый взгляд: WebC обладает большим количеством функций и настроек, которые делают написание веб-компонентов более приятным занятием.
Создание пользовательских веб-компонентов с помощью WebC в проекте vanilla JavaScript
Давайте посмотрим на WebC в действии. В этом уроке мы создадим пользовательский компонент с кнопкой и полем, которое вращается при нажатии кнопки. Это довольно надуманный пример, но он все же поможет нам проиллюстрировать преимущества использования WebC.

Чтобы продолжить, сначала вам нужно настроить проект JavaScript. Мы будем использовать Vite для быстрого запуска нового проекта.
Вам также понадобится установленный Node.js; мы будем использовать его для запуска нашего сценария компиляции веб-камеры, который будет генерировать статические файлы, которые будет обслуживать Vote.
После того, как вы настроили свой проект, запустите yarn add @11ty/webc
, чтобы установить WebC. Далее добавим наш скрипт main.js
, который зарегистрирует страницу WebC и запишет ее содержимое в index.html
в корень нашего проекта:
import { WebC } from "@11ty/webc";
import fs from "fs";
let page = new WebC();
page.defineComponents("components/**.webc");
page.setInputPath("page.webc");
let { html, css, js, components } = await page.compile();
fs.writeFile("./index.html", html, (err) => {
if (err) {
console.log({ err });
}
});
Итак, вот что происходит выше:
- Во-первых, мы создаем объект страницы WebC. Это страница, которая будет содержать наш пользовательский веб-компонент.
- Используя
page.setInputPath("page.webc");
, мы определяем источник контента для нашей страницы. Страницы и компоненты WebC обычно имеют расширение файла.webc
. - Используя
page.defineComponents("components/**.webc");
мы определяем папку, в которой мы будем хранить наши веб-компоненты. - Мы вызываем
page.compile()
для агрегирования и компиляции содержимого страницы в статический вывод HTML. - Наконец, мы записываем выходной HTML в файл
index.html.
Прежде чем двигаться дальше, давайте кратко рассмотрим разницу между страницами и компонентами. В WebC страницы — это файлы, которые начинаются с <!doctype
или <html
и обычно используются для отображения всей страницы.
Компоненты — это любые другие файлы WebC, которые используются для отображения повторно используемых частей или фрагментов пользовательского интерфейса.
Теперь давайте создадим наш файл page.webc
и попробуем запустить наш скрипт. Файл будет содержать базовую настройку HTML-страницы:
<!-- HTML-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebC tutorial</title>
</head>
<body>
<my-component></my-component>
</body>
<style>
body {
padding: 20%;
}
</style>
</html>
Вы могли заметить, что это выглядит точно так же, как наш стандартный HTML, и это потому, что это так! С WebC вы используете обычные HTML, JavaScript и CSS, за исключением нескольких случаев, когда вам нужно добавить некоторый синтаксис WebC.
Теперь давайте попробуем запустить наш скрипт. Вы можете запустить его, просто используя команду node main.js
. Однако для лучшего опыта разработчика я рекомендую использовать nodemon. Он подхватит любые изменения, которые вы вносите в свой скрипт, и автоматически перезапустит файл.
Вот команда nodemon, который мы использовали для этого урока:
nodemon main.js -e js,webc,html
Далее добавим наш веб-компонент, создав папку components
и поместив туда файл my-component.webc
. Добавим следующий контент:
<!-- HTML-->
<div id="rectangle"></div>
<button id="flipper">Flip</button>
<style webc:scoped>
#rectangle {
background-color: skyblue;
width: 40px;
height: 160px;
border: 2px #4ba3c6 solid;
}
button {
margin-top: 12px;
width: 40px;
}
</style>
Опять же, мы используем простой HTML и CSS для настройки и стиля кнопки и элемента div
для нашего блока.
Использование атрибута webc:scoped в тегах style
Одной из примечательных частей приведенного выше примера является атрибут webc:scoped
в нашем теге style
. Этот тег позволяет вам инкапсулировать код CSS внутри вашего компонента.
Когда вы добавите этот атрибут в тег style
, WebC автоматически сгенерирует и назначит уникальный класс хешированной строки элементу вашего компонента во время компиляции. Затем он добавляет префикс этой хэш-строки перед всеми селекторами CSS, которые вы объявляете внутри своего компонента.
Популярные библиотеки стилей, такие как emotion
и styled-Components
, используют аналогичный механизм генерации хэшей для включения стилей в пользовательские компоненты.
Добавление функциональности JavaScript в наш веб-компонент
Пока что мы определили, как выглядит наш веб-компонент, но он мало что делает. Давайте добавим код JavaScript для взаимодействия.
В том же веб-компоненте прямо под тегом style
добавьте тег script
со следующим кодом JavaScript:
<!-- HTML-->
<script>
let deg = 0;
document.getElementById("flipper").onclick = () => {
const rectangle = document.getElementById("rectangle");
const nextDeg = deg === 0 ? 90 : 0;
rectangle.style.transform = `rotate(${nextDeg}deg)`
deg = nextDeg;
}
</script>
Здесь мы просто добавляем прослушиватель onclick
к нашей кнопке, которая поворачивает прямоугольник, обновляя атрибут стиля transform
. Обратите внимание, что нам не нужно было определять наш веб-компонент глобально, используя customElements.define;
мы просто добавили код JavaScript для включения нашей кнопки.
И это все, что нужно сделать. Теперь у нас есть работающий, хоть и простой веб-компонент. Если бы вы отключили JavaScript для своего локального сервера с помощью расширения, наш веб-компонент все равно отображался бы, хотя кнопка ничего не делала.
Прогрессивное улучшение с помощью WebC
Еще одна мощная функция WebC — упрощение процесса добавления прогрессивных улучшений в ваше приложение.
Прогрессивное улучшение — это шаблон, который позволяет пользователям сначала получить доступ к основному контенту и функциям веб-сайта. После этого, если возможности браузера пользователя и подключение к Интернету позволяют, пользователи получают улучшения пользовательского интерфейса и дополнительные интерактивные функции.
Давайте добавим в наш компонент простую прогрессивную процедуру улучшения, отключив кнопку до тех пор, пока не станет доступен JavaScript.

Во-первых, нам нужно обновить код в нашем теге script
:
<!-- HTML-->
<script>
let deg = 0;
class MyComponent extends HTMLElement {
connectedCallback() {
document.getElementById("flipper").onclick = () => {
const rectangle = document.getElementById("rectangle");
const nextDeg = deg === 0 ? 90 : 0;
rectangle.style.transform = `rotate(${nextDeg}deg)`
deg = nextDeg;
}
}
}
window.customElements.define("my-component", MyComponent)
</script>
Здесь мы использовали стандартный шаблон для определения веб-компонента с помощью window.customElements.define
, чтобы иметь возможность ждать, пока JavaScript станет доступным.
Теперь давайте добавим обработку CSS к нашей кнопке:
<!-- HTML-->
<style webc:scoped>
#rectangle {
background-color: skyblue;
width: 40px;
height: 160px;
border: 2px #4ba3c6 solid;
}
button {
margin-top: 12px;
width: 40px;
}
:host:not(:defined)>button {
opacity: 0.2;
cursor: not-allowed;
}
</style>
Как видите, мы используем селектор :host:not(:defined)
. Этот селектор исходит из API Shadow DOM и позволяет вам определять специальные стили для ваших веб-компонентов во время их загрузки.
Тем не менее, WebC делает это по-своему: когда ваш код компилируется, он заменяет часть :host
сгенерированным классом хеш-строки.
Теперь, если вы отключите JavaScript для своего локального сервера, вы увидите, что кнопка неактивна, и более очевидно, что кнопка ничего не делает.

Вы можете использовать тот же шаблон, чтобы дать вашей веб-странице любое прогрессивное улучшение, которое вы хотите.
Заключение
Это все для этого поста. Мы рассмотрели веб-компоненты, варианты их использования и их сравнение с фреймворками JavaScript.
Кроме того, мы обсудили, как WebC устраняет некоторые недостатки веб-компонентов и помогает нам в полной мере воспользоваться их преимуществами.