Stencil — это компилятор веб-компонентов, ориентированный на создание быстрых, многоразовых компонентов с поддержкой современных стандартов. Основой проекта Stencil является структура, которая обеспечивает модульность и масштабируемость.
Проект Stencil обычно содержит следующие ключевые директории:
src/components — место для создания
пользовательских компонентов. Каждый компонент располагается в отдельной
папке с файлом TypeScript и шаблоном HTML.src/utils — вспомогательные функции и
утилиты.www — директория для сборки и
демонстрации компонентов.stencil.config.ts — конфигурационный
файл проекта, где задаются параметры сборки, плагины и оптимизации.Каждый компонент в Stencil реализуется как класс с декоратором
@Component, который определяет селектор, шаблон и стили.
Например:
import { Component, Prop, h } from '@stencil/core';
@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true
})
export class MyComponent {
@Prop() title: string;
render() {
return <div>{this.title}</div>;
}
}
Ключевым элементом Stencil являются реактивные свойства, которые позволяют автоматически отслеживать изменения состояния компонента. Основные декораторы:
@Prop() — свойства, передаваемые
компоненту извне.@State() — внутреннее состояние
компонента, изменения которого вызывают повторный рендер.@Event() — создание пользовательских
событий для коммуникации между компонентами.@Method() — публичные методы
компонента, доступные через DOM.Пример использования @State:
import { Component, State, h } from '@stencil/core';
@Component({
tag: 'counter-component',
shadow: true
})
export class CounterComponent {
@State() count = 0;
increment() {
this.count += 1;
}
render() {
return (
<button onCl ick={() => this.increment()}>
Счетчик: {this.count}
</button>
);
}
}
Stencil предоставляет несколько хуков жизненного цикла, которые позволяют контролировать процесс создания, рендера и уничтожения компонентов:
componentWillLoad() — вызывается перед
первым рендером.componentDidLoad() — после первого
рендера.componentShouldUpdate() — позволяет
предотвратить обновление компонента при определенных условиях.componentWillUpdate() — перед
повторным рендером.componentDidUpdate() — после
повторного рендера.componentDidUnload() — при удалении
компонента из DOM.Эти хуки необходимы для управления состоянием и оптимизации производительности.
Stencil поддерживает Shadow DOM, что обеспечивает инкапсуляцию стилей и предотвращает их утечку в глобальный контекст. Для компонентов с Shadow DOM применяются отдельные CSS-файлы или CSS-in-JS подход.
@Component({
tag: 'styled-component',
styleUrl: 'styled-component.css',
shadow: true
})
export class StyledComponent {
render() {
return <p class="text">Стили из Shadow DOM</p>;
}
}
Для глобальных стилей используется конфигурация
globalStyle в stencil.config.ts, что позволяет
объединять общие CSS для всех компонентов.
Stencil поддерживает работу с асинхронными данными через стандартные
механизмы Jav * aScript: fetch, async/await,
Promises. Для обновления состояния после получения данных используется
@State или forceUpdate().
@Component({
tag: 'data-component',
shadow: true
})
export class DataComponent {
@State() data: any;
async componentWillLoad() {
const response = await fetch('https://api.example.com/data');
this.data = await response.json();
}
render() {
return <div>{JSON.stringify(this.data)}</div>;
}
}
Stencil компилирует компоненты в ванильный JavaScript и применяет ленивую загрузку, что снижает вес конечного бандла. Основные техники оптимизации:
Использование @Prop() и @State()
минимизирует лишние рендеры, так как Stencil отслеживает изменения
реактивных свойств автоматически.
Stencil-компоненты могут использоваться в любых фронтенд-фреймворках: React, Angular, Vue, благодаря поддержке стандартных веб-компонентов. Для интеграции создаются обертки, которые позволяют использовать Stencil-компоненты как обычные элементы.
import { defineCustomElements } from 'my-stencil-components/loader';
defineCustomElements(window);
После этого компоненты доступны в любом приложении как обычные HTML-теги.
Stencil включает встроенные возможности для юнит- и e2e-тестирования:
Пример простого теста с Jest:
import { newSpecPage } from '@stencil/core/testing';
import { MyComponent } from './my-component';
it('рендерит заголовок', async () => {
const page = await newSpecPage({
components: [MyComponent],
html: `<my-component title="Привет"></my-component>`,
});
expect(page.root.textContent).toBe('Привет');
});
Для отслеживания пользовательского опыта в реальном времени в Stencil-приложениях интегрируются RUM-инструменты. Это позволяет измерять метрики загрузки, взаимодействия и стабильности компонентов:
RUM-интеграция обычно реализуется через отдельный сервис или SDK,
подключаемый в index.html или через глобальные хуки
Stencil.
componentDidLoad() {
if (window.RUM) {
window.RUM.trackComponentLoad(this.tagName);
}
}
Это позволяет получать точные данные о производительности и использовании компонентов в реальных условиях.
Использование Stencil позволяет создавать легкие, масштабируемые и совместимые с любыми фронтенд-фреймворками веб-компоненты. Комбинация реактивных свойств, Shadow DOM, жизненного цикла и RUM-метрик обеспечивает высокую производительность и полную прозрачность взаимодействия с пользователем.