当ArcGIS API for JavaScript遇见Webpack(一)

来源:互联网 发布:实况足球因扎吉数据 编辑:程序博客网 时间:2024/05/22 16:42

当ArcGIS API for JavaScript遇见Webpack(一)

96 
小林666 关注
2017.08.14 21:27* 字数 1906 阅读 213评论 0赞赏 2

作者:liuyl 邮箱:liuyl.gisuni@gmail.com
关于作者:GIS从业者,主要在ArcGIS平台下做WebGIS开发


写在最前面


前些天看到公众号推送的由JetBrains发布的2017开发者生态报告,JavaScript荣登最常用语言,其中针对JavaScript开发者的部分,我挑了几条和本文有关的调查结果:

  • ECMAScript6:高达82%的受访者在使用
  • Web框架:有49%的受访者选择了React,44%选择了AngularJS
  • 模块加载器:超过一半的受访者选择了Webpack,22%选择了RequireJS和Browserify
    以上信息摘自微信公众号 Web开发

说实话,这些技术只有用过后才能明白它们究竟为何如此的火,如果还没尝试过,建议花些时间追赶一下时代的潮流。

为什么写这篇文章


年初时第一次折腾Gulp+Webpack+React,学习曲线陡峭到一星期过去了仍一头雾水。后来扒了一个开源项目的整套配置后才勉强可以开始开发项目。当时是做门户页,不需要用ArcGIS API for JavaScript,不过我还是尝试了一个demo,那感觉形容起来~~Dojo和Webpack天生八字不合!

最近为了做新框架,又花了几天研究Webpack和Dojo的文档,终于算是把这一对冤家撮合到一起了,还一并解决了一些衍生问题,谨以此文犒赏我这个辛勤的媒婆~

前置知识


如果在阅读本文时遇到了困难,你可能需要补充一些相关技术知识,这里可以链接到官方文档或不错的教程
ECMAScript6 —— ECMAScript 6 入门 阮一峰
Webpack 3 —— 官方文档
ArcGIS API for JavaScript 4.4 —— 官方文档
Dojo 1.12 —— 官方文档

如果你没接触过 Webpack,很抱歉本文并不会讲解 Webpack 的基础知识。
如果你还不太理解 Dojo 的模块加载机制,即 AMD,请先行掌握其精髓。
如果你发现下面的某段代码比较怪异,那么它可能是用 ECMAScript6 写的,或者是一段 EJS 模板代码。

下面才是正文


写在正文的最前面


本文相关技术实现已经整理到了一个开源项目中,这个项目是一个WebGIS网站开发骨架,集成了 ArcGIS API for JavaScript Webpack Bootstrap React Sass,你可以直接使用这个骨架开发自己的应用,也可以下载下来对照着理解这篇文章或用来学习Webpack。
项目传送门:Fantasy Skeleton Arcgis

让 ArcGIS API for JavaScript 和 Webpack 和谐共处


大致思路前人已经给出了,核心就是将Webpack的编译环境设置为AMD,即:

output: {    libraryTarget: 'amd',}

想看原文请点:前人思路传送门
上面这个参数的作用,请仔细看官方文档:output.libraryTarget

那么下面按步骤来~~

1.在html页面中添加ArcGIS API for JavaScript的js和css文件引用

<link rel="stylesheet" href="https://js.arcgis.com/4.4/esri/css/main.css"/><script src="https://js.arcgis.com/4.4/init.js"></script>

2.修改Webpack配置

output: {    ...    libraryTarget: 'amd',    ...},externals: [    (context, request, callback) => {        if (/^dojo/.test(request) ||        /^dojox/.test(request) ||        /^dijit/.test(request) ||        /^esri/.test(request)        ) {             return callback(null, `amd ${request}`)        }        return callback()    },],

3.添加打包文件引用
在html页面中添加对Webpack打包后的文件的引用,一定要加在api的init.js文件引用后面。

require(['app.js'],function () {    ...})

4.调用api
这样设置之后,就可以像下面这样调用api了。

import Map from 'esri/Map'import MapView from 'esri/views/MapView'var map = new Map({    basemap: 'streets'})var view = new MapView({    container: yourDom,    map: map})
上面发生了什么?

我们的html代码中会有类似这样的一段

<script src="https://js.arcgis.com/4.4/init.js"></script>require(['app.js'],function () {   ...})

首先,ArcGIS API for JavaScript的init.js文件被最先加载,这就意味着其中的dojo带来的模块加载器AMD已经可以用了,那么此时有了全局的 define 函数和 require 函数,前者在AMD中用来定义模块,后者用来加载模块。
紧接着就用 require 函数来加载Webpack打包好的我们的应用代码 app.js文件,这个文件大概是下面这个样子

define(["esri/Map", "esri/views/MapView"],    function (__WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__){        // 这个函数被立刻执行了,注意函数定义后面直接有一个(),        // 括号里就是modules参数,是一个数组。        return(function (modules) {              ...              var installedModules = {}; // 模块缓存              // import语句均被编译成对该函数的调用              function __webpack_require__(moduleId) {                    ...                   // 省略的这一部分代码也不复杂,                   //主要逻辑是如果模块不在缓存中,则执行下面数组中的对应id的函数,                   //然后把exports存到缓存里                   return module.exports;              }        })([              /* 0 */,              /* 1 */(function (module, exports, __webpack_require__) {                  var _Map = __webpack_require__(3);                  var _MapView = __webpack_require__(4);                  var map = new _Map2.default({                      basemap: 'streets'                  });                  ...              }),              /* 2 */,              /* 3 */(function (module, exports) {                  module.exports = __WEBPACK_EXTERNAL_MODULE_3__;              }),              /* 4 */(function (module, exports) {                  module.exports = __WEBPACK_EXTERNAL_MODULE_4__;              }),              /* 5 */,        ])    })

这段代码就是Webpack的精华了,我三言两语估计也说不透彻,还需要在实践中加深理解。
首先是第一句,这个 define 函数的调用,是因为之前指定的 libraryTarget: 'amd' ,如果指定了其他的值,这里就不会有 define 函数了。
define 函数的第一个参数是["esri/Map", "esri/views/MapView"],在这里也不是随意出现的,而是因为上面设置的这一段

externals: [    (context, request, callback) => {        if (/^dojo/.test(request) ||        /^dojox/.test(request) ||        /^dijit/.test(request) ||        /^esri/.test(request)        ) {             return callback(null, `amd ${request}`)        }        return callback()    },],

/^esri/.test(request) 探测import语句引入的模块,如果通过test,则使用AMD方式从外部引入。因此,import Map from 'esri/Map' 语句在编译时被判定为需要从外部引入,所以在打包文件的开头生成了这样的语句:

define(["esri/Map", "esri/views/MapView"],    function (__WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__){    ...    })

这是在使用ArcGIS API for JavaScript时常用的定义类或组件的方法,而且实际执行起来也是一样的,__WEBPACK_EXTERNAL_MODULE_3__中就是我们需要的 Map 类。

之后import Map from 'esri/Map' 自身被编译为 var _Map = __webpack_require__(3); ,
__webpack_require__(3) 语句调用了 modules数组中索引为3的函数,返回了__WEBPACK_EXTERNAL_MODULE_3__ 即 Map 类

貌似我也没解释清楚上面发生了什么

其实Webpack用到现在,很多配置我都不知道是如何起作用的,更不要说那么多的中间件。也是借着写这个文章我才静下心来研究一下Webpack到底做了什么。现在看来之前觉得Webpack学习曲线过高,只是因为一直在用它,而不是去试图理解它。这段Webpack编译成的代码的逻辑并不复杂,如果你被我的解释说糊涂了,请尝试做一个简单的demo或使用 Fantasy Skeleton Arcgis 项目中的代码,实际感受理解一下。

这里本不该是结尾


其实本来这个话题只想写成一篇的,但是写到这里就有点长了,分成两篇吧。
第二篇的内容有两个方面:

  1. 当ArcGIS API for JavaScript和Webpack相遇后,如何引入第三者 ~ 咳 ~ 第三方库,比如jquery,lodash,react 等等,当使用AMD时,直接引入第三方库的js文件可能导致multiple definedundefined错误,有一个技巧可以解决这个问题。
  2. 当要开发一个基于ArcGIS API for JavaScript的组件库时,你可能希望这个库的js文件在API的init.js文件引入后直接引入就好,然后在使用时也用import语句导入其中的模块。这也需要一些变通之策。

这第二篇的内容就找不到前人的思路了,我的方法也不会是唯一的办法,希望大家期待我的下一篇,我也期待和各位的交流。

最后还有广告


如果你查看了 Fantasy Skeleton Arcgis 项目,并点进我的个人页看了项目列表的话,会发现一系列Fantasy开头的项目,这里我列出几个目前可用的供参考,其他的目前都还不可用。
这几个项目都是网站开发骨架,基于Gulp、Webpack构建,支持Eslint、Sass、hot-reload开发

ProjectDescriptionFantasy Skeleton Bootstrap集成了BootstrapFantasy Skeleton React集成了Bootstrap、React、react-routerFantasy Skeleton Arcgis集成了ArcGIS API for JavaScript 4.4、Bootstrap、React、react-routerFantasy Skeleton Leaflet集成了Leaflet、Bootstrap、React、react-router

希望大家喜欢~

我的文章会同时通过个人微信公众号推送出来,欢迎大家关注,一起交流~~

阅读全文
0 0
原创粉丝点击