我们通常在做项目时可能会把第三方库打包到 bundle 中,比如下面这张图
如果不想把第三方库打包到 bundle 中,这就有了 externals。官方的使用 externals 比较简单
externals官网文档解释的很清楚,就是 webpack 可以不处理应用的某些依赖库,使用 externals 配置后,依旧可以在代码中通过 CMD、AMD 或者 window/global 全局的方式访问。
只需三步——
1. 在 html 中引入第三方库的 cdn
2. 在 webpack 中配置 externals
- externals: {
- jquery: "jQuery",
- }
3. 在 js 中引用
- const $ = require("jquery");
- $("#content").html("<h1>hello world</h1>");
好,现在我们可以随心所欲的使用 jquery 插件并保证不会打包到 bundle 中。external 是怎么办到的呢?下面我们通过 bundle 的源码来分析下原理。
这里的 /* 0 */ 和__webpack_require__分别指打包前 js 对应的模块函数,这里就不细说了。这里可以看到 module.exports = jQuery,就是说我们 externals 中的 key 指的是 require 的东西,value 指的就是它,就是说 "当 require 的参数是 jquery 的时候,使用 jQuery 这个全局变量引用它"。这种最简洁的 externals 配置方式为默认的 global 模式,就是在 window 上挂一个全局变量,然后直接可以使用这个变量。具体的流程是这样,我们在源码中使用 require('jquery') 后,可以直接把 jquery 加到 externals 中,得到一个打包的 trunk.js,但是在引入这个 trunkjs 之前,肯定要先引入 jquery 这个库文件,这个库文件会创建一个全局变量 jQuery,而咱们的 trunkjs 中 externals 的 jquery 是 global 模式,所以实际上 trunkjs 引入 jquery 的时候,就会从全局变量中引用,即 module.export = jQuery
当然,既然是通过这种 externals 方式,其实我们可以不用 require 引入,直接使用全局变量也是可以的。
- jQuery("#content").html("<h1>hello world</h1>");
大家如果注意到我刚说过的 global 模式的话,没错,你也许已经猜到了,我可以任意的使用不同的输出方式。如果打包文件我想运行到 node 环境下,我得使用 commonjs 规范,所以你要这么写。
- externals: {
- jquery: "commonjs2 jQuery",
- }
打包后会是这样子。
然后我的项目中还用到了 lodash,也想把它从 bundle 中移除,之前我的代码是这样子,引的是 npm 包
现在我们的 externals 配置如下
- externals: {
- jquery: "jQuery",
- _: "lodash"
- }
我们必须要去掉这个 const ,否则的话会报一个错误 lodash is not defined。为什么会这样呢?因为我们的 lodash 输出是 global 格式的,我在这里先卖一个关子,我们先统一一下输出格式,加一个 libraryTarget 字段
这个东西是干嘛用的呢?
他是我们输出文件的模块化规范,想想我们上面配置的 commonjs jquery 是运行在 node 下,总之记住一句话——我们最长使用的模块化方案是 commonjs2 和 umd,前者是为 node 环境,后者是为浏览器环境。一共有这几种规范:
"var" - Export by setting a variable: var Library = xxx (default)
"this" - Export by setting a property of this: this["Library"] = xxx "commonjs" - Export by setting a property of exports: exports["Library"] = xxx "commonjs2" - Export by setting module.exports: module.exports = xxx "amd" - Export to AMD (optionally named - set the name via the library option) "umd" - Export to AMD, CommonJS2 or as property in root
然后报这个错误,也就是说我们的模块没有正确的输出,回到我们的 externals,它更多的是指定当你引用一个包的时候,这个包 (lodash) 应该遵循哪种模块化方式 (common,root,amd 等等) 引入,这意思就是说,打包的时候不需要关心他到底怎么输出。
- externals: {
- jquery: "jQuery",
- lodash: {
- commonjs: 'lodash',
- commonjs2: 'lodash',
- amd: 'lodash',
- root: '_'
- }
- },
ok,记得要将之前的覆盖掉,替换成下面的 require,因为在 externals 中我们规范的 commmonjs 规范为 lodash
也就是说,这就是我们最初的代码,即没有用过 externals 时候的代码,看,也就是说我们只需要配置 externals 和 libraryTarget 就可以,其他的业务逻辑代码不需要改变。包括我们的项目中还用了 echarts,这个通通不用改变!!!!!
也就是说最终的代码是 externals 配合 libraryTarget 一起使用,如果去掉 umd 的话,会报这个错误
相应的源码是这样子
就是说我不知道通过那种方式输出,所以我应该告诉 webpack,我通过 umd 方式输出, 即将你的 lodash 暴露为所有的模块定义下都可运行的方式。它将在 CommonJS, AMD 环境下运行,或将模块导出到 global 下的变量. 加上 umd 的源码如下
看到了吧,我通过 require('lodash') 引入模块,输出走的是 commonjs 规范, 贴下最终的配置
- entry: {
- main: './src/index.js'
- },
- externals: {
- jquery: "jQuery",
- lodash: {
- commonjs: 'lodash',
- commonjs2: 'lodash',
- amd: 'lodash',
- root: '_'
- }
- },
- output: {
- filename: '[name].[chunkhash].js',
- path: path.resolve(__dirname, 'dist'),
- libraryTarget: 'umd'
- },
来源: http://www.jb51.net/article/129670.htm