Real User Monitoring

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.

Эти хуки необходимы для управления состоянием и оптимизации производительности.

Shadow 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 и применяет ленивую загрузку, что снижает вес конечного бандла. Основные техники оптимизации:

  • Lazy Loading — компоненты подгружаются по мере необходимости.
  • Hydration — серверный рендеринг с последующим “оживлением” на клиенте.
  • Tree Shaking — удаление неиспользуемого кода.

Использование @Prop() и @State() минимизирует лишние рендеры, так как Stencil отслеживает изменения реактивных свойств автоматически.

Интеграция с другими фреймворками

Stencil-компоненты могут использоваться в любых фронтенд-фреймворках: React, Angular, Vue, благодаря поддержке стандартных веб-компонентов. Для интеграции создаются обертки, которые позволяют использовать Stencil-компоненты как обычные элементы.

import { defineCustomElements } from 'my-stencil-components/loader';

defineCustomElements(window);

После этого компоненты доступны в любом приложении как обычные HTML-теги.

Тестирование компонентов

Stencil включает встроенные возможности для юнит- и e2e-тестирования:

  • Jest — для тестирования логики и рендеринга.
  • Puppeteer — для e2e-тестов и проверки взаимодействий с DOM.

Пример простого теста с 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('Привет');
});

Подключение Real User Monitoring (RUM)

Для отслеживания пользовательского опыта в реальном времени в Stencil-приложениях интегрируются RUM-инструменты. Это позволяет измерять метрики загрузки, взаимодействия и стабильности компонентов:

  • Метрики загрузки страницы: время до первого рендера, интерактивности.
  • События взаимодействия: клики, скролл, ввод данных.
  • Ошибки и исключения: логирование и передача на сервер аналитики.

RUM-интеграция обычно реализуется через отдельный сервис или SDK, подключаемый в index.html или через глобальные хуки Stencil.

componentDidLoad() {
  if (window.RUM) {
    window.RUM.trackComponentLoad(this.tagName);
  }
}

Это позволяет получать точные данные о производительности и использовании компонентов в реальных условиях.

Заключение технических аспектов

Использование Stencil позволяет создавать легкие, масштабируемые и совместимые с любыми фронтенд-фреймворками веб-компоненты. Комбинация реактивных свойств, Shadow DOM, жизненного цикла и RUM-метрик обеспечивает высокую производительность и полную прозрачность взаимодействия с пользователем.