使用场景
使用vue-cli创建项目,使用webpack打包。其中,有一个webpack优化webpack.optimize.CommonsChunkPlugin,它会将node_modules中的必需模块提取到vendor文件中,项目开发中,增加第三方模块,比如element-ui、vue-echarts等,vendor的包都会增大。这个时候,就需要考虑减轻vendor包的大小,增加构建速度。我们可以使用webpack的外部扩展(externals)功能。
externals配置选项,可以防止将import的包打包到bundle中,并在运行时再去从外部获取这些扩展依赖。大白话:请不要将这个模块注入编译后的JS文件里,对于我源代码里出现的任何
import/require这个模块的语句,请将它保留
使用方式
以jquery为例,我们将从CDN上引入它,而不是将它下载到本地:
<body><div id="app"></div><script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script><!-- built files will be auto injected --></body>
在vue.config.js文件里面加上:
module.exports = {···configureWebpack: config => {config.externals = {// key 值 jquery 是要引入的别名// value 值 jQuery 是 jquery 库对外暴露的全局变量'jquery': 'jQuery',}},...
可以在main.js中使用:
import $ from 'jquery'
原理分析
我们新建一个index.js文件:
import $ from 'jquery'
$("#content").html("<h1>hello world</h1>");
新建webpack配置文件webpack.config.js:
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
jquery是通过npm i安装的,使用webpack打包后,查看webpackBootstrap参数部分的代码:
({
"./node_modules/jquery/dist/jquery.js": (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
* jQuery JavaScript Library v3.4.1
* https://jquery.com/
*
* Includes Sizzle.js
* https://sizzlejs.com/
*
* Copyright JS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2019-05-01T21:04Z
*/
...
}),
"./src/index.js": (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */
var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! jquery */ "./node_modules/jquery/dist/jquery.js");
/* harmony import */
var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);
jquery__WEBPACK_IMPORTED_MODULE_0___default()("#content").html("<h1>hello world</h1>");
}),
})
可以看到jquery源码都打包进来了,我们再配置externals:
externals: {
jquery: "jQuery",
}
再查看webpack打包后的webpackBootstrap参数部分的代码:
({
"./src/index.js": (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */
var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! jquery */ "jquery");
/* harmony import */
var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);
jquery__WEBPACK_IMPORTED_MODULE_0___default()("#content").html("<h1>hello world</h1>");
}),
"jquery": (function(module, exports) {
module.exports = jQuery;
})
})
可以看到jquery的源码替换成module.exports = jQuery了,这也是externals的作用。**jQuery**是**jquery**库暴露在全局的变量,**module.exports**是**webpack**自身维护的供外部使用的输出变量(不是**node**自带的),也就是说当**import xxx from jquery**的时候,实际上是从被暴露的**jQuery**全局变量引入,这就是核心!
设置 externals 形式
global- 外部library能够作为全局变量使用。用户可以通过在script标签中引入来实现。这是externals的默认设置。commonjs2- 保留require()语句,适用于node环境。AMD- 在define中定义依赖模块。umd- 通用方式,包括commonjs2、AMD和全局变量方式,
在externals中配置:
externals: {
jquery: 'commonjs2 jQuery'
}
// 打包后的形式
module.exports = require('jQuery')
externals: {
jquery: 'jQuery'
}
// 打包后的形式
module.exports = jQuery
使用默认设置时,如果想让你的代码运行在浏览器中,你所引用的包,必须暴露出一个全局变量。如果没有,这种方式不适合在浏览器下使用。
libraryTarget / library / externals
libraryTarget:在output中配置,指定你的模块输出类型。library:在output中配置,可以指定你的库的名称。libraryTarget配置如何暴露library。如果不设置library,那这个library就不暴露,就相当于一个自执行函数。externals决定的是以哪种模式去加载所引入的额外的包。**libraryTarget**决定了你的**library**运行在哪个环境,哪个环境也就决定了你哪种模式去加载所引入的额外的包。也就是说,**externals**应该和**libraryTarget**保持一致。**library**运行在浏览器中的,你设置**externals**的模式为**commonjs**,那代码肯定就运行不了了。
注意点
如果通过这种方式引入第三方包出现问题,可以通过以下几个方向进行查找:
script的先后顺序;cdn的地址路径是否正确;- 引入的变量名是否和
externals属性中的value相对应,可以在console控制台输出看看。 - 确定
externals和libraryTarget所支持的环境是否一致。
关于webpack externals更多详解可以参考这篇文章。
