Stencil — это компилятор для создания веб-компонентов на JavaScript, ориентированный на производительность, совместимость с современными фреймворками и повторное использование компонентов. Он использует стандартные веб-технологии, такие как Custom Elements, Shadow DOM и ES Modules, что позволяет создавать универсальные компоненты, интегрируемые практически в любой фронтенд-проект.
Основная идея Stencil заключается в компиляции TypeScript/JSX в высоко оптимизированный JavaScript, минимизируя runtime-зависимости. Это позволяет создавать легкие, быстрые и модульные компоненты с декларативной логикой и поддержкой реактивного обновления данных.
Компоненты в Stencil определяются с помощью декоратора
@Component:
import { Component, Prop, State, h } from '@stencil/core';
@Component({
tag: 'app-user-card',
styleUrl: 'app-user-card.css',
shadow: true
})
export class AppUserCard {
@Prop() name: string;
@State() online: boolean = false;
private toggleStatus() {
this.onl ine = !this.online;
}
render() {
return (
<div class={`card ${this.online ? 'online' : 'offline'}`}>
<h2>{this.name}</h2>
<p>Status: {this.online ? 'Online' : 'Offline'}</p>
<button onCl ick={() => this.toggleStatus()}>Toggle Status</button>
</div>
);
}
}
Ключевые моменты:
@Prop() — свойства компонента, которые можно задавать
извне. Изменения автоматически вызывают перерисовку.@State() — внутренние реактивные состояния, недоступные
извне.h() — функция гиперэлементов (JSX), аналогичная
React.createElement.shadow: true — включение Shadow DOM для изоляции стилей
компонента.Stencil использует реактивную модель, позволяющую автоматически
отслеживать изменения состояний и свойств. Изменение @State
или @Prop инициирует перерендер компонента. Для сложных
вычислений можно использовать геттеры:
get statusText() {
return this.online ? 'В сети' : 'Не в сети';
}
Геттеры не требуют отдельного отслеживания — они вычисляются при каждом рендере.
Для передачи событий наружу используется декоратор
@Event:
import { Event, EventEmitter } from '@stencil/core';
@Event() userToggled: EventEmitter<boolean>;
private toggleStatus() {
this.onl ine = !this.online;
this.userToggled.emit(this.online);
}
Компоненты, слушающие событие, могут использовать стандартный синтаксис DOM:
<app-user-card onUserTogg led="handleToggle"></app-user-card>
Stencil предоставляет набор методов жизненного цикла:
componentWillLoad() — вызывается перед первым рендером,
до загрузки DOM.componentDidLoad() — после первого рендера и вставки в
DOM.componentShouldUpdate(newVal, oldVal) — можно
возвращать false, чтобы предотвратить обновление.componentWillUpdate() — перед обновлением
компонента.componentDidUpdate() — после обновления.disconnectedCallback() — при удалении из DOM.Эти методы позволяют оптимизировать работу с DOM и внешними данными.
Stencil поддерживает scoped и Shadow DOM стили. Можно подключать CSS и SCSS:
@Component({
tag: 'app-user-card',
styleUrl: 'app-user-card.scss',
shadow: true
})
Стили внутри Shadow DOM не влияют на глобальные стили страницы, что исключает конфликты классов.
Stencil генерирует ES-модули и поддерживает ленивую загрузку компонентов:
const lazyComponent = await import('./components/app-user-card.js');
document.body.appendChild(new lazyComponent.AppUserCard());
При использовании ленивой загрузки каждый компонент загружается только при необходимости, снижая время первичной загрузки страницы.
Stencil-компоненты можно использовать в React, Angular, Vue и обычном HTML:
// React
<AppUserCard name="Alice" />
// Angular
<app-user-card name="Alice"></app-user-card>
Компоненты автоматически интегрируются благодаря стандартам Custom Elements.
Для загрузки данных и взаимодействия с API применяются методы
жизненного цикла и async/await:
async componentWillLoad() {
this.userData = await fetchUserData();
}
Можно также использовать @Watch для отслеживания
изменений свойств и выполнения побочных эффектов:
@Watch('name')
onNameChange(newValue: string, oldValue: string) {
console.log(`Имя изменилось с ${oldValue} на ${newValue}`);
}
Stencil полностью написан на TypeScript, что обеспечивает строгую типизацию:
@Prop() userId: number;
@State() userData: { name: string; age: number };
Типизация помогает выявлять ошибки на этапе компиляции и улучшает автодополнение в редакторах.
В контексте Stencil synthetic monitoring позволяет контролировать работу веб-компонентов через имитацию пользовательских действий, API-запросов и обновления состояний без реального взаимодействия с пользователем. Это достигается следующими подходами:
@State и @Prop после вызова методов.Пример тестирования реактивного компонента:
import { newSpecPage } from '@stencil/core/testing';
import { AppUserCard } from './app-user-card';
describe('app-user-card synthetic monitoring', () => {
it('should toggle status correctly', async () => {
const page = await newSpecPage({
components: [AppUserCard],
html: `<app-user-card name="Alice"></app-user-card>`,
});
const button = page.root.shadowRoot.querySelector('button');
button.click();
await page.waitForChanges();
expect(page.rootInstance.online).toBe(true);
});
});
Synthetic monitoring позволяет проводить нагрузочные и функциональные проверки компонентов без запуска полноценного браузерного интерфейса, ускоряя процесс тестирования и обеспечивая стабильность работы в продакшене.
Stencil сочетает возможности веб-стандартов и современного подхода к фронтенд-разработке: компоненты остаются легкими, производительными и кросс-фреймворковыми. Встроенные механизмы реактивности, жизненного цикла и поддержки TypeScript обеспечивают надежную разработку масштабируемых интерфейсов. Synthetic monitoring дополняет эту экосистему инструментами тестирования, позволяя гарантировать корректность работы компонентов в различных сценариях.