Page.js — это легковесная клиентская библиотека для маршрутизации на стороне браузера, которая позволяет создавать одностраничные приложения (SPA) с управляемой навигацией без перезагрузки страницы. Применение модульной архитектуры в сочетании с Page.js позволяет структурировать код так, чтобы маршруты, контроллеры и представления оставались независимыми, легко тестируемыми и расширяемыми.
В модульной архитектуре каждый маршрут должен быть привязан к отдельному контроллеру. Контроллер — это модуль, который отвечает за обработку данных и взаимодействие с представлением. Пример структуры проекта:
/app
/controllers
homeController.js
aboutController.js
userController.js
/views
homeView.js
aboutView.js
userView.js
/routes
index.js
app.js
homeController.js:
import { renderHome } from '../views/homeView.js';
export function homeController(ctx) {
const data = { title: 'Главная страница', content: 'Добро пожаловать!' };
renderHome(data);
}
aboutController.js:
import { renderAbout } from '../views/aboutView.js';
export function aboutController(ctx) {
const data = { title: 'О нас', content: 'Информация о компании' };
renderAbout(data);
}
Маршруты лучше держать в отдельном модуле, чтобы не смешивать конфигурацию навигации с логикой контроллеров:
routes/index.js:
import page from 'page';
import { homeController } from '../controllers/homeController.js';
import { aboutController } from '../controllers/aboutController.js';
import { userController } from '../controllers/userController.js';
export function setupRoutes() {
page('/', homeController);
page('/about', aboutController);
page('/user/:id', userController);
page();
}
page(path, handler) — назначает
обработчик для конкретного маршрута.:id) позволяют
получать параметры маршрута через объект ctx.params.Каждый обработчик получает объект ctx, который
содержит:
ctx.path — текущий путь в адресной строке.ctx.params — параметры маршрута (например,
ctx.params.id).ctx.querystring — строка запроса после
?.ctx.state — объект для хранения данных между middleware
и контроллерами.Использование ctx.state упрощает передачу информации
между различными модулями без глобальных переменных.
Page.js поддерживает middleware, позволяя выстраивать цепочки обработки маршрутов. Это ключевой инструмент модульной архитектуры, так как позволяет разделять авторизацию, валидацию и рендеринг.
Пример middleware для авторизации:
function authMiddleware(ctx, next) {
if (!ctx.state.user) {
page.redirect('/login');
} else {
next();
}
}
Использование в маршрутах:
page('/dashboard', authMiddleware, dashboardController);
next().Представления также лучше держать в отдельных модулях. Это обеспечивает независимость от контроллеров и упрощает тестирование. Представление обычно получает данные и формирует HTML:
homeView.js:
export function renderHome(data) {
const app = document.getElementById('app');
app.innerHTML = `
${data.title}
${data.content}
`;
}
Преимущества модульного подхода:
Page.js позволяет создавать маршруты с динамическими сегментами, что особенно полезно для SPA с профилями пользователей или товарами.
userController.js:
import { renderUser } from '../views/userView.js';
export function userController(ctx) {
const userId = ctx.params.id;
const userData = getUserDataById(userId);
renderUser(userData);
}
ctx.params.id получает значение из URL
/user/123.getUserDataById может быть отдельным модулем
сервиса, что соответствует принципам модульной архитектуры.Контроллеры могут выполнять асинхронные операции, такие как запросы к API. Page.js поддерживает async функции:
export async function userController(ctx) {
try {
const user = await fetch(`/api/users/${ctx.params.id}`).then(res => res.json());
renderUser(user);
} catch (error) {
console.error('Ошибка загрузки пользователя', error);
}
}
Модульная архитектура предполагает централизованное хранение
состояния приложения. Можно создать отдельный модуль
store.js:
export const state = {
user: null,
settings: {}
};
export function setUser(user) {
state.user = user;
}
export function setSettings(settings) {
state.settings = settings;
}
Контроллеры и middleware используют этот модуль для чтения и изменения состояния, что исключает глобальные переменные и делает код предсказуемым.
Page.js легко интегрируется с компонентными библиотеками и фреймворками:
Эта модульная организация облегчает масштабирование приложения и поддержку сложной логики навигации.