SkateJS — это легковесная библиотека для создания веб-компонентов на основе стандарта Custom Elements, упрощающая работу с DOM и состоянием компонентов. В контексте расширений браузера она особенно полезна, так как позволяет создавать изолированные, повторно используемые UI-блоки, которые легко интегрируются с содержимым страниц и взаимодействуют с фоном расширения.
1. Компоненты как самостоятельные блоки Каждый компонент SkateJS является изолированным элементом, который можно внедрять в DOM любой страницы через расширение. Это позволяет:
2. Рендеринг через JSX или шаблоны SkateJS
поддерживает использование JSX или простых шаблонов для описания
структуры компонентов. В расширениях это критично для генерации
интерфейса всплывающих окон (popup.html) или панели
опций.
Пример минимального компонента:
import { define, Component, h } from 'skatejs';
class UserBadge extends Component {
static get props() {
return {
username: String,
};
}
render() {
return <div class="user-badge">Привет, {this.username}</div>;
}
}
define(UserBadge);
Такой компонент можно динамически вставить в страницу через скрипт контента:
const badge = document.createElement('user-badge');
badge.username = 'Иван';
document.body.appendChild(badge);
1. Связь с фоновым скриптом Компоненты могут
получать данные от background script через
chrome.runtime.sendMessage или
chrome.runtime.onMessage. SkateJS упрощает реактивное
обновление интерфейса при изменении данных:
class NotificationsList extends Component {
static get props() {
return { notifications: Array };
}
connectedCallback() {
super.connectedCallback();
chrome.runtime.onMessage.addListener((msg) => {
if (msg.type === 'NEW_NOTIFICATION') {
this.notifications = [...this.notifications, msg.data];
}
});
}
render() {
return (
<ul>
{this.notifications.map(n => <li>{n.text}</li>)}
</ul>
);
}
}
define(NotificationsList);
2. Встраивание в контент страницы SkateJS-компоненты можно внедрять напрямую в DOM страниц, чтобы добавлять новые элементы интерфейса без необходимости переписывать весь сайт. Преимущество — возможность использовать Shadow DOM, предотвращая конфликт CSS:
const widget = document.createElement('notifications-list');
widget.notifications = [];
document.body.appendChild(widget);
Стили компонента будут инкапсулированы, что особенно важно при работе с внешними страницами.
SkateJS поддерживает инкапсулированные стили, что критично для расширений, которые вставляют UI на сторонние сайты.
import { css } from 'skatejs';
class ColoredButton extends Component {
static get props() { return { label: String }; }
static get styles() {
return css`
button {
background-color: #007bff;
color: white;
border: none;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
`;
}
render() {
return <button>{this.label}</button>;
}
}
define(ColoredButton);
Стили применяются только к компоненту, не затрагивая остальной сайт.
SkateJS предоставляет реактивное обновление при изменении свойств компонента. Это удобно для расширений, где состояние часто меняется:
Пример реактивного счетчика:
class CounterWidget extends Component {
static get props() { return { count: Number }; }
increment() {
this.count += 1;
}
render() {
return (
<div>
<span>{this.count}</span>
<button onCl ick={() => this.increment()}>+</button>
</div>
);
}
}
define(CounterWidget);
Каждое изменение this.count автоматически вызывает
перерисовку интерфейса.
SkateJS-компоненты легко подключаются к API браузера:
chrome.storage — хранение настроек;chrome.tabs — взаимодействие с вкладками;chrome.runtime — обмен сообщениями между компонентом и
фоновым скриптом.Пример использования chrome.storage для загрузки
состояния:
class SettingsPanel extends Component {
static get props() { return { darkMode: Boolean }; }
connectedCallback() {
super.connectedCallback();
chrome.storage.sync.get('darkMode', ({ darkMode }) => {
this.darkMode = darkMode ?? false;
});
}
toggleDarkMode() {
this.darkMode = !this.darkMode;
chrome.storage.sync.set({ darkMode: this.darkMode });
}
render() {
return (
<div>
<label>
<input type="checkbox" checked={this.darkMode} onCha nge={() => this.toggleDarkMode()} />
Темная тема
</label>
</div>
);
}
}
define(SettingsPanel);
Для расширений важно минимизировать нагрузку на страницу. SkateJS позволяет:
Такой подход обеспечивает модульность, повторное использование компонентов и чистую интеграцию с любыми страницами через расширения.