Tree shaking

Tree shaking в CesiumJS опирается на специфику модульной архитектуры библиотеки и особенности её упаковки для современных сборщиков. В контексте WebGL-глобусов и геопространственных сцен проблема размера бандла становится критической: стандартное подключение Cesium без оптимизации может приводить к загрузке сотен килобайт или даже мегабайт кода, значительная часть которого в конкретном проекте не используется.

CesiumJS исторически проектировался как крупная монолитная библиотека, включающая:

  • ядро рендеринга WebGL;
  • геометрические примитивы;
  • систему сцен и камер;
  • обработку 3D Tiles;
  • шейдерные программы;
  • утилиты математики и координатных преобразований;
  • вспомогательные компоненты (инпут, события, ресурсы).

Ранние версии распространялись в основном как единый UMD-бандл. В таком виде tree shaking невозможен, поскольку сборщик не может безопасно удалить неиспользуемые части кода.

Современные версии CesiumJS перешли к ES Modules (ESM), что принципиально меняет поведение при сборке. Именно ESM является основой для статического анализа зависимостей, который используют Rollup, Webpack и Vite.

Природа tree shaking в JavaScript сборках

Tree shaking базируется на двух ключевых свойствах:

  • статическая структура import/export;
  • отсутствие побочных эффектов в модулях (или их явное указание через sideEffects).

Сборщик строит граф зависимостей и удаляет все экспортированные сущности, которые не были импортированы в итоговом коде.

Однако в сложных библиотеках, таких как CesiumJS, tree shaking осложняется:

  • наличием side effects в модулях (регистрация классов, глобальные состояния);
  • динамическими импортами;
  • использованием Web Workers;
  • шейдерными строками и ресурсами;
  • сложной иерархией внутренних модулей.

CesiumJS и ESM-экосистема

В ESM-сборке CesiumJS структура модулей позволяет импортировать только необходимые части:

import { Viewer } from "cesium";

или более точечно:

import Camera from "cesium/Source/Scene/Camera.js";

Разница между этими подходами критична:

  • импорт из корня пакета может подтягивать дополнительные зависимости;
  • глубокие импорты позволяют точнее контролировать включаемые модули;
  • но требуют знания внутренней структуры библиотеки.

Роль sideEffects в CesiumJS

Важный аспект tree shaking — корректная настройка поля sideEffects в package.json.

В CesiumJS часть модулей не является чистыми функциями. Например:

  • регистрация глобальных шейдеров;
  • инициализация WebGL state;
  • подключение ресурсов;
  • регистрация классов в глобальных системах Cesium.

Если сборщик считает модуль «чистым», он может удалить его, даже если он нужен косвенно.

Поэтому CesiumJS частично помечает модули как имеющие побочные эффекты, чтобы предотвратить некорректное удаление.

Webpack и CesiumJS: влияние на tree shaking

В Webpack tree shaking работает только в production-режиме и при использовании ESM.

Типичная конфигурация для CesiumJS включает:

  • alias на папку Source;
  • копирование статических ресурсов;
  • настройку CESIUM_BASE_URL.

Проблема заключается в том, что Webpack часто «размывает» границы модулей Cesium из-за:

  • транспиляции;
  • объединения чанков;
  • обработки Web Workers через loader’ы.

В результате часть tree shaking становится менее эффективной.

Vite и Rollup: более эффективное удаление кода

Rollup, на котором основан Vite, обеспечивает более точный tree shaking благодаря:

  • строгому ESM-first подходу;
  • более агрессивному удалению неиспользуемых экспортов;
  • меньшему количеству runtime-обёрток.

В связке с CesiumJS это приводит к более компактным бандлам при условии:

  • использования ESM-импортов;
  • отказа от глобального импорта cesium/Cesium.js;
  • корректной настройки external/static assets.

Гранулярные импорты и их влияние

CesiumJS позволяет импортировать отдельные модули, например:

  • геометрия
  • математика
  • рендеринг сцены
  • утилиты

Пример подхода:

import Cartesian3 from "cesium/Source/Core/Cartesian3.js";
import Color from "cesium/Source/Core/Color.js";

Такой подход:

  • минимизирует итоговый бандл;
  • уменьшает количество неиспользуемых зависимостей;
  • улучшает загрузку на клиенте.

Но он имеет обратную сторону:

  • повышает сложность поддержки;
  • требует знания внутренней структуры CesiumJS;
  • может ломаться при обновлениях версии.

Web Workers и влияние на tree shaking

CesiumJS активно использует Web Workers для:

  • обработки 3D Tiles;
  • загрузки и декодирования данных;
  • генерации геометрии.

Workers усложняют tree shaking, потому что:

  • они часто загружаются как отдельные entry points;
  • их зависимости должны быть полностью доступны на этапе сборки;
  • сборщик не всегда может анализировать их граф зависимостей.

Это приводит к тому, что часть кода остаётся в бандле «на всякий случай».

Шейдеры и статические ресурсы

Одной из самых тяжёлых частей CesiumJS являются:

  • GLSL шейдеры;
  • изображения текстур;
  • JSON-описания материалов;
  • WASM или бинарные ресурсы (в некоторых сборках).

Tree shaking не может удалить такие ресурсы, если они:

  • динамически импортируются;
  • связаны через runtime-строки;
  • используются внутри engine pipeline.

Поэтому оптимизация CesiumJS чаще смещается в сторону code splitting, а не только tree shaking.

Оптимизация импорта Viewer как антипаттерн

import { Viewer } from "cesium";

такой импорт часто приводит к включению:

  • Scene;
  • Globe;
  • Imagery layers;
  • Terrain providers;
  • Default widgets;
  • Event system.

Это удобно, но почти всегда избыточно.

Более строгий подход — разбиение функциональности:

  • создание Scene вручную;
  • подключение только нужных провайдеров;
  • отказ от стандартного UI.

Переход к минимальным сборкам CesiumJS

В современных проектах CesiumJS часто используется как:

  • ядро рендеринга;
  • без UI-обвязки;
  • с кастомной системой слоёв.

Это позволяет:

  • существенно сократить итоговый бандл;
  • ускорить initial load;
  • уменьшить время гидратации сцены.

Tree shaking в таком подходе становится эффективнее, потому что:

  • уменьшается количество импортируемых entry points;
  • убираются зависимости widgets;
  • исключаются неиспользуемые providers.

Типичные проблемы tree shaking в CesiumJS

На практике возникают следующие ограничения:

  • ложные зависимости через side effects;
  • невозможность удалить часть core engine;
  • обязательное включение worker-скриптов;
  • статические ресурсы всегда остаются в сборке;
  • зависимость от глобального состояния Cesium.

Эти особенности означают, что tree shaking в CesiumJS никогда не достигает уровня «идеально чистой» библиотеки вроде небольших utility-пакетов.

Архитектурные причины ограничений

CesiumJS является не просто библиотекой, а полноценным движком. Это накладывает ограничения:

  • компоненты тесно связаны между собой;
  • порядок инициализации критичен;
  • многие оптимизации выполняются на runtime;
  • часть логики должна быть доступна всегда.

Поэтому tree shaking здесь работает как вспомогательный механизм, а не как основной инструмент оптимизации.

Практическая модель оптимизации бандла

В реальных приложениях оптимизация CesiumJS строится слоями:

  • tree shaking ESM-модулей;
  • code splitting по сценам и маршрутам;
  • вынесение workers в отдельные чанки;
  • кэширование статических ресурсов;
  • минимизация импорта Viewer и UI.

Такой многоуровневый подход даёт устойчивый результат даже при больших 3D-глобусах и сложных геопространственных сценах.