Officially, at this moment, we cannot simply add CesiumJS as a normal module into packages.json and use it directly as other libraries such as lodash.
Instead, to use CesiumJS in your React project, there are some configurations needed.
In this post, I will review the current instructions and supplement with my practical experience to make CesiumJS works best in a Typescript-based ReactJS project.
1. Introduction
- There is a bridge-library introduced by Hiroki Inoue to lets you use CesiumJS easier, called resium, that you can find the post at
- Indeed, using the wrapped-library is the easiest way. However, I prefer to have the full control on Cesium, therefore I went to the next solution, that I found by Google. A post from 2017, a little bit outdated.
The post is useful and goes closer to the truth. However, it is not detailed enough and not a clean solution. Anyway, the solution introduced does work.
- The best solution I found is officially provided by Cesium at https://cesium.com/docs/tutorials/cesium-and-webpack/
It has a cleaner setup and works well. And to make it easier for the configuration, I would like to add some additional steps in the next section, Setup.
2. Setup
Following the guide step by step at https://cesium.com/docs/tutorials/cesium-and-webpack/
- Along with packages added in the guide, I also add the package @types/cesium to use with Typescript (for function recommendation…)
// package.json
{
"dependencies": {
...
"cesium": "^1.62.0"
},
"devDependencies": {
...
"@types/cesium": "^1.59.2",
"copy-webpack-plugin": "^5.0.4"
}
}
- My project webpack structure is as below
├── config
│ ├── path.js // Default path
│ ├── webpack.config.common.js // Common webpack configurations
│ ├── webpack.config.dev.js // Inherit from common webpack
│ └── webpack.config.prod.js // Inherit from common webpack
├── src
├── dist // Compiled .js files for deployment
├── node_modules // installed packages
├── .env // dotenv configuration
├── .eslintrc // Define eslint rules
├── .gitignore // standard git ignore file
├── package.json // scripts & packages
├── README.md
└── yarn.lock
path.js defines the paths to use in webpack config.
// The path to the CesiumJS source code
const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';
However, to make it easier in the config, I explicitly pre-define all paths we need to use for cesium as below
// path.js
'use strict';
const path = require('path');
const process = require('process');
const pathBuilder = (subpath) => path.join(process.cwd(), subpath);
module.exports = {
... // Your current defined paths
// The path to the CesiumJS source code
cesiumSource: pathBuilder('node_modules/cesium/Source'),
cesiumSourceAssets: pathBuilder('node_modules/cesium/Source/Assets'),
cesiumSourceWidgets: pathBuilder('node_modules/cesium/Source/Widgets'),
cesiumWorkers: pathBuilder('node_modules/cesium/Build/Cesium/Workers'),
};
And the most important part, to add CesiumJS into your webpack.config. Since we will use it in both dev & production, I add the configuration into the webpack.config.common.js file.
// webpack.config.common.js
............... // Your current imports
const CopywebpackPlugin = require('copy-webpack-plugin');
const { DefinePlugin } = require('webpack');
// Common configs
const path = require('./path');
// Everything belongs to cesium is isolated in an object like this
const cesiumConfig = {
resolve: {
alias: {
// CesiumJS module name
cesiumSource: path.cesiumSource,
},
},
amd: {
// Enable webpack-friendly use of require in Cesium
toUrlUndefined: true
},
output: {
// Needed to compile multiline strings in Cesium
sourcePrefix: '',
},
plugins: [
// Copy Cesium Assets, Widgets, and Workers to a static directory
new CopywebpackPlugin([ { from: path.cesiumWorkers, to: 'Workers' } ]),
new CopywebpackPlugin([ { from: path.cesiumSourceAssets, to: 'Assets' } ]),
new CopywebpackPlugin([ { from: path.cesiumSourceWidgets, to: 'Widgets' } ]),
new DefinePlugin({
// Define relative base path in cesium for loading assets
CESIUM_BASE_URL: JSON.stringify('')
}),
],
};
// Now, using the cesiumConfig in your real configuration
const config = {
...cesiumConfig,
module: {
unknownContextCritical: false,
rules: [
// Make sure you have below rules as default
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}, {
test: /\.(png|gif|jpg|jpeg|svg|xml|json)$/,
use: [ 'url-loader' ]
}
],
},
resolve: {
alias: {
...cesiumConfig.resolve.alias,
},
},
plugins: [
...., // your current plugins
...cesiumConfig.plugins,
],
};
module.exports = config;
That’s it!!! Now your project is ready to use Cesium.
3. Using CesiumJS with Typescript
To make sure you can use CesiumJS with correct UI everywhere, remember to add its CSS at your root component/index
// Import Cesium CSS
// You may need tslint:disable: to disable linting rules errors
import 'cesiumSource/Widgets/widgets.css';
In your component, let's callCesiumPage.tsx, import and use like below
....
// You may need to disable tslint for this require
// Notice that cesiumSource is the alias we defined in
// webpack.config.common.js resolve.alias
const cesium: any = require('cesiumSource/Cesium');
// Import @types/cesium to use along with CesiumJS
import { Viewer } from 'cesium';
// Import Cesium CSS if not yet added at root component
import 'cesiumSource/Widgets/widgets.css';
const Root: AnyStyledComponent =
styled.div({
width: '100%',
height: '100%',
});
const CesiumViewer: AnyStyledComponent = styled.div`
width: 100%;
height: 100%;
`;
export interface Props {
...
}
/**
* Project page
*/
class CesiumPage extends Component<Props> {
private cesiumContainer: RefObject<HTMLDivElement>;
public constructor(props: Props) {
super(props);
this.cesiumContainer = createRef();
}
public componentDidMount(): void {
if (this.cesiumContainer.current) {
// type Viewer is from @types/cesium
// whereas, new cesium.Viewer is from the module cesium
const viewer: Viewer = new cesium.Viewer(this.cesiumContainer.current);
........
console.log('cesium viewer = ', viewer);
}
}
public render(): ReactNode {
return (
<Root>
<CesiumViewer id='cesiumContainer' ref={this.cesiumContainer} />
</Root>
);
}
}
export default CesiumPage;
4. Misc.
In case your project setup with Jest, you may need an additional configuration in jest.config.js
like below
moduleNameMapper: {
// Your current configs...,
'cesiumSource/Cesium$': '<rootDir>/node_modules/cesium/Source/Cesium.js',
},
transformIgnorePatterns: [
'/node_modules/(?!(?:ol|lodash-es|cesium)/)[^/]*/.*\\.(js|jsx|ts|tsx)$',
],
DONE!!!
In case you have better solutions or a simpler configuration, please add a comment or share it with our community.
Thank you.
5. References
https://medium.com/@lhviet88/how-to-setup-cesiumjs-to-use-in-reactjs-webpack-and-typescript-a9cd8378f129