CesiumJS представляет собой крупную модульную систему, включающую ядро рендеринга, движок сцен, обработку 3D Tiles, работу с террейном, провайдерами изображений, а также набор вспомогательных утилит и веб-воркеров. При подключении библиотеки целиком формируется значительный по объёму JavaScript-бандл, что делает стратегию разделения кода критически важной для производственных приложений.
Code splitting в контексте CesiumJS направлен на уменьшение времени первичной загрузки, оптимизацию использования сети и перенос части вычислений и инициализации на момент реальной необходимости функционала.
Архитектура CesiumJS включает несколько крупных подсистем, которые логически изолированы и могут загружаться независимо:
Viewer и базовые математические утилитыКаждая подсистема содержит как синхронные модули, так и динамически используемые компоненты. Это создаёт естественные границы для разделения чанков.
Разделение кода в CesiumJS-приложениях обычно опирается на три уровня:
Модульность ES6 позволяет импортировать только необходимые части библиотеки:
import { Viewer } from "cesium/Source/Widgets/Viewer/Viewer.js";
Однако такой подход требует аккуратного управления зависимостями, так как внутренние импорты Cesium могут тянуть дополнительные модули.
Ключевая стратегия заключается в переносе создания Viewer в отдельный чанк:
async function createCesiumViewer(container) {
const cesiumModule = await import("cesium");
return new cesiumModule.Viewer(container, {
terrainProvider: new cesiumModule.EllipsoidTerrainProvider(),
});
}
Такой подход позволяет исключить Cesium из основного бандла и загрузить его только при переходе к 3D-визуализации.
CesiumJS часто используется в приложениях с несколькими режимами работы:
Каждый режим может быть выделен в отдельный чанк:
const load3DModule = () => import("./modules/cesium3d/index.js");
const loadMeasurementTools = () => import("./modules/analysis/measurements.js");
Такое разделение снижает начальную нагрузку на браузер и позволяет масштабировать приложение.
Подсистема 3D Tiles является одной из самых тяжёлых частей CesiumJS. Её инициализация часто откладывается до момента появления сцены:
async function loadTileset(url) {
const cesium = await import("cesium");
const tileset = await cesium.Cesium3DTileset.fromUrl(url);
return tileset;
}
Отдельный чанк для 3D Tiles предотвращает загрузку декодеров и обработчиков до фактического запроса данных.
CesiumJS активно использует веб-воркеры для геометрических вычислений и декодирования форматов. Эти воркеры могут быть вынесены в отдельные бандлы:
При использовании Webpack требуется явное указание путей:
window.CESIUM_BASE_URL = "/cesium/";
И копирование статических ресурсов:
new CopyWebpackPlugin({
patterns: [
{ from: "node_modules/cesium/Build/Cesium/Workers", to: "Workers" }
]
});
Разделение воркеров позволяет избежать блокировки основного потока при инициализации.
CesiumJS использует набор внешних ресурсов: шейдеры, текстуры, воркеры. Эти ресурсы не попадают в JavaScript-бандл и требуют отдельной загрузки.
Корректная настройка базового пути критична для code splitting:
window.CESIUM_BASE_URL = "/assets/cesium/";
Это позволяет отделить статические ресурсы от JS-логики и размещать их в CDN или отдельном домене.
Webpack требует настройки для корректной работы динамических импортов Cesium:
Пример разделения:
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
cesium: {
test: /[\\/]cesium[\\/]/,
name: "cesium",
chunks: "all",
},
},
},
}
Vite обеспечивает более естественное разделение благодаря native ESM:
export default {
build: {
rollupOptions: {
output: {
manualChunks: {
cesium: ["cesium"],
},
},
},
},
};
Cesium при этом загружается как отдельный динамический модуль без дополнительной трансформации.
Cesium Viewer содержит множество подсистем, которые не обязаны инициализироваться сразу:
Отложенная инициализация позволяет уменьшить initial bundle execution cost:
async function enablePostProcessing(viewer) {
const cesium = await import("cesium");
viewer.scene.postProcessStages.fxaa.enabled = true;
viewer.scene.postProcessStages.bloom.enabled = true;
}
В современных приложениях Cesium часто используется внутри UI-фреймворков. Разделение кода между UI и движком снижает блокировку интерфейса.
Типичная структура:
UI и Cesium загружаются независимо:
const loadUI = () => import("./ui/app.js");
const loadCesiumRuntime = () => import("./cesium/runtime.js");
ImageryProvider и TerrainProvider могут быть отложены до момента изменения режима отображения.
async function setTerrain(viewer, url) {
const cesium = await import("cesium");
viewer.terrainProvider = await cesium.CesiumTerrainProvider.fromUrl(url);
}
Разделение этих компонентов уменьшает стартовую нагрузку на сеть и CPU.
В SPA-архитектуре Cesium обычно подключается только на определённых маршрутах:
/map2d — без Cesium/map3d — загрузка Cesium chunk/analysis — частичная загрузка Cesium modulesМаршрутная стратегия позволяет полностью исключить Cesium из критического пути загрузки.
Cesium включает математические библиотеки, декодеры и графические утилиты. При неаккуратной сборке они попадают в общий bundle.
Выделение зависимостей:
Каждый слой может быть вынесен в отдельный динамический импорт или отдельный бандл, что уменьшает размер основного entrypoint.
Viewer является центральным объектом CesiumJS и часто становится границей разделения кода:
export async function initViewer(container) {
const cesium = await import("cesium");
const viewer = new cesium.Viewer(container, {
animation: false,
timeline: false,
});
return viewer;
}
Отделение Viewer от bootstrap-логики приложения позволяет полностью контролировать момент загрузки тяжёлых зависимостей.
Code splitting эффективно только при корректной стратегии кэширования:
Cesium ресурсы особенно чувствительны к кэшированию воркеров и шейдеров, так как их повторная загрузка может существенно замедлять запуск сцены.
Некоторые модули Cesium имеют транзитивные зависимости, которые могут неожиданно попасть в основной bundle:
Контроль этих зависимостей требует анализа графа модулей и корректного разделения entrypoints на уровне сборщика.
Типовая схема code splitting в CesiumJS-приложении включает: