webpack之externals详解(精华)

2020-01-13 23:36:35

参考地址 深入浅出webpack之externals的使用

这篇文章主要介绍了深入浅出webpack之externals的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

我们通常在做项目时可能会把第三方库打包到bundle中,比如下面这张图

如果不想把第三方库打包到bundle中,这就有了externals。官方的使用externals比较简单

externals

官网文档解释的很清楚,就是webpack可以不处理应用的某些依赖库,使用externals配置后,依旧可以在代码中通过CMD、AMD或者window/global全局的方式访问。

只需三步——

1.在HTML中引入第三方库的cdn

2.在webpack中配置externals

?

1
2
3
externals: {
 jquery: "jQuery",
}

3.在js中引用

?

1
2
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引入,直接使用全局变量也是可以的。

?

1
jQuery("#content").html("<h1>hello world</h1>");

大家如果注意到我刚说过的global模式的话,没错,你也许已经猜到了,我可以任意的使用不同的输出方式。如果打包文件我想运行到node环境下,我得使用commonjs规范,所以你要这么写。

?

1
2
3
externals: {
 jquery: "commonjs2 jQuery",
}

打包后会是这样子。

然后我的项目中还用到了lodash,也想把它从bundle中移除,之前我的代码是这样子,引的是npm包

现在我们的externals配置如下

?

1
2
3
4
5
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等等)引入,这意思就是说,打包的时候不需要关心他到底怎么输出。

?

1
2
3
4
5
6
7
8
9
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规范,贴下最终的配置

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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'
 },


  • 2019-08-28 08:28:36

    Js apply,call方法详解,及其apply()方法的妙用

    在给对象参数的情况下,如果参数的形式是数组的时候,比如apply示例里面传递了参数arguments,这个参数是数组类型,并且在调用Person的时候参数的列表是对应一致的(也就是Person和Student的参数列表前两位是一致的) 就可以采用 apply , 如果我的Person的参数列表是这样的(age,name),而Student的参数列表是(name,age,grade),这样就可以用call来实现了,也就是直接指定参数列表对应值的位置(Person.call(this,age,name,grade));

  • 2019-08-28 08:49:47

    Nginx + fastcgi + php 的原理与关系

    CGI对每个请求会parse一遍对应脚本的配置文件(如php.ini), 加载配置和扩展,初始化执行环境,性能非常差,所有有了下面的流程:

  • 2019-08-28 09:23:15

    php单例模式

    单例模式,是一种常见的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。

  • 2019-08-28 22:45:02

    彻底搞懂Gradle、Gradle Wrapper与Android Plugin for Gradle的区别和联系

    Gradle是个构建系统,能够简化你的编译、打包、测试过程。熟悉Java的同学,可以把Gradle类比成Maven。Gradle Wrapper的作用是简化Gradle本身的安装、部署。不同版本的项目可能需要不同版本的Gradle,手工部署的话比较麻烦,而且可能产生冲突,所以需要Gradle Wrapper帮你搞定这些事情。Gradle Wrapper是Gradle项目的一部分。

  • 2019-08-30 21:53:51

    OpenSSL实践-Android下的编译和使用

    openssl可以编译成ARM下面的二进制代码(动态库或者静态库),方便APP使用,APP在使用的时候,需要使用JNI来进行调用。