在 《解决Vue项目打包后文件过大问题》一文中提到了借用Webpack-externals配置项,在打包时将依赖独立出来,本文详细讲解下externals的使用。

externals 配置项提供了阻止将某些 import 的包(package)打包到 bundle 中的功能,在运行时(runtime)再从外部获取这些扩展依赖(external dependencies)

externals用法:

module.exports={configureWebpack:congig =>{externals:{key: value}}
}

语法说明:

  • key是第三方依赖库的名称,同package.json文件中的dependencies对象的key一样

  • value值可以是字符串、数组、对象。应该是第三方依赖编译打包后生成的js(要用CDN引入的js文件)文件,执行后赋值给window的全局变量名称。

那么,如何找这个全局变量呢?以element-ui为例:找到element-ui的CDN资源,如果是压缩后的文件,可以使用js在线格式化工具进行处理。格式化后代码如下:

function(e, t) {"object" == typeof exports && "object" == typeof module ? //判断环境是否支持commonjs模块规范module.exports = t(require("vue")) :"function" == typeof define && define.amd ? //判断环境是否支持AMD模块规范define("ELEMENT", ["vue"], t) :"object" == typeof exports ? //判断环境是否支持CMD模块规范exports.ELEMENT = t(require("vue")) : e.ELEMENT = t(e.Vue)
} ("undefined" != typeof self ? self: this,function(e){//省略...
});

从代码可以看出element-ui是用UMD模块规范输出的,所以

  • 兼容commonjs模块规范(在node环境中使用)。
  • 兼容AMD模块规范(用require.js引入使用)。
  • 兼容CMD模块规范(用sea.js引入使用)。

代码中对各个环境做了判断,因为是用CDN在public/index.html引入,也就是浏览器环境,不符合上面各种环境,最后执行

e.ELEMENT = t(e.Vue)

其中e为window对象,那么赋值给window的全局变量名称是ELEMENT。

在vue.config.js中配置如下:

module.exports={configureWebpack:{externals: {'element-ui': 'ELEMENT',}}
}

在public/index.html中引入

<body><div id="app"></div><script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
</body>

运行后,发现报错了,如下图:

再看一下e.ELEMENT = t(e.Vue),发现还需要Vue,那么把Vue依赖包也提取出来。Vue编译打包生成js的文件,格式化后如下:

function(t, e) {"object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = t || self).Vue = e()
} (this,function(){//省略...
})

在浏览器中最后执行(t = t || self).Vue = e(),其中t为this,this是window对象。那么赋值给window的全局变量名称是Vue。 在vue.config.js中配置如下:

module.exports={configureWebpack:{externals: {'element-ui': 'ELEMENT','vue': 'Vue',}}
}

在public/index.html中引入

<body><div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script><script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>
</body>

那么,如何判断外部资源是否成功引入了呢?在不好辨别插件赋值给window的全局变量名称是什么时候,又该如何处理呢?以xlsx为例:

var XLSX = {};
function make_xlsx_lib(e){//省略...
}
if (typeof exports !== "undefined") make_xlsx_lib(exports);
else if (typeof module !== "undefined" && module.exports) make_xlsx_lib(module.exports);
else if (typeof define === "function" && define.amd) define(function() {if (!XLSX.version) make_xlsx_lib(XLSX);return XLSX
});
else make_xlsx_lib(XLSX);
var XLS = XLSX,

从上面的代码中不好判断赋值给window的全局变量名称是什么了,先猜测用的是XLSX,在public/index.html中引入:

<body><div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script><script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.1/xlsx.min.js"></script>
</body>

把public/index.html这个文件丢到浏览器打开,然后在控制台输入window.XLSX,看看有没有值。输出如下:

window.XLSX输出有值,不为undefined,说明赋值给window的全局变量名称是XLSX。那么在vue.config.js中配置如下:

module.exports={configureWebpack:{externals: {'element-ui': 'ELEMENT','vue': 'Vue','xlsx': 'XLSX'}}
}

再次执行npm run dev,刷新页面无报错。

用externals提取第三方依赖包后,代码原先引入依赖的地方,要不要去改动呢?比如main.js中:

import ElementUI from 'element-ui';
Vue.use(ElementUI);

正常是不需要改动的。如果把<script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>放在app.js后面引入:

<body><div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.1/xlsx.min.js"></script>
</body>
<script src="https://unpkg.com/element-ui@2.10.1/lib/index.js"></script>

编译打包后,dist/index.html生成内容如下:

此时刷新浏览器,报错如下:

删除main.js中的引用,删除后,刷新浏览器,无报错。

import ElementUI from 'element-ui';
Vue.use(ElementUI);

前面提到element-ui的CDN链接放在app.js后面引入,main.js里面的代码都会编译打包到app.js中,在执行app.js时会遇到element-ui。但是,由于element-ui的CDN链接是放在app.js后面加载执行的,这时ElementUI是不存在的,所以会报错。

