【WebGIS系列】Typescript+WebGL+Webpack开发环境搭建

目前Web实现矢量渲染的主流技术包括SVG、VML和WebGL。相对而言,VML是一种较古老的技术,虽然未成为W3C标准,但被早期的IE浏览器(IE9以下)和微软Office广泛使用,目前已经远离了浏览器战场。所以可供选择的仅剩SVG和WebGL。SVG是XML的一个子集,秉承了一个标签对应一条数据的原则,目前经常被使用于数据量较小的web项目,比如图表和地铁图。Web矢量地图的数据量非常庞大,举个例子,如下图所示的一个512px*512px的瓦片,其数据量是一个接近5位数的二维数组。而这个瓦片仅仅是最简单的大陆和海洋轮廓,同尺寸街道图的数据量更加庞大。

【WebGIS系列】Typescript+WebGL+Webpack开发环境搭建

处理庞大的数据量必然对性能的要求非常苛刻,况且由于中间隔着一层浏览器,Web地图并不能完全发挥CPU的计算能力。在有限的CPU资源下如果能够借助其他计算资源则必事半功倍,能够调用GPU资源的WebGL便成为了唯一的选择。

SVG不适合开发Web矢量地图的原因主要有两点:

无法借助GPU提高性能;

Web地图交互非常频繁,比如移动、缩放、旋转等等,如果使用SVG则需要借助频繁操作DOM实现,而DOM操作是浏览器最消耗性能的行为。

技术选型

确定了底层技术-WebGL之后,接下来需要选择合适的辅助技术,针对目标有两点:

JavaScript

构建工具

WebGL渲染与CSS无关,所以CSS开发框架的选型对整体的影响微乎其微,在此略过。

WebGL可以理解为OpenGL在浏览器环境下的变种,保留了OpenGL ES的语义和规范,提供相对简洁的JavaScript API。绝大部分的shader可以实现WebGL和OpenGL的共用。开发WebGL shader的语言GLSL是一种语法接近C的强类型编程语言。这一点对于习惯了JavaScript的前端开发者们需要一定的调整。既然是调整,那么不妨调整的彻底一些:将整体开发都引入强类型的概念。目前支持在JavaScript中引入强类型的主流框架有两种:TypeScript和Flow.js。TypeScript是JavaScript的强类型超集,Flow则更接近于一种类型注解或者注释工具。相对而言,引入Flow的成本更低,你可以自由决定哪些文件开启或者关闭类型检查,仅仅需要在文件顶部添加一行注释:

// @flow

所以Flow非常适合现有的项目进行迁移,而如果使用TypeScript则更需要将全部源代码进行改写。好在目前要做的项目并没有历史包袱,所以Flow的这点优势并不能作为技术选型的决定性因素。

最终选择TypeScript的原因有以下几点:

语法更严谨甚至有些繁琐,但习惯之后非常顺手;

生态更丰富,目前大部分主流第三方库均提供TypeScript支持。

ES6正式推出了Typed Array标准,但其实早在ES6之前,支持WebGL的浏览器就已经提供了强类型数组的API,目的是为了提高计算性能。

构建工具的选择相对比较多,Webpack、Rollup、gulp都是非常优秀的工具。最终选择Webpack的原因非常简单:比较熟。

构建配置

Webpack的配置与常规的web项目大体相同,需要注意的两点是:

TypeScript与Babel的配合

shader的构建

TypeScript&Babel

TypeScript本身支持编译为ES5或ES3,即将tsconfig.json的编译选型target修改为"es5"http://www.likecs.com/"es3":

{ "compilerOptions": { "target": "es5" } }

TypeScript编译器对于语法规范的转译功能可以满足绝大多数ES6新功能,但是其功能的全面性相比较Babel仍然有些不足,所以为了对编译进行更精准的控制,项目中采用的方案是将TypeScript首先转译为ES6语法,再借助Babel将其转译为ES5,即将tsconfig.json中的compilerOptions.target设置为"es6",webpack配置如下:

module: { rules: [{ test: /\.ts$/, exclude: /node_modules/, use: ['babel-loader','awesome-typescript-loader'] } }

Webpack编译TypeScript的loader有两个:ts-loader和awesome-typescript-loader。最终选择后者的原因当然不是因为它的名字中有个awesome,而是相对于前者,awesome-typescript-loader能够提供一些更加便利的功能,比如alias-别名。

如果源码的目录结构比较复杂,引用一个模块时可能需要写很长的路径名称,比如:

import Utils from '../../../utils';

为了令代码具有更好的易读性,我们通常借助一些工具将模块的引用设置较短的别名。Webpack也有此功能,通过resolve配置模块的别名:

resolve: { alias: { 'utils': path.resolve(__dirname,'src/utils') } }

但遗憾的是ts-loader和awesome-typescript-loader并不能直接使用Webpack的alias配置,源码中直接使用模块别名将会抛出not found错误,请注意这个错误是TypeScript编译器抛出而非Webpack。解决方案很简单:在tsconfig.json中配置模块别名。如下:

{ "paths": { "utils/*": ["src/utils/*"] } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzdzs.html