Skip to main content

Modular Structure in CesiumJS Offers Better Dependency Management

With the release of CesiumJS 1.100 on December 1, it’s possible to download either the entire CesiumJS release or just a subset of the Cesium library through smaller packages. This change gives applications that use only a subset of Cesium’s capabilities access to smaller, more specific packages.

CesiumJS is an extensive library with a lot of functionality to meet a broad range of use cases. While some users may use the whole stack by embedding the CesiumViewer in their application and using all the features that the Timeline and Animation widgets bring, others may only want a lean interface through the CesiumWidget, and still others may only want to use the geospatial math library in Core.

Given the diversity of our user community and the domains CesiumJS is used for, the benefits of a modularized structure of packages are apparent: users can choose to depend on only what they want to use in their application. The benefits go beyond producing a leaner bundle; this change eliminates the need to install all of the direct dependencies that are synced with the existing cesium npm package. It also reduces the surface area of the API that the user is supposed to learn, and provides flexibility in selecting when and how users update their dependencies.

To start, these smaller packages take the form of “engine” and “widgets.” We plan on maintaining our regular monthly release schedule for CesiumJS. For example, when CesiumJS 1.100 was made available December 1, engine 1.0 and widgets 1.0 were also released.

Diagram of division of CesiumJS into engine and widgets

Engine package

The engine package is the core runtime components of CesiumJS, including everything except the Widgets folder found in the combined CesiumJS release. The one exception here is that CesiumWidget has been moved from the widgets to engine. This provides a lean and minimal way of adding CesiumJS to the browser.

Which CesiumJS package to use decision tree

So, if you’re only using the engine package, you can get started with the following snippet:

import { CesiumWidget } from “@cesium/engine”;
import “@cesium/engine/Source/Widget/CesiumWidget.css”;

const widget = new CesiumWidget(“cesium-container”);
Globe in CesiumJS without widgets

Widgets package

The widgets package contains all the different UI widgets that are part of the combined CesiumJS package. These include the Viewer, Timeline, Animation, etc., along with the different mixins. To get started with the widgets package, you can use the following snippet:

import { Viewer } from “@cesium/widgets”;
import “@cesium/widgets/Source/widgets.css”;

const viewer = new Viewer(“cesium-container”);
Globe in CesiumJS with widgets

Since widgets depends on engine, the engine package will automatically be installed when you install widgets.

Implementation details

We use npm workspaces to impose a monorepo structure. These packages can be found in the root level packages directory and will be published under the @cesium scope, i.e., @cesium/engine and @cesium/widgets.

As compared to the combined CesiumJS package, which includes pre-bundled artifacts such as Cesium.js, index.js and index.cjs, these newer packages will be shipped in a lean configuration, as ES modules with TypeScript definitions, as is the standard for modern packages. This will allow users to employ the bundling tools of their choice for their applications and take advantage of features like tree-shaking, or dead code elimination.

Also, as per npm best practice, these packages will follow semantic versioning, which lets users clearly understand the scope of changes between versions and prevent cases where allowing npm to automatically update versions would result in broken builds.

In terms of what these changes look like in the repository or the combined release, all source files from the root level Source folder have been moved into the respective package folder. For example, Scene.js has moved from Source/Scene/Scene.js to packages/engine/Source/Scene/Scene.js. And Viewer.js has moved from Source/Widgets/Viewer/Viewer.js to packages/widgets/Source/Viewer/Viewer.js. Any direct dependencies included in the source code have been moved to the ThirdParty folder within each package’s Source folder.

When working within the repository, each package also comes with its own simple scripts: build - Creates the package’s entry module index.js, bundles the Specs build-ts - Generates the TypeScript definitions file test - Runs tests coverage - Generates coverage report

To minimize impact on applications that depend on the combined CesiumJS release structure, static assets found in Assets, ThirdParty, and Widgets are still copied to the root level Source folder at the time of publishing.

Next steps

These changes are another important step of our plan to continue modernizing the CesiumJS library and they build on the previous improvements to our source code, tooling, and build processes. In the future, we hope to be able to break the packages down along even finer lines, such as publishing a core package that contains all the geospatial math classes like Cartesian3, etc.

Please share your feedback on GitHub or the community forum.