前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >4-11 shimming 的作用

4-11 shimming 的作用

作者头像
love丁酥酥
发布2020-03-23 14:31:43
7560
发布2020-03-23 14:31:43
举报
文章被收录于专栏:coding for lovecoding for love

1. 简介

webpack 编译器(compiler)能够识别遵循 ES2015 模块语法、CommonJS 或 AMD 规范编写的模块。然而,一些第三方的库(library)可能会引用一些全局依赖(例如 jQuery 中的 $)。这些库也可能创建一些需要被导出的全局变量。这些“不符合规范的模块”就是 shimming 发挥作用的地方。 shimming 另外一个使用场景就是,当你希望 polyfill 浏览器功能以支持更多用户时。在这种情况下,你可能只想要将这些 polyfills 提供给到需要修补(patch)的浏览器(也就是实现按需加载)。

2. 处理遗留模块

这块以前比较多见,但随着各个库的规范升级,现在用的比较少了。我们来看一下。

2.1 shimming 全局变量

我们来看一个简单的例子:

代码语言:javascript
复制
// index.js
import { ui } from './ui';

ui();
代码语言:javascript
复制
// ui.js
import $ from 'jquery';

export function ui() {
    $('body').css('background', 'green');
}

我们使用一个 ui 库,提供了一个方法 ui,依赖 jquery 实现。打包后,打开页面:

image.png

可以看到正常输出。 现在我们试着调整 ui, 去掉对 jquery 的引用,在 index 将其引入会如何呢?

代码语言:javascript
复制
// index.js
import $ from 'jquery';
import { ui } from './ui';

ui();
代码语言:javascript
复制
// ui.js

export function ui() {
    $('body').css('background', 'green');
}

打包:

image.png

发现即使在入口 index 引入 jquery,但是 ui 找不到该变量,这还是因为模块引入变量的作用范围是模块内,正确的用法是哪里使用,就在哪里引用(虽然webpack 底层只会对相同模块加载一次,但是引用标识必须是多次的)。可是对一些老的三方库,并没有引用 jquery,怎么办呢,他们默认 jquery 是全局变量可以直接引用。

要解决这个问题,我们把 jquery 作为我们应用程序中的一个全局变量就可以了。要实现这些,我们需要使用 ProvidePlugin 插件。

使用 ProvidePlugin 后,能够在通过 webpack 编译的每个模块中,通过访问一个变量来获取到 package 包。如果 webpack 知道这个变量在某个模块中被使用了,那么 webpack 将在最终 bundle 中引入我们给定的 package。 我们恢复 index.js, 然后修改 webpack.common.js

代码语言:javascript
复制
    plugins: [
        ...
        new webpack.ProvidePlugin({
            $: 'jquery'
        })
    ],

打包,

image.png

本质上,我们所做的,就是告诉 webpack,如果你遇到了至少一处用到 lodash 变量的模块实例,那请你将 lodash package 包引入进来,并将其提供给需要用到它的模块。 我们还可以使用 ProvidePlugin 暴露某个模块中单个导出值,只需通过一个“数组路径”进行配置(例如 [module, child, ...children?]) 如下:

代码语言:javascript
复制
    plugins: [
        ...
        new webpack.ProvidePlugin({
            $: 'jquery',
            _join: ['lodash', 'join']
        })
    ],

告诉我们如果用到_join 的地方,实际上是使用 lodash.join 方法。

代码语言:javascript
复制
// ui.js

export function ui() {
    $('body').css('background', _join(['dark', 'green'], ''));
}

打包后如下:

image.png

这样就能很好的与 tree shaking 配合,将 lodash 库中的其他没用到的部分去除。

2.2 细粒度 shimming

一些传统的模块依赖的 this 指向的是 window 对象。我们来看一下 webpack 模块中打印 this 指向哪里:

代码语言:javascript
复制
// index.js
console.log(this);
this.alert('hi');

image.png

本来模块设想运行在 window 下,如果当模块运行在 CommonJS 环境下这将会变成一个问题,也就是说此时的 this 指向的是 module.exports。在这个例子中,可以通过使用 imports-loader 覆写 this

代码语言:javascript
复制
rules: [
            ...
            {
                test: require.resolve('../src/index.js'),
                use: 'imports-loader?this=>window'
            }
        ]

安装 imports-loader, 然后打包后如下:

image.png

2.3 全局 exports

让我们假设,某个库(library)创建出一个全局变量,它期望用户使用这个变量。

代码语言:javascript
复制
// index.js
import { file, parse } from './global.js';

console.log(file);
parse();
代码语言:javascript
复制
// global.js
const file = 'blah.txt';
const helpers = {
    test: function() { console.log('test something'); },
    parse: function() { console.log('parse something'); }
}

你可能从来没有在自己的源码中做过这些事情,但是你也许遇到过一个老旧的库(library),和上面所展示的代码类似。在这个用例中,我们可以使用 exports-loader,将一个全局变量作为一个普通的模块来导出。例如,为了将 file 导出为 file 以及将 helpers.parse 导出为 parse,做如下调整:

代码语言:javascript
复制
rules: [
            ...
            {
                test: require.resolve('../src/global.js'),
                use: 'exports-loader?file,parse=helpers.parse'
            }
        ]

打包后:

image.png

3. polyfills

除了处理那些遗留的 package 包,shimming 的另一个作用就是处理 polyfills。有很多方法来载入 polyfills。例如,要引入 babel-polyfill 我们只需要如下操作:

代码语言:javascript
复制
npm install --save babel-polyfill
代码语言:javascript
复制
// index.js
import 'babel-polyfill';

请注意,我们没有将 import 绑定到变量。这是因为只需在基础代码(code base)之外,再额外执行 polyfills,这样我们就可以假定代码中已经具有某些原生功能。 让我们把 import 放入一个新文件,并加入 whatwg-fetch polyfill:

代码语言:javascript
复制
npm install --save whatwg-fetch
代码语言:javascript
复制
// pollyfills.js
import 'babel-polyfill';
import 'whatwg-fetch';

配置修改如下:

代码语言:javascript
复制
    entry: {
        polyfills: './src/polyfills.js',
            index: "./src/index.js"
    },
    output: {
        path: path.resolve(__dirname, '../dist'),
        filename: "[name].bundle.js",
    },

打包后正常运行:

image.png

当我们开始执行构建时,polyfills.bundle.js 文件将会被载入到浏览器中,然后所有代码将正确无误的在浏览器中执行。请注意,以上的这些设定可能还会有所改进,我们只是对于如何解决「将 polyfills 提供给那些需要引入它的用户」这个问题,向你提供一个很棒的想法。

4. 小结

shimming 说到底视为了解决兼容问题,对旧的库或者浏览器进行兼容。shim 是一个库(library),它将一个新的 API 引入到一个旧的环境中,而且仅靠旧的环境中已有的手段实现。polyfill 就是一个用在浏览器 API 上的 shim。我们通常的做法是先检查当前浏览器是否支持某个 API,如果不支持的话就加载对应的 polyfill。然后新旧浏览器就都可以使用这个 API 了。

参考

https://www.webpackjs.com/guides/shimming/ https://webpack.js.org/guides/shimming/

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 简介
  • 2. 处理遗留模块
    • 2.1 shimming 全局变量
      • 2.2 细粒度 shimming
        • 2.3 全局 exports
        • 3. polyfills
        • 4. 小结
        • 参考
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档