Hyperapp — минималистичный фреймворк для построения пользовательских интерфейсов на JavaScript, который ориентирован на простоту и реактивность. Одной из ключевых практик при создании крупных приложений является оптимизация загрузки и снижение объема начального бандла. Это достигается с помощью ленивой загрузки компонентов и разделения кода.
Ленивая загрузка (lazy loading) заключается в том, чтобы определенные части приложения загружались только при необходимости. В контексте Hyperapp это обычно относится к отдельным страницам или тяжелым компонентам. Такой подход позволяет:
Ленивая загрузка в Hyperapp тесно связана с динамическим импортом модулей ES6:
const loadComponent = () => import('./MyComponent.js');
Этот синтаксис возвращает промис, который разрешается модулем только
при вызове функции loadComponent.
Разделение кода позволяет разделять приложение на независимые бандлы, которые загружаются по мере необходимости. В Hyperapp это особенно актуально при использовании маршрутизации.
Пример интеграции разделения кода с маршрутизатором:
import { h, app } from "hyperapp";
const state = { page: null };
const actions = {
setPage: page => state => ({ page }),
loadPage: pageModule => async state => {
const module = await pageModule();
return { page: module.default };
}
};
const view = (state, actions) => h("div", {}, [
h("nav", {}, [
h("button", { onclick: () => actions.loadPage(() => import("./Home.js")) }, "Home"),
h("button", { onclick: () => actions.loadPage(() => import("./About.js")) }, "About")
]),
state.page ? h(state.page) : h("p", {}, "Loading...")
]);
app({ init: state, view, node: document.getElementById("app"), actions });
В этом примере:
Home и About загружаются
только при клике.state.page хранит текущий загруженный компонент.loadPage управляет динамическим
импортом.Hyperapp не имеет встроенного механизма для ленивых компонентов, как некоторые другие фреймворки, но асинхронные функции и промисы позволяют реализовать их самостоятельно.
const AsyncComponent = (importFunc) => {
let Loaded = null;
return (state, actions) => {
if (!Loaded) {
importFunc().then(module => {
Loaded = module.default;
actions.refresh();
});
return h("p", {}, "Загрузка...");
}
return h(Loaded, state);
};
};
Здесь:
importFunc — функция динамического импорта.actions.refresh триггерит обновление состояния, чтобы
рендер отобразил загруженный компонент.Для крупных приложений важно комбинировать ленивую загрузку с маршрутизатором. Паттерн выглядит следующим образом:
Пример структуры маршрутов:
const routes = {
"/": () => import("./pages/Home.js"),
"/about": () => import("./pages/About.js"),
"/profile": () => import("./pages/Profile.js")
};
Экшен для обработки маршрутов:
const navigate = path => async (state, actions) => {
if (routes[path]) {
const module = await routes[path]();
return { page: module.default };
}
return { page: null };
};
Hyperapp ориентирован на минимализм, поэтому большинство решений для ленивой загрузки реализуется вручную через асинхронные экшены и промисы. Встроенных средств для автоматического code splitting нет, что даёт гибкость, но требует внимательного управления состоянием и рендером.
Ленивая загрузка и разделение кода в Hyperapp обеспечивают высокую производительность даже при больших приложениях, позволяя загружать только необходимые ресурсы и экономить время и память пользователя.