Skip to content
目录

常见问题

这里总结下用户在前端工程化方面遇到的问题

我喜欢现代化开发可以不打包吗?

可以的,目前市面上的打包工具都提供了了 externals功能的

  • webpack(一般是自己搭建的脚手架/React/Angular等)
js
//weppack.config.js

externals: {
    maptalks: "maptalks";
}
  • vue-cli
js
//vue.config.js

configureWebpack: {
    externals: {
      maptalks: "maptalks"
    },
}
  • vitejs
js
//vite.config.js

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { viteExternalsPlugin } from "vite-plugin-externals";

// https://vitejs.dev/config/
export default defineConfig({
    plugins: [
        vue(),
        viteExternalsPlugin({
            maptalks: "maptalks",
        }),
    ],
});

在MVVM框架里发现地图性能非常差?

GIS引擎是个非常复杂的东西,不像我们平时写的一些传统的前端的业务,GIS里的地图对象是个非常复杂的对象,进过MVVM包裹后其性能会变得非常差,以vue为例经过本人测试会有20倍的差距,所以在开发时不要个将地图相关的东西进行响应式包裹,以vue为例

  • 不要将地图,图层,图形,gis的业务数据放到data里,vue会将地图等进行包裹导致(Proxy/Object.defineProperty),因为地图等是个非常复杂的对象, 从而导致性能急剧下降,内存飙升.
  • 项目编译的 target要尽可能的高,比如你将target设置为es5会导致编译好的代码里插入了大量的polyfill的东西,一般都是corejs里东西,相对于原生浏览器提供的,polyfill的代码性能比较差,而地图里数据一般都比较大,会有大量的循环等操作,故而导致性能下降
  • 如果你确实需要在组件之间进行地图等相关的传递,可以这样做:
    • 写个独立的js工具函数,用来管理地图等对象,其可以进行地图等获取,删除等操作
    • 在组件参数传递时仅仅传递地图的对象的id(map.id),然后组件里拿到地图的id,从你写的地图管理工具函数里去获得地图等对象
    • 总之就是在组件话开发时的数据传输链路上不要将地图这些复杂的对象作为参数,可以用简单的key作为参数,然后再组件里用这个key去拿地图等对象
js
//大意代码
const mapCache = {};
funciton getMap(id){
   return mapCache[id];

}

function setMap(id,map){
  mapCache[id]=map;
}

//在vue组件传参时(prop),仅仅传递id即可,在对应的组件里进行

  const map=getMap(this.mapId);

TIP

不仅仅是地图,其他方面的比如threejs,echarts图表等这些非常复杂的东西都会存在类似的问题,所以在MVVM框架里使用这些非常复杂的对象的东西一定不要进行对象的包裹

在打包项目时发发生一些奇奇怪怪的错误

这种一般都是你在工程里进行了polyfill导致的,尤其是promisefetch相关的polyfill,maptalks里因为有大量的数据处理和计算很多逻辑会放到worker里执行,如果你polyfill了,可能导致worker里涉及到promisefetch会发生一些未知的错误

不要在路由里不断的创建和销毁地图

地图的创建

我们创建地图一般都是

js
var map = new maptalks.Map("map", {
    center: [180, 0],
    zoom: 4,
});

但是有的同学喜欢将地图封装成组件,尤其在vue项目里,这时要注意,因为组件是多例的,所以创建地图是不能把地图容器的dom(上面代码里的map)写死了
地图创建时也是支持传入dom节点对象的,不仅仅是domid

