webpack 对Externals的说明
外部扩展(Externals)
externals
配置选项提供了「从输出的 bundle 中排除依赖」的方法。相反,所创建的 bundle 依赖于那些存在于用户环境(consumer's environment)中的依赖。此功能通常对 library 开发人员来说是最有用的,然而也会有各种各样的应用程序用到它。
externals
string
[string]
object
function
RegExp
防止将某些 import
的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)。
例如,从 CDN 引入 jQuery,而不是把它打包:
index.html
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"
></script>
webpack.config.js
module.exports = {
//...
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 模块系统
好了说了那么多,总结来说就是
将不怎么需要更新的第三方库脱离webpack打包,不被打入bundle中,从而减少打包时间,但又不影响运用第三方库的方式,例如import方式等
在vue项目里面 vue.config怎么去配置呢?
每次都手动去在index.html里面手动引入外部依赖的cdn路径的。
肯定不是我们需要的,这太笨了。
需要解决的问题:
a. 不打包指定的外部依赖
b. 在index.html自动引入外部依赖
怎么运用externals:
例如:
在index.html中引入CDN的资源react全家桶之类的资源
<script src="https://lib.baomitu.com/react/16.4.0-alpha.7926752/cjs/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.2/cjs/react-dom-server.browser.development.js"></script>
webpack.config.js配置如下:
module.exports = {
...
output: {
...
},
externals : {
xlsx: 'XLSX',
lodash: {
commonjs: 'lodash',
amd: 'lodash',
root: '_', // 指向全局变量
},
redux:'redux',
// 暂时注释,此库采用cdn引入,会导致报错,cdn引入方式,是暴露了X6全局变量,Graph等属性是挂载在X6全局变量里面,
// 但是里面挂载的对象属性都不一样。暂未找到解决方案
// '@antv/x6': 'X6',
'jquery':'jQuery' // 由于@antv/x6依赖了jQuery,这里配置忽略,采用cdn方式引入
}
}
这样的话在应用程序中依旧可以以import的方式(还支持其他方式)引用:
import XLSX from 'xlsx'
import { createStore, combineReducers, applyMiddleware } from 'redux';
XLSX
就是暴露的全局变量,xlsx
库的名称,例如: import XLSX from 'xlsx'
这样不仅之前对第三方库的用法方式不变,还把第三方库剥离出webpack的打包中,从而加速webpack的打包速度。
完整的externals配置如下,我已经将externals对象单独导出一个文件
可以看到上面还有个cdn对象,这个对象是干嘛用的,下面我们就来介绍一下。上面我们已经介绍了配置externals 来忽略打包了。但是我们不可能真的就每次都去手动引入cdn链接,这样就太蠢了。
此时我们肯定是希望运行打包命令的时候自动加载到模板里面。此时我们就需要借助一个webpack的插件 html-webpack-plugin
html-webpack-plugin的使用
html-webpack-plugin是webpack的一个插件,可以动态的创建和编辑html内容,在html中使用esj语法可以读取到配置中的参数,简化了html文件的构建。(
ejs知识点请自行百度,类似jsp跟asp的模板语法
)
最基础的使用方式
new HtmlWebpackPlugin({
// 其他默认配置
cdn: externalConfig// cdn配置
})
定义好了配置则可以再模板里面使用ejs模板语法来读取这个变量了。模板语法可以if、for等函数
index.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<!--配置cdn 的css-->
<% if(htmlWebpackPlugin.options.cdn){ htmlWebpackPlugin.options.cdn.css.forEach(function(item){%>
<link href="<%=item%>" rel="prefetch" />
<% }) }%>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<!--配置cdn 的js-->
<% if(htmlWebpackPlugin.options.cdn){ htmlWebpackPlugin.options.cdn.js.forEach(function(item){%>
<script src="<%=item%>"></script>
<% }) }%>
</body>
</html>
可以看到我先判断有没有cdn这个变量,然后再循环遍历输出。这样就实现了编译之后自动引入cdn外部依赖了。
在vue项目中。我们在vue.config中的 chainWebpack里面,其实我们不需要再去引入html-webpack-plugin
这个库了。因为已经集成了的
chainWebpack: config => {
config.plugin('html').tap((args) => {
args[0].title = 'edge-compute-platform'
// 配置cdn
if (isProduction) {
args[0].cdn = externalsConfig.cdn
}
return args
})
}
看vue-cli源码就知道config.plugin('html')就是html-webpack-plugin
如果只是简单定义一个变量而已就是上面这样的用法。所以到这里引入cdn就完成了。