Cesium和Webpack(九)
Cesium和Webpack
Webpack是捆绑JavaScript模块的流行且强大的工具。它允许开发人员以直观的方式构建自己的代码和资产,并根据需要用简单的require
语句加载不同种类的文件。在构建时,它将跟踪代码依赖关系并将这些模块打包成一个或多个由浏览器加载的包。
在本教程的前半部分,我们将使用webpack从头开始构建一个简单的Web应用程序,然后介绍集成Cesium npm模块的步骤。如果您想使用Cesium开发Web应用程序,那么这是一个很好的开始,但对于开始使用Cesium的更简单的示例,请参阅我们的入门教程。
在下半年,我们将探索更先进的webpack配置,以优化使用Cesium的应用程序。
完整的应用程序和优化Cesium和webpack应用程序的提示可以在官方的cesium-webpack-example存储库中找到。
先决条件
- 对命令行,JavaScript和Web开发的基本了解。
- 支持WebGL的浏览器。如果有疑问,请确保您的浏览器已准备好Cesium。
- 一个IDE或代码编辑器。Cesium团队成员的开发人员使用Webstorm,但最小代码编辑器(如Sublime Text)也可以工作。
- Node.js已安装。LTS版本是一个很好的开始,但任何版本6或更高版本都可以使用。
创建一个基本的webpack应用程序
在第一部分中,我们将介绍如何使用webpack和开发服务器来设置基本Web应用程序。如果您已经创建了一个应用程序并只想添加Cesium,请跳至添加Cesium至一个webpack应用程序。
用npm初始化一个应用程序
为您的应用程序创建一个新目录。我们称之为cesium-webpack-app
。打开一个控制台并在该新目录中运行以下命令:
npm init
按照提示进行操作并填写有关应用程序的任何详细信息。按下enter使用默认设置,所有这些默认设置都适用于此应用程序。这将创建我们的package.json
文件。
创建我们的应用代码
src
为我们的“源” 创建一个新目录。这就是我们所有的应用程序代码都会存在的地方,这些是我们要编辑的文件。当我们构建时,webpack将在dist
目录中生成输出或“分发”文件。
让我们src/index.html
为样板HTML页面创建和添加代码。
<!DOCTYPE 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>
现在我们需要为应用程序创建一个入口点。这将是我们告诉webpack开始包括我们的所有源代码和依赖关系的地方。该捆绑包将被加载到我们的index.html
文件中。
现在,我们将保持简单。创建一个新文件src/index.js
并添加一个快速行,以便我们知道一切正常。
console.log('Hello World!');
安装并配置webpack
首先安装webpack。
npm install --save-dev webpack
组态
创建一个名为的新文件webpack.config.js
。这是我们定义webpack 配置对象的地方,然后我们可以将它传递给编译器。
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: __dirname,
entry: {
app: './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
}
};
首先,我们将要求path
Node和webpack
我们刚刚安装的模块。在配置中,我们会告诉webpack我们的基本路径是什么,context
并提供Node全局__dirname
来指定这个文件的位置。我们指定我们entry
是src/index.js
,我们会打电话给它app
。我们将告诉webpack将该包(将在命名后app.js
使用该条目命名[name]
)输出到该dist
文件夹。那么export
这个对象就可以在其他地方使用了。
装载机
我们还需要一种方法来加载我们的css文件和其他资产文件。webpack可以让我们像模块一样加载所有东西,并且使用加载程序完成。我们将使用style-loader
,css-loader
和url-loader
。
npm install --save-dev style-loader css-loader url-loader
让我们继续并添加module.rules
到webpack.config.js
。我们将添加两个规则,一个用于css文件,另一个用于其他静态文件。对于每一个,我们将定义一个test
用于加载该加载器的文件类型,以及一个use
指定加载器列表的数组。
const path = require('path');
const webpack = require('webpack');
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' ]
}]
}
};
插件
我们正在创建一个Web应用程序,所以我们需要定义我们的index.html
并将我们的包注入到该页面中。我们将使用一个名为the 的webpack 插件来做到这一点html-webpack-plugin
。
npm install --save-dev html-webpack-plugin
要求插件位于webpack.config.js
文件的顶部并将其添加到plugins
。我们将以我们的src/index.html
身份通过template
,并且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'
})
]
};
请记住,配置文件只是一个JavaScript文件,所以我们可以要求其他节点模块并执行操作。
捆绑应用程序
我们将定义一些脚本,将很容易与调用npm
中出package.json
。随意删除默认"test"
脚本,因为我们不会在这里使用它。让我们添加build
命令。
"scripts": {
"build": "node_modules/.bin/webpack --config webpack.config.js"
}
该脚本只需调用webpack并传入webpack.config.js
我们创建的配置文件。
当你运行build命令时,
npm run build
你应该看到一些从webpack开始的输出:
npm run build
> test-app@1.0.0 build C:\workspace\test-app
> node_modules/.bin/webpack --config webpack.config.js
Hash: 2b42bff7a022b5d956a9
Version: webpack 3.6.0
Time: 2002ms
Asset Size Chunks Chunk Names
Assets/Textures/NaturalEarthII/2/0/3.jpg 10.3 kB [emitted]
app.js 162 kB 0 [emitted] app
我们的app.js
软件包和index.html
文件将被输出到dist
文件夹中。这些文件已准备好作为Web应用程序提供。
运行开发服务器
这并不令人兴奋。让我们使用它webpack-dev-server
来快速提供开发版本并查看我们的应用程序。
首先,将其作为开发依赖项安装。
npm install --save-dev webpack-dev-server
接下来,让我们为我们添加另一个脚本package.json
。我们将使用该start
命令运行开发服务器,通过--config
标志传递配置文件,就像我们所做的那样build
。或者,--open
在命令运行时,我们将传递标志顶部以在浏览器中打开应用程序。
"scripts": {
"build": "node_modules/.bin/webpack --config webpack.config.js",
"start": "node_modules/.bin/webpack-dev-server --config webpack.config.js --open"
}
我们需要告诉开发服务器在哪里为我们的文件提供服务。在这种情况下,这将是我们放置webpack输出的相同文件夹dist
。在你的webpack配置的底部添加这个webpack.config.js
。
// development server options
devServer: {
contentBase: path.join(__dirname, "dist")
}
最后,我们可以运行应用程序!
npm start
你应该看到你的内容在服务localhost:8080
,如果你打开控制台,你应该看到我们的“Hello World!”消息打印在那里。
将铯添加到webpack应用程序
现在我们已经有了一个运行webpack的简单骨骼应用程序,让我们来看看有趣的部分并添加Cesium。
安装铯
cesium
从npm 安装模块并将其package.json
作为开发依赖项添加到我们的文件中。
npm install --save-dev cesium
在webpack中配置Cesium
铯是一个庞大而复杂的图书馆。除了JavaScript模块之外,它还包含静态资产,如css,image和json文件。它包含web worker文件以在另一个线程中执行密集计算。与传统的npm模块不同,Cesium没有定义入口点,因为库的使用方式各不相同。我们需要配置一些其他选项才能正确使用它。
首先,我们来定义Cesium的位置。我们将使用源代码,它允许我们使用各个模型并通过利用webpack来追踪依赖关系。另一种方法是使用Cesium的内置版本(缩小版本或非版本化版本); 但是,这些模块已经使用RequireJS优化器进行了组合和优化,这会带来一些问题以便轻松集成库,并使我们自己的优化变得更加灵活。
在中webpack.config.js
,我们在配置对象上添加以下内容:
// The path to the Cesium source code
const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';
接下来,我们将下面的选项添加到我们的配置对象中,以解决webpack编译Cesium的一些怪癖。
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
// Needed to compile multiline strings in Cesium
sourcePrefix: ''
},
amd: {
// Enable webpack-friendly use of require in Cesium
toUrlUndefined: true
},
node: {
// Resolve node module use of fs
fs: 'empty'
},
让我们快速看看这些单独配置选项的推理以及它们包含的原因:
output.sourcePrefix: ''
是需要的,因为某些版本的webpack默认\t
在每行输出前添加一个制表符。Cesium有多行字符串的实例,所以我们需要用空前缀覆盖这个默认值''
。amd.toUrlUndefined: true
告诉Cesium ,AMD webpack用来评估require
语句的版本不符合标准toUrl
功能。node.fs: 'empty'
解决了fs
模块的一些第三方用法,该模块的目标是在Node环境中使用,而不是在浏览器中使用。
接下来让我们添加一个cesium
别名,以便像我们的传统Node模块那样,在我们的应用程序代码中轻松引用它。
resolve: {
alias: {
// Cesium module name
cesium: path.resolve(__dirname, cesiumSource)
}
},
管理Cesium静态文件
最后,让我们确保正确提供并加载静态Cesium资产,小工具和web worker文件。
我们将使用这个copy-webpack-plugin
将允许我们作为构建过程的一部分来将Cesium中包含的静态文件复制到我们的dist
目录中,以便它们可以被提供。首先,安装它。
npm install --save-dev copy-webpack-plugin
然后要求它靠近我们webpack.config.js
文件的顶部。
const CopywebpackPlugin = require('copy-webpack-plugin');
另外,将以下内容添加到plugins
数组中。
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
// Copy Cesium Assets, Widgets, and Workers to a static directory
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' } ])
],
我们正在复制Assets
和Widgets
目录。另外,我们将使用构建的 web worker脚本,这些脚本已经通过RequireJS优化器进行了编译和优化。由于Web工作人员被设计为在他们自己的线程中分别运行,因此可以按原样加载和运行。网络工作者很少(如果有的话)将以原始形式进行调试。我们将从Build/Cesium/Workers
目录中复制这些内容。
如果您已将Cesium指向GitHub repo的克隆,则该Build
文件夹将不会存在。确保您导航到基本Cesium目录并运行npm run release
以生成构建输出。有关更多信息,请参阅Cesium构建指南。
最后,我们将定义一个环境变量,告诉DefinePlugin
Cesium 使用内置于webpack中的静态文件加载静态文件的基本URL 。该plugins
数组现在看起来像这样:
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
// Copy Cesium Assets, Widgets, and Workers to a static directory
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({
// Define relative base path in cesium for loading assets
CESIUM_BASE_URL: JSON.stringify('')
})
],
在我们的应用程序中需要Cesium模块
现在我们可以在我们的应用程序中使用几种不同的方式来使用Cesium以及单独的Cesium模块。CommonJS语法以及import
ES6模块使用的新语句。
此外,您可以将整个Cesium库导入到一个Cesium
对象下(例如,这就是我们在Sandcastle中所做的)。您也可以只需要您需要的特定模块。由于Cesium是一个如此庞大的库,这将允许您只将指定的模块及其依赖包括在您的包中,而不是整个Cesium库中。
CommonJS风格 require
要在一个对象下需要所有的Cesium库:
var Cesium = require('cesium/Cesium');
var viewer = new Cesium.Viewer('cesiumContainer');
要求个别模块:
var Color = require('cesium/Core/Color');
var color = Color.fromRandom();
ES6风格的导入
要在一个对象下需要所有的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如何使用加载器加载我们配置中的每种文件类型,所以我们只需要调用require
。
require('cesium/Widgets/widgets.css');
你好,世界!
现在我们已经建立了环境,并且我们知道如何包含Cesium文件,让我们从原始入门教程中复制Hello World应用程序。
让我们再看看我们的index.js
文件。删除其内容。首先,我们将包括Cesium
。以下定义了该Cesium
对象:
var Cesium = require('cesium/Cesium');
为了使用Cesium Viewer小部件,我们需要包含它的CSS:
require('cesium/Widgets/widgets.css');
在HTML正文中,我们将创建一个供观众使用的div。在该index.html
文件中,删除我们的<p>Hello World!</p>
行并将其替换为此div:
<div id="cesiumContainer"></div>
最后,我们将创建一个查看器实例。回来再index.js
添加一行:
var viewer = new Cesium.Viewer('cesiumContainer');
当我们运行应用程序时,npm start
我们将在浏览器中看到Cesium Viewer!
为了您和我的理智,让我们通过添加一些自定义CSS来摆脱那个白色边框。
创建一个新文件,src/css/main.css
并添加以下样式:
html, body, #cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
要求在你的index.js
文件中,正好在其他require语句之下:
require('./css/main.css');
再次启动应用程序,您将看到全屏辉煌的查看器。
随意复制并粘贴您最喜爱的Sandcastle示例。我认为粒子系统的例子是一个很好的结论。
先进的webpack配置
可以通过更多方式利用webpack来提高性能,减少捆绑包的大小,并执行额外或复杂的构建步骤。这里我们将讨论一些与使用Cesium库相关的配置选项。
我们的优化生产Cesium webpack构建配置可以在我们的示例仓库中找到 release.webpack.config.js
代码拆分
默认情况下,Webpack将Cesium 与我们的应用程序放在同一个块中,结果是巨大的。我们可以将Cesium分成它自己的软件包,并通过使用该软件来提高我们的应用程序的性能CommonChunksPlugin
。如果最终为自己的应用程序创建多个块,则它们都可以引用一个常见cesium
块。
只需将插件添加到您的webpack.config.js
文件中,并指定用于突破Cesium模块的规则:
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'cesium',
minChunks: module => module.context && module.context.indexOf('cesium') !== -1
})
]
启用源地图
源地图允许webpack将错误追溯到原始内容,并且有许多选项。它们提供或多或少的详细调试信息以换取编译速度。我们建议您使用该'eval'
选项,但要充分利用适合您开发的最佳选项。
devtool: 'eval'
源图不建议用于生产。
删除杂注
我们在Cesium源代码中包含开发人员错误和警告,这些对生产版本来说不是必需的。传统上,我们使用RequireJS Optimizer在最小化版本构建中删除它们。由于没有内置webpack的方式来删除这些警告,我们将使用strip-pragma-loader
。
首先,安装它,
npm install uglifyjs-webpack-plugin --save-dev
然后将加载程序module.rules
与debug
设置为一起false
。
rules: [{
// Strip cesium pragmas
test: /\.js$/,
enforce: 'pre',
include: path.resolve(__dirname, cesiumSource),
use: [{
loader: 'strip-pragma-loader',
options: {
pragmas: {
debug: false
}
}
}]
}]
丑化和缩小
Uglifying和缩小代码允许生产中的较小文件大小。对于发布版本,Cesium将uglify JavaScript文件并缩小CSS文件。
为了丑化铯源,我们将使用uglifyjs-webpack-plugin
,
npm install uglifyjs-webpack-plugin --save-dev
需要它,
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
并将其包含在插件列表中。
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
为了缩小我们加载的任何css,我们将使用该minimize
选项css-loader
。
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
// minify loaded css
minimize: true
}
}
]
}]
}
资源
官方的cesium-webpack例子 repo包含本教程中介绍的最小webpack配置和hello world代码,以及可选代码配置的说明。
有关您的新应用中包含的某些Cesium功能(如添加和设置数据)的信息,请参阅Cesium Workshop教程。
在文档的帮助下,在Sandcastle中玩耍。