js
var map = new maptalks.Map(document.getElementById('map)',{
     center:     [180,0],
     zoom:  4
});

在vue里组件化我们可以借助ref来动态传入地图创建时的dom节点

js
var map = new maptalks.Map(this.$refs.map, {
    center: [180, 0],
    zoom: 4,
});

地图的销毁

js
map.remove();

当一个地图不在使用了,要记得将其销毁,尤其是vue等现代化开发的SPA项目,否则路由的切换会不断的创建地图,从而导致页面崩了.

地图是个非常复杂的对象,非常吃资源,不断的创建和销毁也不是个好的方法 建议的做法: 将地图创建为个全局变量或者dom元素,路由等切换只是改变页面的非地图模块和要素 比如这样的一个页面,路由切换的仅仅切换地图上面的菜单和面板等,而地图是独立的元素,是不包含在路由里的

  • 路由切换时只切换非地图的东西
  • 切换路由时利用地图的方法动态切换地图上的要素,比如图层的动态添加和删除,地图视角等的改变,千万不要去随随便便的创建一个新的地图
  • 代码设计层面
html
<h1>Hello App!</h1>
<!--地图容器,不把其放到路由里-->
<div class="map" id="map"></div>
<p>
    <!--使用 router-link 组件进行导航 -->
    <!--通过传递 `to` 来指定链接 -->
    <!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
</p>
<!--路由容器-->
<router-view></router-view>

vue-cli等工具打包geojson文件时内存溢出

vue-cli底层的打包工具是webpack,webpack 不怕文件多,就怕单个文件体积特别大,所以当你的一个 js/json 文件好几 M 的时候,且这个文件只是数据文件,你应当

把数据文件放到 public 目录下作为静态资源,因为静态的数据文件打包没有任何意义,然后再业务代码里用ajax来动态读取这个文件

TIP

在前端开发中,json文件,图片,视频,excel等这些静态的东西,我们一般视为非代码的东西,最好不要打包,放到静态目录即可,需要的地方读取即可

将地图等进行组件包装有意义吗?

没有意义,因为现代化前端的框架的本质都是数据驱动DOM,比如一个数组渲染成表格,但是地图是个非常特殊的东西, 这个体系里几乎没有DOM的存在,万物都是js对象(除了UI模块,地图,图层,图形, 样式等都是纯js的对象),所以你将其做成组件将显得没有意义了,因为其没有dom给你来进行驱动, 另外因为地图是个典型的数据量大,计算复杂的业务对象,组件化稍微一不注意就是内存溢出和性能暴跌

会提供Vue/React等组件库吗?

不会,就像上面说的,将地图包装成组件是没有意义的,因为地图里几乎没有DOM的存在,那么现代化框架最核心的功能 数据驱动DOM将失去意义

  • 目前maptalks里关于数据状态的更新都是使用set,config等方法来更新的:
js
map.setCenter([0,0]),
map.config({centerCross:true});
....
  • 如果使用React封装成组件,最后还是各种set
  • 如果使用Vue来封装,最后就是:
js
this.center = [0, 0];

然后在组件内部还是去调用

js
this.map.setCenter(prop.center);
  • 自始至终都没有涉及到html,jsx,tsx,template等(用js数来驱动这些组件模板),全部都是js驱动js,唯一的区别就是:
js
//vue 哲学
this.center = [0, 0];
//react 哲学
setCenter([0, 0]);

的区别

理由

  • maptalks是个纯脚本库,封装成组件后变成DSL,灵活度大打折扣(可以类比HTML和js的灵活度)
  • 和vue/react等深度耦合了,地图和这些前端框架应该是没有任何耦合关系的
  • 由于DSL的固有的属性关系,DSL的type支持是很差的,这就是为什么vue templte的type支持情况永远不如js/ts/jsx等原因
  • 性能损失比较严重,本来整个地图库的流程是 js->maptalks,现在变成了template parse->js->maptalks,多了个template parse过程 自己可以手动试试在vue里v-for个10w个图形,然后对比下和原生js对比的性能差距
  • 泛型约束失效,比如map上面只可以添加图层(Layer组件),封装成组件后用户可能把图形(Geometry组件)放到地图里,因为DSL的关系, 组件里没法子做强制约束了和判断了,设么意思?

正常的组件嵌套逻辑是这样的:

html
<MapCom>
    <Layer>
        <Geometry></Geometry>
    </Layer>
</MapCom>

如果用户这样写怎么办?

html
<MapCom>
    <Geometry></Geometry>
</MapCom>

This document is generated by mdpress