Hot Module Replacement (HMR) представляет собой механизм, позволяющий обновлять модули приложения в браузере без полной перезагрузки страницы. Для веб-компонентов, созданных с помощью SkateJS, HMR особенно важен, так как перезагрузка может привести к потере состояния элементов или их повторной инициализации. SkateJS не предоставляет встроенный HMR, но полностью совместим с популярными инструментами, такими как Webpack или Vite, что позволяет интегрировать HMR на уровне модулей и компонентов.
HMR работает через три ключевых процесса:
Для SkateJS HMR важен потому, что компоненты определяются как классы или фабрики с рендер-функциями. При полной перезагрузке теряется DOM-элемент и его внутренние свойства, а при HMR можно заменить только код класса, сохранив текущий DOM и состояние.
Для работы с HMR в проекте SkateJS через Webpack необходимы следующие шаги:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
hot: true,
open: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
};
import { define, h } from 'skatejs';
class MyComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = `<p>Компонент загружен</p>`;
}
}
define('my-component', MyComponent);
if (module.hot) {
module.hot.accept('./index.js', () => {
console.log('Модуль обновлен через HMR');
});
}
Ключевой момент: HMR обновляет модуль
index.js, но сам DOM-элементmy-componentостаётся на странице, что позволяет сохранить внутреннее состояние.
SkateJS использует props и реактивные рендер-функции
через h() и JSX-подобный синтаксис. Для корректной работы
HMR необходимо правильно обновлять реактивные свойства,
чтобы изменения сразу применялись в уже существующих экземплярах
компонента.
Пример:
import { define, h, props } from 'skatejs';
class Counter extends HTMLElement {
static props = {
count: props.number
};
connectedCallback() {
this.render();
}
render() {
this.innerHTML = `
<div>
<p>Счётчик: ${this.count || 0}</p>
<button id="increment">+</button>
</div>
`;
this.querySelector('#increment').addEventListener('click', () => {
this.count = (this.count || 0) + 1;
this.render();
});
}
}
define('x-counter', Counter);
if (module.hot) {
module.hot.accept('./counter.js', () => {
console.log('Counter модуль обновлён');
});
}
При использовании HMR состояние
countсохраняется, так как DOM-элемент не удаляется. Новая версия класса обновляет только методы и рендер.
SkateJS не позволяет дважды определять один и тот же тег. При HMR необходимо учитывать этот момент:
if (customElements.get('my-component')) {
customElements.define('my-component', class extends customElements.get('my-component') {
connectedCallback() {
super.connectedCallback();
console.log('Обновлённый компонент подключён');
}
});
} else {
define('my-component', MyComponent);
}
Это позволяет безопасно обновлять компонент без ошибок
DOMException: A custom element with name "my-component" has already been defined.
Vite поддерживает HMR “из коробки”, и для SkateJS достаточно использовать модульный импорт компонентов и простой блок:
import './my-component.js';
if (import.meta.hot) {
import.meta.hot.accept('./my-component.js', (newModule) => {
console.log('Компонент обновлён через Vite HMR');
});
}
Vite автоматически заменяет старый класс новым, сохраняя существующие DOM-элементы.
Hot Module Replacement в SkateJS позволяет ускорить процесс разработки, сохраняя состояние компонентов и минимизируя перезагрузку страницы. Правильная настройка HMR через Webpack или Vite обеспечивает стабильное и реактивное обновление компонентов, что особенно важно для больших приложений с динамическими веб-компонентами.