【快速理解】webpack中的shimming预置全局变量

相信很多人很难一下子理解官方文档的这段话:
官方介绍:webpack compiler 能够识别遵循 ES2015 模块语法、CommonJS 或 AMD 规范编写的模块。但一些第三方库(或者老代码)可能会引用一些全局依赖(如 jQuery 中的全局变量 $,即第三方库里没有导入 ,但把 ,但把 ,但把当成全局变量使用)。这些依赖也可能会创建一些需要导出的全局变量。这些 “broken modules(不符合规范的模块)” 就是 shimming(预置依赖) 发挥作用的地方。
本文尝试用大白话解释一下webpack里的shimming,shim意思是硬垫片,那就跟兼容有关系了(polyfill是软垫片)

使用场景:

有一些旧的库或代码,可能会多处使用某个全局变量,如使用jquery的全局变量$,这样就要求:全局变量$需要提前在浏览器通过script标签引入,否则可能会报错(webpack解决的痛点之一)。

shimming就是用来兼容这些旧的库的,让webpack也能对它们进行打包。打包时,把使用全局变量的方式,改为模块引入的方式。例如,把$认为是一个模块,而不是全局变量。

原理非常简单:
打包时,在旧的库里,插入导入该全局变量对应的模块的语句。本质就是给旧的库实现自动导入指定模块。注意:要同时安装该全局变量对应的模块化版本。

效果:
这样一些旧代码或者库,即使是以全局变量的方式使用某个库,也可以直接复制过来使用,同时无需修改旧代码,webpack帮你实现导入,把对旧代码的侵入性降到最低。

使用全局变量,和使用模块化二者在代码里主要区别是:有没有提前导入声明。模块化方式会在顶部导入再使用;全局变量方式会直接在代码里使用,没有导入语句。二者的其余代码可以一模一样。

配置:

// webpack.config.js
// 首先记得安装依赖:npm i jquery lodash -S
const webpack = require('webpack');
module.exports = {
    plugins: [
        new webpack.ProvidePlugin({
            // 注意
            // 并不是全局创建myLodash、$变量,而是识别业务代码里的这两个变量。
            // 并在使用了myLodash、$变量的js文件里,自动导入对应的'lodash'、'jquery'模块
            myLodash: 'lodash',
            $: 'jquery'
        })
    ],
}

// index.js
// 这样就可以在任意代码里使用 myLodash、$ 变量,无需提前导入
// 也就是可以直接把旧代码复制过来使用
myLodash.join(['hellow','hi'], ' ');
$('div')

细颗粒度shimming–更多自定义配置

上面实现shimming的webpack.ProvidePlugin插件,虽然可以实现把多个全局变量,改造成模块导入的方式使用(逻辑代码里像一个全局变量那样使用该依赖),但是webpack会改变被打包的库的一级作用域,如this字面量不再是window,而可能是module.exports。

而一些旧代码不仅使用全局变量,也会默认一级作用域下的this指向window。而经过webpack打包后,特别是经过转为 CommonJS 后,这个this会指向module.exports。

为了能自动导入依赖的同时,还能修改一级作用域下this指向,就需要使用imports-loader来实现:

更多imports-loader功能实现请查阅webpack文档

  1. 安装loader:npm install imports-loader -D

  2. 对需要特殊处理的模块配置该loader即可

    // webpack.config.js
    module.exports = {
      module: {
        rules: [
          {
            // example.js这里可以是第三方库:使用了全局变量$,还使用this当window使用
            test: require.resolve('example.js'),
            use: [
              {
                loader: 'imports-loader',
                options: {
                  imports: {
                    // 给example.js导入jquery模块,命名为$
                    moduleName: 'jquery',
                    name: '$',
                  },
                  // 把this指向window
                  wrapper: 'window',
                },
              },
            ],
          },
        ],
      },
    };
    
    // example.js的全部代码Code,会被imports-loader转为:
    import $ from 'jquery';
    
    (function () {
      // ...
      // Code
      // ...
    }.call(window));
    

自动全局导出

既然webpack可以实现自动导入,那么就会有自动导出。

全局exports就是帮你自动把旧代码的一级作用域下的变量导出,通过exports-loader来实现:

  1. 安装`npm install exports-loader --save-dev

  2. 使用

    // 方式一:内联式,无需配置webpack
    // index.js
    import { addAlias } from 'exports-loader?type=commonjs&exports=multiple|funs.add|addAlias!./normal.js';
    // normal.js 会被插入module.exports = {"addAlias": funs.add}
    // type取值为commonjs,exports只能是multiple(默认)、single
    
    // type的取值默认为module,即es6,对应的exports的值只能是named(默认)、defalult
    // import {num} from 'exports-loader?exports=named|num!./normal.js' =》export {num}
    
    // 方式二:配置loader
    module.exports = {
      module: {
        rules: [
          {
            test: require.resolve('./normal.js'),
            loader: 'exports-loader',
            options: {
              type: 'commonjs',
              exports: 'multiple funs.add addAlias',
            },
          },
        ],
      },
    };
    // index.js
    import { addAlias } from './normal.js';
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值