返回介绍

Cesium 和 Webpack Cesium 和 Webpack

发布于 2021-01-09 13:40:56 字数 22866 浏览 1351 评论 0 收藏 0

原文地址:https://cesiumjs.org/tutorials/cesium-and-webpack/

Cesium 和 Webpack

Webpack是非常强大非常流行的JavaScript 模块打包工具。它可以让开发人员以一种简单直观的 require 方式去加载各种页面需要的文件,极大的方便了开源人员对代码和资源文件进行结构化设计。当编译的时候,它会跟踪代码依赖性,把所有的模型打包到浏览器可以直接加载的一个或者多个bundles中。

在这个教程的前一半,我们创建一个简单的web项目,学会使用webpack,然后再去集成 Cesium npm模块。这是基于Cesium开发正式web项目的很好开端,但是它不是学习Cesium的最简单示例,可以看一下我们的新手入门

在教程的后半部分,我们将讨论更多高级的webpack 配置参数,去优化使用Cesium的项目。

这个优化Cesium和Webpack集成的项目示例,可以查看官网webpack示例 代码库。

先决条件

  • 对命令行,JavaScript语言和web开发需要有一个基本了解。
  • 一个代码编辑器(IDE)。Cesium团队的开发人员都用 Webstorm, 但是 Sublime Text 等工具也可以。
  • 安装了Node.js 。LTS版本最好,但是只要是v6以上都可以的。

创建一个基本的 webpack 程序

第一部分,描述如何建立一个简本的webpack程序以及一个开发测试服务器。如果你已经创建了程序,就想添加Cesium,直接看后面和Cesium继承部分。

使用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安装
配置参数

创建一个名为webpack.config.js的文件。这是定义webpack的配置参数 的地方,它会传给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'),
    }
};

首先,我们需要从Nodejs中加载 path和我们刚刚安装的webpack模块。我们告诉webpack,context的及处理路径是Node的全局变量__dirname,这个全局变量指的这个文件所在的目录位置。我们设定了我们的程序入口src/index.js,而且把它命名为app。我们还告诉webpack把打包后的文件(这个文件的名称叫app.js,因为我们设置了程序入口的[name])输出到dist目录下。最后export 把这个配置对象导出,其他文件才能用到这个配置。

加载器(Loaders)

我们还需要加载我们的css以及其他资源文件的方法。webpack允许我们像加载js模块一样,载入这些文件。我们需要使用 loaders。我们需要使用 style-loader, css-loader, 和 url-loader

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

继续往 webpack.config.js里添加 module.rules。我们添加两个规则,一个是为css文件,一个是为其他静态文件。每个一个配置,我们定义 test过滤器来筛选这种类似的文件,还定义了一个use数组,指定这种类型用到的loader。

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' ]
        }]
    }
};
插件

项目已经创建好了,下来需要修改index.html ,让它把打包文件引到页面上。使用webpack的 插件(plugins) 中的 html-webpack-plugin

npm install --save-dev html-webpack-plugin
安装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文件,所以我们可以引用任何Nodejs的模块,做任何操作。

打包程序

package.json文件里添加一点脚本配置,我们就能很方便的调用npm。把里面默认的"test"脚本删除掉,我们用不上它。添加一个build命令。

  "scripts": {
    "build": "node_modules/.bin/webpack --config webpack.config.js"
  }

这个脚本就是简单的调用了webpack命令,并把我们刚才新建的配置文件webpack.config.js 当作参数传递过去。

因为我们的webpack刚才是本地安装。这样每个项目都使用独立的版本,这也是webpack的推荐安装方式。如果你选择全局安装方式,使用 npm install --global webpack全局安装webpack,然后这里的build命令修改为 webpack --config webpack.config.js
我们运行下编译命令。

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.jsindex.html 输出到了 dist目录。这些文件已经是可以使用的程序了。

编译后的目录

启动开发服务器

这个还不算什么。我们使用 webpack-dev-server 快速的搭建一个开发者服务器,我们的程序就可以实时查看了。
首先安装webpack-dev-server

npm install --save-dev webpack-dev-server

下来,在 package.json文件中增加另外的脚本。使用start命令去启动服务,通过 --config参数传递参数。还传一个 --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.config.js文件中增加一些配置。

    // 开发服务器配置
    devServer: {
        contentBase: path.join(__dirname, "dist")
    }

最后,我们运行程序

npm start

你应该能看见程序已经在 localhost:8080运行了。如果你打开浏览器控制台,因会看见“Hello World!” 已经输出了。

基本webpack程序示例

webpack 程序里集成 Cesium

我们的webpack程序已经搭好了框架,下来我们干点有意思的,增加Cesium。

安装Cesium

