在webpack打包的过程中,我们往往要做一些代码上的兼容或者打包过程的兼容;
举例来说,之前我们要使用babel polyfill
这样的工具,它解决的问题是,我们打包生成的JS代码运行在低版本浏览器上的时候,有的时候会因为低版本浏览器上不存在promise
这类的变量,导致我们的代码没有办法运行,那为了解决打包生成代码过程中这样的问题,我们就要借助babel polyfill
这样的工具,在低版本浏览器上自动帮我们去构建一些类似promise
这样的全局变量,从而使我们的代码能够在低版本浏览器上运行。
其实这就是一个
webpack
的垫片(shimming)
,它能够解决webpack打包过程中一些兼容性问题。当然这种加兼容性问题,不局限在浏览器的低版本或高版本的这种兼容性问题上,还有一些其他方面。看下边的例子:
在我们使用webpack
的时候,有的时候会出现这样一种情况,比如说我们引入了一个jquery库
,假如这个库叫做jquery.ui.js
.假如库里的代码是下边这样的
- 然后我们在
index.js
里引入这个库,并且执行,相当于给页面初始化了一个背景色
image.png - 我们可以看到在
jquery.ui.js
库里,我们调用了$
符号,通过这个符号把body背景色变为绿色,有些人认为这个代码是没有问题的,但是实际上是不会正确的执行的。我们刷新页面可以看到下边报错,说$
找不到;
image.png - 实际上就是
jquery.ui.js
库里的$
符号找不到。这是为什么呢? 明明我们已经在index.js
里引入了jquery
并赋值给了$
变量了啊?
原因很简单,在
webpack
中,我们是基于模块打包
的,模块里的变量,只能在模块这个文件内使用,而换了文件再想使用上一个文件里的变量是不行的。通过这种形式,我们可以保证模块与模块之间不会有任何的耦合。这样出了问题,我们就直接到自己的模块里去找问题就行了,不会因为一个模块而另外一个模块。因为他们的变量是隔离的
。
- 所以说,如果我们想在
jquery.ui.js
库里使用$
符号,就需要在这个库里引入jquery
,
image.png -
再刷新页面就没有问题了
image.png - 但是实际是,我们引入的
jquery.ui.js
库它并不是我们自己的业务代码,而是第三方库,是别人写的,所以我们在源码里去加这个jquery
的引用是不现实的。我们刚才之所以能加,是因为我们把文件是写在src
目录下的,而实际情况下,它很可能是一个NPM
包,它是在node_modules
里面的一个目录下,我们不可能去改node_modules
下面的代码的。 - 那么我们这个模块就用不了了吗?我们就是想用这个库应该怎么办呢?这个时候我们就可以借助一个垫片的形式来解决这个问题。
垫片ProvidePlugin
的使用步骤
- 引入
webapck
模块
image.png -
webapck
自己提供了一个插件叫做ProvidePlugin
,我们配置这个插件
image.png - 它的意思是,如果我们的一个模块中使用了
$
这个字符串,它就会在模块里自动的帮我们引入jquery
这个模块。然后把模块的名字叫做$
- 拿我们刚才的
jquery.ui.js
库来说,代码里用到了$
这个字符串,它底层就会帮我们引入jquery
,并且把jquery
赋值给$
这个变量
image.png - 当我们配置这个插件以后,再次打包
npm run dev
,发现,虽然我们没有手动引入jquery
,代码却依然可以正常运行
image.png - 我们把
index.js
里的jquery
引入也删除,依然可以正常运行
image.png
image.png
总结:
如果我们使用了一些版本比较老的第三方的模块,它里边用到了jquery
或者lodash
,而它的用法又不是我们现在ESModules
的使用方式,没有在上边import
。如果我们用webpack
打包使用这样的库的话它会报错的。为了解决这样的错误,我们就可以使用webpack
的一个插件叫做ProvidePlugin
,通过对这个插件的配置来解决我们遇到的问题。这个时候,我们就可以把这个插件理解为一个垫片$
当然这个插件,还有其他的使用方式
- 比如,我们还想用
_
这个符号来代表lodash
,那我们就可以这样配置
image.png - 然后我们就可以直接在
jquery.ui.js
库里用_
符号了
image.png
image.png - 或者是,我们就想用
lodash
的join
方法去拼接字符串,那么可以这样配置,这样就会在遇到_join
字符的时候,自动帮我们引入lodash
的join
方法,打包放入到模块里,同时赋值给_join
字符
image.png
image.png
还有一些垫片
-
比如,当我们在
index.js
里打印this
的时候,这个this
到底指向的是谁呢?
image.png -
我们刷新页面,可以看到,它指向的是一个对象,这个对象里会有一些方法。实际上这个
this
指向的是这个模块自身。
image.png -
但是有的时候,我们希望这个
this
指向的是window
,我们看下现在是否相等
image.png
image.png 我们会发现一个模块里的
this
默认它永远指向的是模块自身,而不是window
这个全局变量
如果我们想让每个JS模块里的this都指向window
这个全局变量,需要借助imports-loader
- 先安装
npm install imports-loader --save-dev
-
我们原来的配置里,只要遇到JS文件,就使用
babel-loader
image.png -
然后我们再对
webpack
做一些配置,因为我们要对JS文件使用多个loader
,所以我们使用use
image.png 配置好以后,如果我们加载一个JS文件的时候,首先会走
imports-loader
,它会把这个JS模块里的this改为指向window,然后再交给babel-loader
做JS文件的编译-
当我们配置好以后,再次打包运行,发现现在模块中的this已经指向了
window
image.png
这种修改webpack
打包中一些默认的行为,或者实现一些webpack
原始打包实现不了的效果,这种行为都叫做shimming
垫片的行为
- shimming这个概念很宽泛,涉及到的东西也很多,根据不同的场景我们再去找不同的解决方法就行了。