Cesium和Webpack(九)

admin0条评论 785 次浏览

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'),
	}
};

首先,我们将要求pathNode和webpack我们刚刚安装的模块。在配置中,我们会告诉webpack我们的基本路径是什么,context并提供Node全局__dirname来指定这个文件的位置。我们指定我们entrysrc/index.js,我们会打电话给它app。我们将告诉webpack将该包(将在命名后app.js使用该条目命名[name])输出到该dist文件夹。那么export这个对象就可以在其他地方使用了。

装载机

我们还需要一种方法来加载我们的css文件和其他资产文件。webpack可以让我们像模块一样加载所有东西,并且使用加载程序完成。我们将使用style-loadercss-loaderurl-loader

npm install --save-dev style-loader css-loader url-loader

让我们继续并添加module.ruleswebpack.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我们创建的配置文件。

我们在这些脚本中使用本地安装的webpack和webpack-dev-server。这允许每个项目使用它自己的个人版本,并且是webpack文档建议的内容。如果您希望使用全局版本,请使用全局安装,npm install --global webpack然后使用该命令webpack --config 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应用程序输出

`app.js`控制台输出

将铯添加到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';

虽然我们选择在这里使用npm模块以方便安装,但您也可以使用GitHub存储库的副本或解压缩版本下载。只需更新cesiumSourceSource相对于webpack.config.js文件位置的Cesium 目录的位置即可。

接下来,我们将下面的选项添加到我们的配置对象中,以解决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' } ])
	],

我们正在复制AssetsWidgets目录。另外,我们将使用构建的 web worker脚本,这些脚本已经通过RequireJS优化器进行了编译和优化。由于Web工作人员被设计为在他们自己的线程中分别运行,因此可以按原样加载和运行。网络工作者很少(如果有的话)将以原始形式进行调试。我们将从Build/Cesium/Workers目录中复制这些内容。

如果您已将Cesium指向GitHub repo的克隆,则该Build文件夹将不会存在。确保您导航到基本Cesium目录并运行npm run release以生成构建输出。有关更多信息,请参阅Cesium构建指南

最后,我们将定义一个环境变量,告诉DefinePluginCesium 使用内置于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语法以及importES6模块使用的新语句。

此外,您可以将整个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!

Hello World App

为了您和我的理智,让我们通过添加一些自定义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');

再次启动应用程序,您将看到全屏辉煌的查看器。

风格的Hello World应用程序

随意复制并粘贴您最喜爱的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.rulesdebug设置为一起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中玩耍。

要了解有关webpack的更多信息,请查看webpack Concepts 或者深入文档