从npm中安装 cesium 模块,在 package.json 中增加开发依赖选项。

npm install --save-dev cesium

webpack中配置Cesium

Cesium是一个庞大的复杂的库。除了JavaScript模块之外,它还包含静态资源css,图片和json文件。它也包含为了多线程进行大量计算的web worker。和传统npm模块不同,Cesium也没有定义一个入口,因为这个库可以各种方式应用。为了正确使用,我们需要配置一些额外选项。
首先,我们定义Cesium所在位置。我们使用源码,这样我们就可以使用独立模块,依靠webpack可以跟踪依赖性。其他方式是使用编译好的(最小化压缩或者未压缩)版本的Cesium;可是,那些模块已经被RequireJS optimizer 组合和优化,这种方式集成起来简单避免犯错,但是对于我们的优化灵活度不够好。

webpack.config.js,我们增加如下配置

// Cesium源码所在目录
const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';

我们选择使用了npm 中的模块,安装容易一些,当然你也可以用 GitHub 库 上的版本,或者解压已发布版本下载。这时候仅仅需要更改cesiumSource 指向Cesium的 Source 目录,相对 webpack.config.js 文件的相对路径。
接着再增加一些配置项,为了解决使用webpack编译Cesium的一些问题。

    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist'),
        //需要编译Cesium中的多行字符串 
        sourcePrefix: ''
    },
    amd: {
        //允许Cesium兼容 webpack的require方式 
        toUrlUndefined: true
    },
    node: {
        // 解决fs模块的问题(Resolve node module use of fs)
        fs: 'empty'
    },

快速过下,为什么这些配置选项需要配置。

  • output.sourcePrefix: '' 因为某些版本的webpack默认会在输出的每一行的开始增加一个\t 字符。Cesium有很多多行字符串,所以我们需要使用空字符串 ''来覆盖这个选项。
  • amd.toUrlUndefined: true 告诉Cesium,webpack中计算 require声明的AMD 模块里的toUrl 函数和标准的不兼容。
  • node.fs: 'empty' 解决一些第三方库使用的fs 模块,它一般是用在NodeJS的环境里,而不能在浏览器环境里使用。
    下来我们增加一个 cesium 别名(alias) ,我们就很容易的在项目里引用,就像一个传统的Node 模块。
    resolve: {
        alias: {
            // Cesium模块名称
            cesium: path.resolve(__dirname, cesiumSource)
        }
    },

</figure>

管理Cesium 静态文件

最后,我们确认一下Cesium的静态资源,控件,web worker文件能被服务正确加载。
我们使用 copy-webpack-plugin,它能在编译阶段,把Cesium里静态文件整个拷贝到 dist 目录下,确保我们的服务能访问它。首先,安装它。

npm install --save-dev copy-webpack-plugin

下来在webpack.config.js文件最开始require它。

const CopywebpackPlugin = require('copy-webpack-plugin');

此外,在plugins 目录下增加下述配置:

    plugins: [
        new HtmlWebpackPlugin({
            template: 'src/index.html'
        }),
        // 拷贝Cesium 资源、控价、web worker到静态目录 
        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 optimizer编译和优化过了。因为web woker设计就是运行在他们自己的线程里,所以他们可以直接载入和运行。web worker很少需要调试他们原来的代码。所以直接整个从 Build/Cesium/Workers目录拷贝过去。
如果你用的GitHub库的源码,那么这个Build目录不存在。确认你定位到了Cesium的根目录下,然后运行 npm run release去编译输出。更多信息可以查看Cesium编译指导
最后,我们使用DefinePlugin 定义了一个环境变量,这个告诉Cesium加载静态文件的URL根路径,并把它编译到webpack里去。最后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载入静态的资源的相对路径
            CESIUM_BASE_URL: JSON.stringify('')
        })
    ],

在我们的程序里引用Cesium

现在我们的程序里引用Cesium的独立模块有几种方式。使用CommonJS的语法,以及最新的ES6的 import模块声明。
另外,你也可以通过一个 Cesium 引入整个Cesium库(例如,我们在 Sandcastle中所用的方式)。你也可以只请求某个你需要的特定模块。因为Cesium是一个巨大的库,这种方式让你只引用你用的特定模块,而不是整个Cesium库。

CommonJS 形式的 require

引用Cesium整个库:

var Cesium = require('cesium/Cesium');
var viewer = new Cesium.Viewer('cesiumContainer');

引用某个Cesium库:

var Color = require('cesium/Core/Color');
var color = Color.fromRandom();
ES6 形式的 import

引用Cesium整个库:

import Cesium from 'cesium/Cesium';
var viewer = new Cesium.Viewer('cesiumContainer');

引用某个Cesium库:

import Color from 'cesium/core/Color';
var color = Color.fromRandom();

