Cesiumとは、Google Earthと同様に3Dで地図をWebブラウザー上に描画するJavaScriptライブラリーです。WebpackでWebアプリとしてビルドできる様にするための手順が公式サイトにあったので、あちこち端折りながらまとめます。
目次
前提環境
- コマンドラインとJavaScript、Web開発の基礎知識
- WebGLをサポートしたBrowser。対応状況が不明な場合は、こちらを開いて、動くか確認してください
- コードエディター。CesiumのメンバーはWebstormを利用している。最小限のコードならSublime Textなどでも良い
- Node.jsがインストールされていること。LTS(Long Time Support)バージョン推奨だが、Version 6以降なら動作します
ここでは、OSはmacOS、エディターはAtomで進めます。また、元のドキュメントではWebブラウザーの表示にwebpack-dev-server
を使っていますが、ライブリロードをしたいのでbrowser-sync
に差し替えました。
基本的なWebpackアプリの作成
まずはWebpackで基本的なWebアプリが開発できる様にセットアップします。既知の場合は次に進んでください。
npmの初期化
任意の場所に、プロジェクトを入れておくディレクトリーを作成して、ターミナルを起動して、プロジェクトディレクトリーにcd
で移動します。ディレクトリー名はcesium-webpack-app
などにしておきます。
mkdir cesium-webpack-app && cd cesium-webpack-app
以下のコマンドを実行して、npm
用のpackage.json
を生成します。
npm init -y
package.json
が生成されたので、必要に応じて項目を変更します。今のところ、そのまま進めます。
browser-syncのインストール
他記事に手順を記載済みです。こちらをみて、[Browsersyncをインストール]と[Browsersyncの設定ファイル]を完了させてください。
アプリ用のコードを生成
Atomエディターをインストールしていたら、Atom .
として、このディラクトリーをプロジェクトフォルダーとして、Atomを起動します。
Atomでプロジェクトフォルダーを右クリックして、[New Folder]を選択してsrc
という名前のディレクトリーを生成してください。アプリ用のソースファイルは全てこの中に保存して、編集していきます。Webpackはsrc
ディレクトリー内のコードをビルドして、dist
というディレクトリーに出力します。
Atomでsrc
ディレクトリーを右クリックして、[New File]を選択して、index.html
という名前のファイルを作成してください。作成したら、以下のコードをコピー&ペーストなどで入力して、保存します。
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<title>Hello World!</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
次に、WebアプリのエントリーポイントとなるJavaScriptファイルを作成します。Webpackは、Webアプリをビルドするのに必要なJavaScriptやCSSなどのファイルを、エントリーポイントから辿って見つけていきます。
src/index.js
を新規ファイルとして作成して、まずは他のファイルは組み込まず、シンプルに1行だけのコードを書いておきます。
console.log('Hello World!');
Webpackのインストールと設定
ターミナルで以下を実行して、Webpackをはじめとするパッケージをプロジェクトに加えます。
npm i --save-dev webpack style-loader css-loader url-loader html-webpack-plugin
これで、以下の様なパッケージがインストールされました。
- webpack
- Webアプリをビルドするためのツール。分割されたファイルを統合したり、様々なファイルを再配置したり、ビルドに関連する処理をしてくれます
- style-loader, css-loader, url-loader
- CSSや各種リソースファイルを読み込んでくれるローダーです
- html-webpack-plugin
設定
プロジェクトディレクトリー直下に新しいファイルを作成して、webpack.config.js
という名前にしてください。このファイルにWebpackのビルド設定を以下の様に記載します。
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
context: __dirname,
entry: {
app: './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}, {
test: /\.(png|gif|jpg|jpeg|svg|xml|json)$/,
use: [ 'url-loader' ]
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
})
]
};
おおよそ、以下の様なことを設定しています。
- パス操作をするためにNodeの
path
を読み込み
webpack
モジュールをwebpack
という定数に読み込み
html-webpack-plugin
をHtmlWebpackPlugin
という定数に読み込み
__dirname
はNodeのグローバル値で、このファイルのパスを表す。このプロジェクトのベースのパスをcontextを使って指定
- エントリーポイントとして
./src/index.js
を設定
- 出力先は
dist
ディレクトリーにして、ファイル名を[name].js
で指定
- CSSファイルは
style-loader
とcss-loader
で読み込む様に指定
- 画像などの各種リソースは、
url-loader
で読み込む様に指定
- HTMLファイルのテンプレートとして、
src/index.html
を指定
- Webpackが
src/index.html
を雛形にして、必要な項目をページの本文に差し込みます
アプリをバンドルする
package.json
に設定を追加して、npm
コマンドで簡単にバンドルを実行できる様にします。test
スクリプトは現状では利用しないので削除しても構いません。
package.json
を開いて、"scripts"
を以下の様にします。
"scripts": {
"build": "node_modules/.bin/webpack --config webpack.config.js",
"start": "node_modules/.bin/webpack --watch --config webpack.config.js & browser-sync start --config bs-config.js"
},
ビルドの実行
ターミナルで以下を入力することで、バンドルの実行と、開発サーバーでの動作確認ができる様になります。
npm start
これでローカルサーバーが起動して、自動的にWebブラウザーが起動して、 http://localhost:3000 が開きます。これ以降、index.html
を変更したり、index.js
を変更して保存すると、自動的にビルドが実行されて、Webページが更新される様になります。
まだ作業が残っているので、動作中のターミナルで[Ctrl]+[C]キーを押してローカルサーバーを停止してください。
WebアプリにCesiumを組み込む
Cesiumをインストール
プロジェクトディレクトリーから、以下を実行します。
npm i --save-dev cesium
設定
Cesiumをインストールすると、ライブラリーに加えて、CSSや画像、JSONファイルといったものも組み込まれます。また、他スレッドで処理を行うWebWorkerファイルも含まれます。古いnpmモジュールと異なり、様々な組み合わせができるようにCesiumはエントリーポイントを定義しません。動かすためには、いくらかのオプションを設定する必要があります。
まずは、Cesiumがどこにあるかの指定が必要です。ソースコードを指定して、それをWebpackが利用して個々のファイルの依存関係を解決します。ビルドされたバージョンのCesiumを使う方法もあります。それらのモジュールはRequireJS Optimizerによって最適化されているため、ライブラリーを簡単に改良することが難しく、自由度は下がります。
webpack.config.js
を開いて、以下の設定を最初の方に追加します。
const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';
次に、以下のようなオプションを追加して、CesiumがWebpackでどのようにコンパイルされるかを指定します。
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
sourcePrefix: ''
},
amd: {
toUrlUndefined: true
},
node: {
fs: 'empty'
},
追加したオプションを簡単に説明します。
output.sourcePrefix: ''
- Webpackのいくつかのバージョンは、デフォルトの設定で、出力するファイルの各行の先頭にタブ文字を追加する設定になっています。Cesiumは複数行の文字列のインスタンスがあるため、この設定を無効にするために必要になります。
amd.toUrlUndefined: true
- AMD版のWebpackは
require
ステートメントがtoUrl
に対応していないことをCesiumに伝えるための設定です。
node.fs: 'empty'
- いくらかのサードパーティーで使われる
fs
モジュールを解決するための設定です。これはNode環境ではなく、Webブラウザーでの動作時に利用されます。
次に、cesium
のエイリアスをwebpack.config.js
の適当な場所に追加します。これを設定しておくと、Nodeの伝統的なモジュールのように簡単にアプリのコードから参照できるようになります。
resolve: {
alias: {
cesium: path.resolve(__dirname, cesiumSource)
}
},
Cesiumの静的ファイルを管理する
最後に、Cesiumの静的なアセットやウィジェット、Web Workerファイルを提供して、読み込むようにします。
copy-webpack-plugin
を使って、ビルド時にCesiumに含まれる各種ファイルをdist
ディレクトリーにコピーします。まずは以下をターミナルで実行して、プラグインをインストールします。
npm i --save-dev copy-webpack-plugin
それから、webpack.config.js
ファイルの上の方に、以下の定義を追加します。
const CopywebpackPlugin = require('copy-webpack-plugin');
plugins
配列を以下のようにコード追加します。
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CopywebpackPlugin([ { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' } ]),
new CopywebpackPlugin([ { from: path.join(cesiumSource, 'Assets'), to: 'Assets' } ]),
new CopywebpackPlugin([ { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' } ]),
new webpack.DefinePlugin({
CESIUM_BASE_URL: JSON.stringify('')
})
]
web workerは最適化済みのビルドされたものを使いますが、デバッグのためにオリジナルフォームが必要になる場合があります。それらはBuild/Cesium/Workers
ディレクトリーからコピーされます。
DefinePlugin
では、webpackに組み込む静的ファイルのベースURLをCesiumに伝えています。
設定の動作確認
ここまでの設定が間違っていないかをチェックします。以下をターミナルで実行して、ビルドが成功して、Webページが表示されることを確認しましょう。
npm start
エラーが発生せず、Hello World!
という文字が表示されればここまで成功です。いよいよ、Cesiumを使ってみましょう。
src/index.js
ファイルを開いて、現在の内容は消して、以下を入力してください。
var Cesium = require('cesium/Cesium');
require('cesium/Widgets/widgets.css');
var viewer = new Cesium.Viewer('cesiumContainer');
1行目で、CommonJSスタイルで、Cesium
オブジェクトにCesiumの全ての機能を読み込みます。
2行目で、ウィジェットのCSSを指定します。
最後に、Cesiumのビュアーを生成して、cesiumContainer
のIDを持ったHTML要素に表示する指定をしています。
index.html
に、cesiumContainer
要素を追加する必要があります。src/index.html
を開いて、<p>Hello World!</p>
という行を消して、その場所に以下のコードを入力してください。
<div id="cesiumContainer"></div>
これで設定完了です。ローカルサーバーは起動済みですので、変更したファイルを保存すれば自動的にブラウザーがリロードされるはずです。Webブラウザーに切り替えて、Cesiumの画面が表示されれば成功です。切り替わらない場合は、Webブラウザーをリロードしてみてください。
少し表示領域の周りに白い枠があったり、ブラウザーのクライアント領域全体に表示されておらず、スペースが無駄になっています。
独自のCSSを定義して、ブラウザーいっぱいに表示してみましょう。
src/css/main.css
というファイルを新しく作成して、以下のコードを入力して保存します。
html, body, #cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
src/index.js
の先頭の方に、以下を追加して、css/main.css
を読み込むようにします。
require('./css/main.css');
上書き保存をすれば、自動的にリビルドされて、Webブラウザーが更新されます。変化しない時は、リロードしてみてください。枠がなくなり、ブラウザーのクライアント領域いっぱいに表示されるようになりました。
以上で、簡単なCesium Webアプリの構築は完了です。
補足情報
各種、補足情報です。
アプリからCesiumモジュールを読み込むいくつかの方法
アプリに個別のCesiumモジュールを読み込む方法として、CommonJSの文法を使う方法と、ES6のモジュールを読み込むimport
を使う方法があります。
全てのCesiumライブラリーをCesium
オブジェクトに設定する方法もあります。これはSandcastleで採用している方法です。Cesiumは巨大なライブラリーなので、基本的には必要なモジュールだけを読み込む方が良いでしょう。
CommonJSスタイルのrequire
Cesium
オブジェクトにCesiumの全てのライブラリーを読み込んで利用するには、以下のようにします。
var Cesium = require('cesium/Cesium');
var viewer = new Cesium.Viewer('cesiumContainer');
個別のモジュールを読み込むには、以下のようにします。
var Color = require('cesium/Core/Color');
var color = Color.fromRandom();
ES6スタイルのimport
Cesium
オブジェクトにCesiumの全てのライブラリーを読み込んで利用するには、以下のようにします。
import Cesium from 'cesium/Cesium';
var viewer = new Cesium.Viewer('cesiumContainer');
個別のモジュールを読み込むには、以下のようにします。
import Color from 'cesium/core/Color';
var color = Color.fromRandom();
アセットファイルの読み込み
Webpackの考え方では、全てのファイルはモジュールのように扱うべきというものがあります。これにより、JavaScriptのモジュールと同じようにアセットを読み込むことができます。Webpackが読み込みに使うローダーはwebpack.config.js
のloaders
属性で設定しているので、JavaScriptファイル内でrequire
で以下のように呼び出すだけです。
require('cesium/Widgets/widgets.css');
この後は・・・
Sandcastleの気になったサンプルを見ながら、実装してみると良いでしょう。
発展的なWebpackの設定
Webpackでは、機能を増やしたり、バンドルサイズを減らしたり、追加機能を入れたりと、多様なビルド方法を選択できます。いくつかの設定について触れておきます。
Cesiumを製品に最適化したWebpackの設定例はrelease.webpack.config.jsにあります。
コード分割
デフォルトのCesiumパッケージは、アプリと同じチャンク内にあり、とても巨大になります。CommonChunksPlugin
を使うことで、Cesiumを分離して、アプリのパフォーマンスを向上させることができます。開発するアプリを複数のチャンクに分けたら、それらすべてが共通のcesium
チャンクを参照するようにします。
webpack.config.js
ファイルにプラグインを追加して、Cesiumモジュールを分割するルールを指定するだけです。
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'cesium',
minChunks: module => module.context && module.context.indexOf('cesium') !== -1
})
]
ソースマップを使うには
デバッグ時に、問題箇所がオリジナルファイルのどこかを示すためのマップファイルを作成できます。webpack.config.js
に以下を追加します。
devtool: 'eval',
開発時には、この設定をしておくことを推奨します。製品版には含めるべきではありません。
pragmasの削除
開発時のエラーや警告メッセージが、Cesiumに埋め込まれています。これらは製品版には不要です。通常、これらは RequireJS Optimizer を使って、コードを縮小する時に削除します。これはWebpackの組み込み機能ではないので、以下のようにプラグインをインストールします。
npm i uglifyjs-webpack-plugin --save-dev
webpack.config.js
のmodule.rules
の設定で、debug
をfalse
にします。
rules: [{
test: /\.js$/,
enforce: 'pre',
include: path.resolve(__dirname, cesiumSource),
use: [{
loader: 'strip-pragma-loader',
options: {
pragmas: {
debug: false
}
}
}]
}]
Uglify(最適化/圧縮)とminify(圧縮)
uglifyingとminifyingで、製品コードのサイズを縮小できます。公開用ビルドのために、CesiumはuglifyでJavaScriptファイルを、minifyでCSSファイルを縮小します。
まだuglifyjs-webpack-plugin
をインストールしていなければ、以下でインストールします。
npm i uglifyjs-webpack-plugin --save-dev
webpack.config.js
の先頭の方で、以下でrequireします。
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
webpack.config.js
のplugins
設定に以下を追加します。
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
CSSの最小化は、css-loader
のoptions
にminimize
設定を書きます。
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
minimize: true
}
}
]
}]
}
学習素材
公式のcesium-webpack-exampleリポジトリーには、最小のwebpack設定や、このチュートリアルで作成したHello Worldのコードが含まれ、コード設定の設定方法の導入として有用です。
データを追加したり、スタイリングを設定する方法など、作成するアプリで利用したい機能がCesium Workshop Tutorialで確認できるかもしれません。
Webブラウザーでコードをすぐに試せるSandcastleとドキュメントも使えます。
Webpackについては、Webpack Conceptsや、Webpackのドキュメントを確認してください。
参考URL