Code splitting — техника разделения кода на отдельные части (чанки), которые загружаются по мере необходимости. В контексте клиентских приложений на JavaScript это позволяет уменьшить начальный размер бандла и ускорить первичную загрузку страницы. В библиотеке Navigo code splitting реализуется через динамический импорт модулей в обработчиках маршрутов.
Navigo позволяет назначать функции-обработчики на каждый маршрут.
Вместо того чтобы импортировать все модули сразу, можно использовать
динамический import():
import Navigo from 'navigo';
const router = new Navigo('/');
router.on('/home', async () => {
const { default: homeModule } = await import('./modules/home.js');
homeModule.init();
});
router.on('/about', async () => {
const { default: aboutModule } = await import('./modules/about.js');
aboutModule.init();
});
router.resolve();
Ключевые моменты:
import('./modules/home.js') возвращает промис.default — стандартный
экспорт ES6.init() отвечает за рендеринг или логику
страницы.Таким образом, код модуля подгружается только тогда, когда пользователь переходит на соответствующий маршрут.
В больших приложениях часто используется концепция lazy loading компонентов. Navigo позволяет подключать асинхронные компоненты аналогично:
router.on('/dashboard', async () => {
const { Dashboard } = await import('./components/Dashboard.js');
const dashboard = new Dashboard();
dashboard.render();
});
Особенности:
await внутри обработчика маршрута
для последовательной загрузки зависимостей.Современные сборщики, такие как Webpack, поддерживают именование чанков. Это упрощает отладку и контроль загрузки:
router.on('/profile', async () => {
const { default: profileModule } = await import(
/* webpackChunkName: "profile" */ './modules/profile.js'
);
profileModule.init();
});
Преимущества именованных чанков:
profile.js), вместо
генерации случайного хеша.При использовании динамического импорта важно предусмотреть обработку ошибок, например при отсутствии модуля или проблемах с сетью:
router.on('/settings', async () => {
try {
const { default: settingsModule } = await import('./modules/settings.js');
settingsModule.init();
} catch (err) {
console.error('Ошибка загрузки модуля settings:', err);
document.body.innerHTML = '<h1>Ошибка загрузки страницы</h1>';
}
});
Рекомендации:
try/catch для промисов
динамических импортов.Если страница зависит от нескольких модулей, их можно загружать
параллельно с помощью Promise.all:
router.on('/analytics', async () => {
try {
const [chartsModule, tableModule] = await Promise.all([
import('./modules/charts.js'),
import('./modules/table.js')
]);
chartsModule.default.init();
tableModule.default.init();
} catch (err) {
console.error('Ошибка загрузки модулей analytics:', err);
}
});
Преимущества:
При использовании code splitting важно учитывать состояние приложения. Например, если модуль зависит от глобального состояния или store:
import store from './store.js';
router.on('/cart', async () => {
const { default: cartModule } = await import('./modules/cart.js');
cartModule.init(store.getState());
});
Особенности интеграции:
Navigo автоматически перехватывает переходы по ссылкам внутри приложения. Это позволяет применять code splitting без перезагрузки страницы:
document.querySelectorAll('a[data-navigo]').forEach(link => {
link.addEventListener('click', e => {
e.preventDefault();
router.navigate(link.getAttribute('href'));
});
});
Преимущества:
Эти подходы позволяют создавать быстрые, отзывчивые SPA с минимальным первоначальным бандлом и поддержкой масштабируемого кода.