请求静态资源文件

webpack的设计理念就是每个文件都当作一个模块。所以导入静态资源和导入js模块完全相同。我们已经在loaders里面配置了,告诉webpack每种类型的文件使用哪个loader,所以我们只需要调用 require

require('cesium/Widgets/widgets.css');

Hello World! 示例

有了基本框架也学习如何引入Cesium文件,我们来创建一个简单的Hello World程序。
再看下index.js文件。删除它的内容,首先我们引入 Cesium,然后定义 Cesium的对象:

var Cesium = require('cesium/Cesium');

为了使用Cesium Viewer里的控件,我们还需要引入Cesium的CSS:

require('cesium/Widgets/widgets.css');

在HTML的body部分,我们创建了一个viewer需要的div。在 index.html 文件里,删除 <p>Hello World!</p> 这一行,替换成下面:

<div id="cesiumContainer"></div>

最后,我们创建一个viewer的实例。返回到 index.js 文件,添加下面代码:

var viewer = new Cesium.Viewer('cesiumContainer');

当我们运行 npm start ,我们将看见浏览器里的Cesium控件了。

Hello World 程序

为了美观,我们用一些自定义css去掉页面上的白色边界。
创建一个新的文件src/css/main.css,增加下面的样式:

html, body, #cesiumContainer {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

index.js里require它,在其他require的后面。

require('./css/main.css');

重新npm start,Cesium的控件完美全屏了。

随便拷贝粘贴 Sandcastle 中的示例。 我认为 粒子系统的示例 最能说明问题。

示例程序

webpack 高级配置

webpack有很多其他方法增加性能、减小打包大小、执行额外的或者复杂的编译过程。对于使用Cesium库,我们将讨论一些配置选项。
我们的最佳配置选项示例放在github的配置库里 webpack.release.config.js

代码切片

webpack默认会把Cesium和整个程序代码打进一个 chunk中,最终这个库非常庞大。我们也可以用CommonChunksPlugin把Cesium打到它自己的包,提升程序的性能。如果最终你的程序创建了多个chunks,他们可以引用一个通用的cesiumchunk。
只需要在 webpack.config.js添加这个插件,然后设置打断Cesium模块的规则。

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: 'cesium',
            minChunks: module => module.context && module.context.indexOf('cesium') !== -1
        })
    ]

这个插件最新版webpack上已经不能这么配置了,使用config.optimization.splitChunks去设置,详情点击webpack-splitChunks

启用 source maps

Source maps 允许webpack跟踪原来代码中的错误,它有很多配置项。它用编译速度来换取或多或少的调试详情信息。我们推荐使用'eval'选项,但是尽量使用你自己开发中最好的方式。

    devtool: 'eval'

不推荐在最终产品代码里添加Source maps(容易被破解呗)。

删除 pragmas

Cesium源码里包含了一些开发错误和警告信息,但是产品中是不需要的。通常我们使用 RequireJS Optimizer在release编译下压缩它。因为没有webpack内置的方式去删除这些警告,我们将使用 strip-pragma-loader
首先,安装。

npm install strip-pragma-loader --save-dev

然后在loader的 module.rules增加规则,并且 把 debug 设置为 false.

    rules: [{
        // 删除 cesium pragmas
        test: /\.js$/,
            enforce: 'pre',
            include: path.resolve(__dirname, cesiumSource),
            use: [{
                loader: 'strip-pragma-loader',
                options: {
                    pragmas: {
                        debug: false
                    }
                }
            }]
    }]

混淆和压缩

混淆和压缩代码使最终产品的代码变得更小。对于一个release编译,Cesium会JavaScript文件,并且压缩CSS文件。为了混淆Cesium源码,我们使用 uglifyjs-webpack-plugin插件。

npm install uglifyjs-webpack-plugin --save-dev

引入这个插件

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

在插件里引用它

    plugins: [
        new webpack.optimize.UglifyJsPlugin()
    ]

这个插件最新版webpack上已经不能这么配置了,使用config.optimization.minimize去设置,详情点击webpack-optimization
为了压缩css代码,在css-loader中使用minimize选项。

    module: {
        rules: [{
            test: /\.css$/,
            use: [
                'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        // minify loaded css
                        minimize: true
                    }
                }
            ]
        }]
    }

相关资源

官方 cesium-webpack-示例 的git库。包含最小的webpack配置,以及此篇教程的hello word代码,还有部分可选的代码配置选项。

学习如何基于Cesium开发项目实例,比如如何添加数据和配置样式,那么去学习 Cesium Workshop 教程

玩下 Sandcastle以及官方用户手册

深入学习webpack,可以看下webpack 概念 ,或者看下webpack的配置手册

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文