webpack 外部扩展[ externals ]

780 阅读2分钟

image.png 图片来自  微信公众号:豆芽的小阁

背景

最近从零开始写一个地图相关的 vue 项目,当我创建好项目,并正确引入高德 JSAPI 时,在 index.html 页面能正确获取到 AMap 对象,但当我在组件中 import AMap对象,执行程序的时候,却报错

image.png

后来发现这个东西是要在 webpack 中配置好 externals

解决方案

我使用的是 vue-cli3去创建 vue 项目的,vue-cli 是使用 webpack的打包的,当 import 的时候, 会去 boundle 中去读取 import 的对象的。而高德 JSAPI 只允许在线加载,是通过 script 的方式引入项目中的,所以 boundle 中并未打包的有 AMap 对象,若使用 import 的话,就需要在 vue.config.js 中配置好 AMap 依赖。

配置如下:

vue.config.js

module.exports = {
  configureWebpack: config => {
    const externals = {
      AMap: 'window.AMap',
      Loca: 'window.Loca'
    };
    config.externals = { ...config.externals, ...externals };
  },
}

当然,当你不想配置的话,那就只能新建一个对象去指向 window 中的 AMap

App.vue

<script>
   const AMap = window.AMap
   export default {
      name: 'App',
      data(){
        return {
          mapObj: null
        }
      },
      methods: {
    initMap(){
      var map = new AMap.Map('app', {
        zoom:11,//级别
        center: [116.397428, 39.90923],//中心点坐标
        viewMode:'3D'//使用3D视图
      });
      this.mapObj = map;
    },
  }
</script>

externals 说明【摘自官方网站

  1. externals是一个 webpack 的一个配置项,中文名叫做外部扩展,该配置项提供了从输出的 bundle 中排除依赖的方法。

  2. externals的作用:防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)

  3. 举个例子

  • 从 CDN 上引入 jQuery,而不说把它打包 index.html
<script
  src="https://code.jquery.com/jquery-3.1.0.js"
  integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
  crossorigin="anonymous">
</script>

webpack.config.js

externals: {
  jquery: 'jQuery'
}

这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:

import $ from 'jquery';

$('.my-element').animate(...);

具有外部依赖(external dependency)的 bundle 可以在各种模块上下文(module context)中使用,例如 CommonJS, AMD, 全局变量和 ES2015 模块。外部 library 可能是以下任何一种形式:

  • root:可以通过一个全局变量访问 library(例如,通过 script 标签)。
  • commonjs:可以将 library 作为一个 CommonJS 模块访问。
  • commonjs2:和上面的类似,但导出的是 module.exports.default.
  • amd:类似于 commonjs,但使用 AMD 模块系统。

可以接受各种语法……

App.vue 完整代码

<template>
  <div>
    <button @click="mapClickHandle">地图点击事件</button>
    <div id="app"></div>
  </div>
</template>
<script>
import AMap from 'AMap'
export default {
  name: 'App',
  data(){
    return {
      mapObj: null
    }
  },
  mounted(){
    this.initMap();
  },
  methods: {
    initMap(){
      var map = new AMap.Map('app', {
        zoom:11,//级别
        center: [116.397428, 39.90923],//中心点坐标
        viewMode:'3D'//使用3D视图
      });
      this.mapObj = map;
      map.on('click', function(){
        let center = map.getCenter();
        console.log('center', center)
      })
      map.on('complete', () => {
        this.initMarker()
      })
    },
    initMarker(){
      var marker = new AMap.Marker({
          position: new AMap.LngLat(120.009221, 29.8872),   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
          draggable: true,
      });
      this.mapObj.add(marker)
      this.mapObj.setCenter([120.009221, 29.8872])
      // this.mapObj.setFitView()
    },
    mapClickHandle(){
      let center = this.mapObj.getCenter();
      console.log('点击按钮, 获取center', center)
    }
  }
}
</script>

<style>
#app, .mapContainer {
  border: 1px solid red;
  width: 100vw;
  height: 90vh;
  margin: 0 auto;
}
</style>