所以只要保证element-ui的CDN链接放在app.js之前加载,就不会报错。换句话来说,只要在main.js中需要引入的依赖,其CDN链接都要放在app.js之前加载,这样就不需要去改变原来引入依赖的代码。

但是,app.js是入口文件,放在app.js之前加载,会不会阻塞app.js的加载和执行呢?其实并有没有影响,因为app.js已经用link标签做了预加载。js文件的加载是并发的,谁先加载完先执行谁。

我们的最终目的是减少http请求资源大小,用externals提取第三方依赖包时,提取的过细将会增加http请求数量。

附:
webpack外部扩展(externals)文档

本文转载自https://juejin.cn/post/6844904190083350542

Webpack--externals(外部扩展)详解相关推荐

  1. PHP中cal_days_in_month函数和calendar扩展详解

    PHP中cal_days_in_month函数和calendar扩展详解 问题: 在开发中无意间发现cal_days_in_month函数不可使用.然后就开始研究学习. 1.cal_days_in_m ...

  2. vue webpack 访问php,实例详解vue-cli优化的webpack配置

    最近的项目度过了开始忙碌的基建期,也慢慢轻松下来,准备记录一下自己最近webpack优化的措施,希望有温故知新的效果.本文主要介绍了详解基于vue-cli优化的webpack配置,小编觉得挺不错的,现 ...

  3. vue-cli脚手架中webpack配置基础文件详解

    一.前言 vue-cli是构建vue单页应用的脚手架,输入一串指定的命令行从而自动生成vue.js+wepack的项目模板.这其中webpack发挥了很大的作用,它使得我们的代码模块化,引入一些插件帮 ...

  4. STM32开发 -- 外部中断详解

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/87376865 在讲三轴加速度计的时候,提到外部中断.接下来就看看中断为什么这 ...

  5. PHP扩展详解(一)

    为什么80%的码农都做不了架构师?>>>    PHP详解 一个php实例,当被调用的时候,都会一次经过Module init,Request init,Request shutdo ...

  6. 【STM32学习笔记】(13)——外部中断详解

    EXTI 简介         EXTI(External interrupt/event controller)-外部中断/事件控制器,管理了控制器的 20 个中断/事件线.每个输入线可以独立地配置 ...

  7. <转>OSPF OE2和OE1外部路由详解(主要解释了下OE2为什么没默认负载均衡)

    从OSPF的ASBR重分发的外部路由,会生成OE1和OE2的两类路由在OSPF区域中进行传递. cisco默认的外部路由的类型是OE2.默认的metric=20,不会根据链路的cost进行累加. 而O ...

  8. 03-OSPF OE2和OE1外部路由详解

    Technorati 标签: OSPF,CCIE,OE1,OE2,forward metric 从OSPF的ASBR重分发的外部路由,会生成OE1和OE2的两类路由在OSPF区域中进行传递. cisc ...

  9. webpack概念以及配置文件详解

    Webpack 概念 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建一个依赖关系 ...

最新文章

  1. Ubuntu18彻底删除MySQL5.7数据库
  2. Deno 正式发布,彻底弄明白和 node 的区别
  3. python菜鸟教程函数-Python 函数装饰器
  4. 声明和定义结构体需要注意的问题
  5. cas 连接oracle,Oracle 生成系统数据导入测试系统及smarteam 连接更改
  6. PHP10段常用功能代码
  7. Asynchronous(异步处理-Generator)
  8. Python正则表达式用法总结
  9. 数据科学 IPython 笔记本 9.3 理解 Python 中的数据类型
  10. php 操件文件指定编码,(PHP帮助)如果文件中存在特定编号,请执行此操作
  11. Vue计算属性的_set与get方法_实现双向数据传递---vue工作笔记0006
  12. ACM题目————STL练习之众数问题
  13. Apple Pay如何使用?全网最完美攻略(图文教程)!
  14. java真香表情包_真香表情包 - 真香微信表情包 - 真香QQ表情包 - 发表情 fabiaoqing.com...
  15. Tensorflow2.5(gpu)+Python3.9+Spyder5的平台搭建
  16. 1.CPU体系架构-RISC指令集和CISC指令集
  17. java开发融云web聊天
  18. php必应壁纸 分辨率,必应壁纸php获取接口
  19. 安卓学习笔记3.1 线性布局
  20. 新版华为P30,这5个新功能C位出道,3988值得拥有

热门文章

  1. 粗糙集在计算机网络中的应用,粗糙集理论在入侵检测系统中的应用研究软件工程专业论文.docx...
  2. 我们去工作到底为了什么?
  3. 推荐 30 款最好的免费项目管理软件
  4. python交叉验证法_详解python实现交叉验证法与留出法
  5. 关于matlab中矩阵与逆矩阵为何相乘不等于单位阵的问题
  6. 【微信小程序】如何实现用户输入信息并进行反馈
  7. android mvvm架构-基于Jetpack
  8. html单页面js完成表数据库自动生成带注释的java实体类和简单的增删改查sql
  9. 如何从solidworks导出URDF模型
  10. Vijos 1028-魔族密码【暴力】