shimming(垫片)

在webpack打包的过程中,我们往往要做一些代码上的兼容或者打包过程的兼容;

举例来说,之前我们要使用babel polyfill这样的工具,它解决的问题是,我们打包生成的JS代码运行在低版本浏览器上的时候,有的时候会因为低版本浏览器上不存在promise这类的变量,导致我们的代码没有办法运行,那为了解决打包生成代码过程中这样的问题,我们就要借助babel polyfill这样的工具,在低版本浏览器上自动帮我们去构建一些类似promise这样的全局变量,从而使我们的代码能够在低版本浏览器上运行。

其实这就是一个webpack垫片(shimming),它能够解决webpack打包过程中一些兼容性问题。当然这种加兼容性问题,不局限在浏览器的低版本或高版本的这种兼容性问题上,还有一些其他方面。看下边的例子:

在我们使用webpack的时候,有的时候会出现这样一种情况,比如说我们引入了一个jquery库,假如这个库叫做jquery.ui.js.假如库里的代码是下边这样的
shimming(垫片)_第1张图片
image.png
  • 然后我们在index.js里引入这个库,并且执行,相当于给页面初始化了一个背景色
    shimming(垫片)_第2张图片
    image.png
  • 我们可以看到在jquery.ui.js库里,我们调用了$符号,通过这个符号把body背景色变为绿色,有些人认为这个代码是没有问题的,但是实际上是不会正确的执行的。我们刷新页面可以看到下边报错,说$找不到;
    shimming(垫片)_第3张图片
    image.png
  • 实际上就是jquery.ui.js库里的$符号找不到。这是为什么呢? 明明我们已经在index.js里引入了jquery并赋值给了$变量了啊?

原因很简单,在webpack中,我们是基于模块打包的,模块里的变量,只能在模块这个文件内使用,而换了文件再想使用上一个文件里的变量是不行的。通过这种形式,我们可以保证模块与模块之间不会有任何的耦合。这样出了问题,我们就直接到自己的模块里去找问题就行了,不会因为一个模块而另外一个模块。因为他们的变量是隔离的

  • 所以说,如果我们想在jquery.ui.js库里使用$符号,就需要在这个库里引入jquery
    shimming(垫片)_第4张图片
    image.png
  • 再刷新页面就没有问题了


    shimming(垫片)_第5张图片
    image.png
  • 但是实际是,我们引入的jquery.ui.js库它并不是我们自己的业务代码,而是第三方库,是别人写的,所以我们在源码里去加这个jquery的引用是不现实的。我们刚才之所以能加,是因为我们把文件是写在src目录下的,而实际情况下,它很可能是一个NPM包,它是在node_modules里面的一个目录下,我们不可能去改node_modules下面的代码的。
  • 那么我们这个模块就用不了了吗?我们就是想用这个库应该怎么办呢?这个时候我们就可以借助一个垫片的形式来解决这个问题。
垫片ProvidePlugin的使用步骤
  • 引入webapck模块
    shimming(垫片)_第6张图片
    image.png
  • webapck 自己提供了一个插件叫做ProvidePlugin,我们配置这个插件
    shimming(垫片)_第7张图片
    image.png
  • 它的意思是,如果我们的一个模块中使用了$这个字符串,它就会在模块里自动的帮我们引入jquery这个模块。然后把模块的名字叫做$
  • 拿我们刚才的jquery.ui.js库来说,代码里用到了$这个字符串,它底层就会帮我们引入jquery,并且把jquery赋值给$这个变量
    shimming(垫片)_第8张图片
    image.png
  • 当我们配置这个插件以后,再次打包npm run dev,发现,虽然我们没有手动引入jquery,代码却依然可以正常运行
    shimming(垫片)_第9张图片
    image.png
  • 我们把index.js里的jquery引入也删除,依然可以正常运行
    shimming(垫片)_第10张图片
    image.png

    shimming(垫片)_第11张图片
    image.png
总结:

如果我们使用了一些版本比较老的第三方的模块,它里边用到了jquery或者lodash,而它的用法又不是我们现在ESModules的使用方式,没有在上边import。如果我们用webpack打包使用这样的库的话它会报错的。为了解决这样的错误,我们就可以使用webpack的一个插件叫做ProvidePlugin,通过对这个插件的配置来解决我们遇到的问题。这个时候,我们就可以把这个插件理解为一个垫片$

当然这个插件,还有其他的使用方式
  • 比如,我们还想用_这个符号来代表lodash,那我们就可以这样配置
    shimming(垫片)_第12张图片
    image.png
  • 然后我们就可以直接在jquery.ui.js库里用_符号了
    shimming(垫片)_第13张图片
    image.png

    image.png
  • 或者是,我们就想用lodashjoin方法去拼接字符串,那么可以这样配置,这样就会在遇到_join字符的时候,自动帮我们引入lodashjoin方法,打包放入到模块里,同时赋值给_join字符
    shimming(垫片)_第14张图片
    image.png

    shimming(垫片)_第15张图片
    image.png
shimming(垫片)_第16张图片
image.png
还有一些垫片
  • 比如,当我们在index.js里打印this的时候,这个this到底指向的是谁呢?

    shimming(垫片)_第17张图片
    image.png

  • 我们刷新页面,可以看到,它指向的是一个对象,这个对象里会有一些方法。实际上这个this指向的是这个模块自身。

    shimming(垫片)_第18张图片
    image.png

  • 但是有的时候,我们希望这个this指向的是window,我们看下现在是否相等

    shimming(垫片)_第19张图片
    image.png

    shimming(垫片)_第20张图片
    image.png

  • 我们会发现一个模块里的this默认它永远指向的是模块自身,而不是window这个全局变量

如果我们想让每个JS模块里的this都指向window这个全局变量,需要借助imports-loader
  • 先安装
npm install imports-loader --save-dev
  • 我们原来的配置里,只要遇到JS文件,就使用babel-loader

    shimming(垫片)_第21张图片
    image.png

  • 然后我们再对webpack做一些配置,因为我们要对JS文件使用多个loader,所以我们使用use

    shimming(垫片)_第22张图片
    image.png

  • 配置好以后,如果我们加载一个JS文件的时候,首先会走imports-loader,它会把这个JS模块里的this改为指向window,然后再交给babel-loader做JS文件的编译

  • 当我们配置好以后,再次打包运行,发现现在模块中的this已经指向了window

    shimming(垫片)_第23张图片
    image.png

这种修改webpack打包中一些默认的行为,或者实现一些webpack原始打包实现不了的效果,这种行为都叫做shimming垫片的行为
  • shimming这个概念很宽泛,涉及到的东西也很多,根据不同的场景我们再去找不同的解决方法就行了。

你可能感兴趣的:(shimming(垫片))