Bundle splitting — техника разделения JavaScript-кода на несколько независимых бандлов, загружаемых по требованию. В приложениях на Mithril эта практика особенно уместна из-за минималистичного ядра фреймворка и отсутствия жёстко навязанной архитектуры. Разделение кода позволяет сохранить быстрый первый рендер, не жертвуя масштабируемостью и модульностью при росте проекта.
Ключевая цель — отделить критический путь загрузки (core bundle) от функциональности, необходимой только в определённых сценариях: маршруты, административные разделы, тяжёлые визуализации, редакторы, интеграции.
Mithril не диктует способ сборки и не содержит встроенного механизма код-сплиттинга. Разделение бандлов достигается за счёт:
import()), поддерживаемого
современными сборщиками;m.route с асинхронным разрешением
компонентов.Фреймворк не препятствует ленивой загрузке: компонент — это функция или объект, и его можно получить асинхронно.
Типичная структура проекта:
src/
├─ index.js
├─ app.js
├─ routes/
│ ├─ home.js
│ ├─ profile.js
│ └─ admin.js
└─ components/
└─ ...
index.js и app.js формируют
основной бандл:
import m from "mithril"
import App from "./app"
m.mount(document.body, App)
Этот код должен оставаться максимально компактным: инициализация, глобальные стили, конфигурация роутера.
ES-синтаксис import() возвращает Promise и служит
основным инструментом код-сплиттинга.
Пример ленивой загрузки компонента:
const AdminPage = () =>
import("./routes/admin.js").then(m => m.default)
Сборщик (Vite, Webpack, Rollup) автоматически выделит
admin.js в отдельный чанк.
m.route поддерживает асинхронное разрешение маршрутов
через onmatch. Это каноничный способ ленивой загрузки
страниц.
m.route(document.body, "/", {
"/": Home,
"/profile": {
onmatch: () =>
import("./routes/profile.js").then(m => m.default)
},
"/admin": {
onmatch: () =>
import("./routes/admin.js").then(m => m.default)
}
})
Пока Promise не разрешён, Mithril не выполняет рендер маршрута. Это гарантирует отсутствие обращения к ещё не загруженному коду.
Асинхронные маршруты допускают возврат объекта-компонента с логикой отображения состояния загрузки:
const LazyRoute = loader => {
let Component = null
return {
oninit: () => loader().then(m => Component = m.default),
view: () => Component ? m(Component) : m("div", "Loading...")
}
}
Использование:
"/admin": LazyRoute(() => import("./routes/admin.js"))
Подход удобен при необходимости повторного использования паттерна.
Код-сплиттинг применим и к локальным компонентам:
Пример ленивой загрузки модального окна:
let Modal = null
const openModal = async () => {
if (!Modal) {
Modal = (await import("./components/Modal.js")).default
}
}
Компонент загружается только при первом вызове.
Mithril не хранит состояние компонентов вне текущего дерева. При ленивой загрузке важно учитывать:
Это делает код-сплиттинг предсказуемым и безопасным: загрузка кода не влияет на жизненный цикл уже смонтированных компонентов.
Vite использует Rollup для production-сборки. Динамический импорт автоматически создаёт чанки:
import("./routes/admin.js")
Дополнительная настройка не требуется. Для контроля имён чанков:
import(/* @vite-ignore */ "./routes/admin.js")
или через build.rollupOptions.output.manualChunks.
Webpack поддерживает magic comments:
import(
/* webpackChunkName: "admin" */
"./routes/admin.js"
)
Это упрощает анализ бандлов и кэширование.
Некоторые сценарии требуют загрузки кода заранее, но не блокируя основной поток.
import("./routes/profile.js")
Вызов без использования результата инициирует загрузку чанка. Часто применяется при наведении на ссылку:
const preloadProfile = () => {
import("./routes/profile.js")
}
Асинхронный импорт может завершиться ошибкой. Mithril не перехватывает её автоматически.
Пример обработки:
onmatch: () =>
import("./routes/admin.js")
.then(m => m.default)
.catch(() => ErrorPage)
Такой подход важен для офлайн-режима и нестабильных сетей.
Размер Mithril (~10 KB gzipped) делает его идеальной основой для агрессивного код-сплиттинга. В отличие от фреймворков с тяжёлым runtime, основной бандл остаётся минимальным даже при росте функциональности.
Практический эффект:
Для крупных приложений применяется многоуровневое разделение:
Каждый уровень загружается строго по необходимости, без утечки зависимостей в основной бандл.
Код-сплиттинг увеличивает:
В Mithril это компенсируется простотой компонентов и отсутствием скрытой магии. Все точки загрузки видны в коде и полностью контролируются разработчиком.
Bundle splitting в Mithril — не вспомогательная оптимизация, а органичная часть архитектуры. Асинхронные маршруты, динамические импорты и минималистичное ядро позволяют строить приложения с чётким контролем над загрузкой кода, не усложняя модель мышления и не нарушая принципов фреймворка.