babel-polyfill

babel-polyfill在Babel7以后名字是@babel/polyfill。在引入polyfill一节,我们学习了polyfill的入门知识,在本节将会深入讲解。

本节配套代码是github仓库 https://github.com/jruit/babel-tutorial 的babel03-babel08例子

polyfill广义上讲是为环境提供不支持的特性的一类文件或库,既有Babel官方的库,也有第三方的。babel-polyfill指的是Babel官方的polyfill,本教程默认使用babel-polyfill。polyfill传统上分两类,一类是已构建成JS文件的polyfill.js,另一类是未构建的需要安装npm包@babel/polyfill。因为@babel/polyfill本质是由两个npm包core-js与regenerator-runtime组合而成的,所以在使用层面上还可以再细分为是引入@babel/polyfill本身还是其组合子包。

总体来说,Babel官方的polyfill使用方法主要有如下几种:

  1. 直接在html文件引入Babel官方的polyfill.js脚本文件;
  2. 在前端工程的入口文件里引入polyfill.js;
  3. 在前端工程的入口文件里引入@babel/polyfill;
  4. 在前端工程的入口文件里引入core-js/stable与regenerator-runtime/runtime;
  5. 在前端工程构建工具的配置文件入口项引入polyfill.js;
  6. 在前端工程构建工具的配置文件入口项引入@babel/polyfill;
  7. 在前端工程构建工具的配置文件入口项引入core-js/stable与regenerator-runtime/runtime;

所有的例子,我们仍以火狐27.0不支持的Promise为例,进行演示。该版本的火狐,在遇到如下代码的时会报错

  var promise = Promise.resolve('ok');
  console.log(promise);

报错信息为:ReferenceError: Promise is not defined

我们需要做的就是让火狐27.0可以正常运行我们的代码,下面对上文提到的7种方法进行讲解。

1. 直接在html文件引入Babel官方的polyfill.js脚本文件

该方法在分类上属于使用已构建成JS文件polyfill.js的一类,该方法在引入polyfill一节已经讲过,本节不再重复讲解。

2. 在前端工程的入口文件里引入polyfill.js

github配套的代码是babel03例子

该方法在分类上属于使用已构建成JS文件polyfill.js的一类,该我们以目前业界最为流行的webpack打包工具为例,讲述该方法。

我们的工程里有a.js与index.html文件,a.js文件的内容是

  var promise = Promise.resolve('ok');
  console.log(promise);

index.html文件在head标签里直接引入了a.js文件,这个时候在火狐27.0下打开该html会报错。

在之前的例子里,我们是在index.html里单独引入了polyfill.js文件对API进行补齐。现在,我们换一种方式,通过在工程入口文件a.js引入polyfill.js进行补齐。

我们使用webpack来讲述这个过程,首先进行webpack和其命令行工具的安装

  npm install webpack webpack-cli --save-dev

在webpack4.0和node8.2以上版本,我们可以使用npx webpack a.js -o b.js命令来进行打包。该命令的意思是,指定工程入口文件是a.js,最后打包成b.js。

为了方便,我们在package.json里配置scripts项,现在,只需要执行npm run dev,就会自动执行npx webpack a.js -o b.js命令,即可完成打包。

  "scripts": {
    "dev": "npx webpack a.js -o b.js"
  },

在我们这个例子里,前端工程入口文件是a.js,我们只需要在a.js最上方加入一句

  import './polyfill.js';
babel-polyfill Babel教程

然后执行npm run dev,就可以把polyfill打包到我们的最终生成的文件里(我们需要提前在相应的文件目录里存放polyfill.js)。

现在,我们把index.html使用的a.js改成b.js,然后在火狐27.0打开,可以看到控制台已经正常。

3. 在前端工程的入口文件里引入@babel/polyfill

配套代码是babel04例子。

该方法在分类上属于使用未构建的需要安装npm包@babel/polyfill的一类,其实整个过程和上面的例子非常像,不一样的地方如下。

1) a.js里的

  import './polyfill.js';

改成

  import '@babel/polyfill';

2)删除工程目录下的polyfill.js文件,同时安装@babel/polyfill这个npm包

  npm install --save @babel/polyfill

除了这两点,其余的地方和上面的例子完全。

执行npm run dev,然后和之前一样在火狐打开进行验证正常。

4. 在前端工程的入口文件里引入core-js/stable与regenerator-runtime/runtime

配套代码是babel05例子。

该方法在分类上属于使用未构建的需要安装npm包@babel/polyfill的组合子包的一类,我们仍以目前业界最为流行的webpack构建工具为例,讲述该方法。后续默认是使用webpack。

该方法需要我们单独安装单独安装core-js与regenerator-runtime这两个npm包,这种方式core-js是默认是3.x.x版本。
需要注意的是,我们使用该方法的时候,不能再安装@babel/polyfill了。因为@babel/polyfill在安装的时候,会自动把core-js与regenerator-runtime这两个依赖安装上了,而@babel/polyfill使用的core-js已经锁死为2.x.x版本了。core-js的2.x.x版本里并没有stable文件目录,所以安装@babel/polyfill后再引入core-js/stable会报错。

其实这个方法和上面的例子也是非常像,就是把一个npm包换成了两个而已。不一样的地方具体如下

1) a.js里的

  import '@babel/polyfill';

改成

  import "core-js/stable";
  import "regenerator-runtime/runtime";

2)安装两个npm包core-js和regenerator-runtime

  npm install --save core-js regenerator-runtime

替换之前安装的@babel/polyfill

执行npm run dev,然后和之前一样在火狐打开进行验证正常。

5. 在前端工程构建工具的配置文件入口项引入polyfill.js

配套代码是babel06例子。

webpack的配置文件有多种类型,我们采用webpack.config.js,其它类型的webpack配置文件与其一致。

因为要在webpack配置文件里指定入口文件,我们就不手动使用webpack a.js -o b.js来进行打包了,而是在webpack.config.js进行设置。

  const path = require('path');

  module.exports = {
    entry: ['./a.js'],
    output: {
      filename: 'b.js',
      path: path.resolve(__dirname, '')
    },
    mode: 'development'
  };

webpack的配置文件的入口项是entry,这里entry的值我们设置成数组,a.js就是入口文件。然后,package.json里的dev命令改为

  "scripts": {
    "dev": "npx webpack"
  },

现在我们执行npm run dev,webpack就完成了打包。现在我们index.html直接引用b.js,火狐27会报错。原因我们都知道,我们没有使用polyfill。

那么,在前端工程构建工具的配置文件入口项引入polyfill.js,该怎么操作呢?

其实很简单,那就是把数组的第一项改成'./polyfill.js',原先的入口文件作为数组的第二项,polyfill就会打包到我们生成后的文件里了。

  const path = require('path');

  module.exports = {
    entry: ['./polyfill.js', './a.js'],
    output: {
      filename: 'b.js',
      path: path.resolve(__dirname, '')
    },
    mode: 'development'
  };

现在再执行npm run dev进行打包,然后index.html就不会在火狐27里报错了。

6. 在前端工程构建工具的配置文件入口里引入@babel/polyfill;

配套代码是github上的babel07例子。

如果你对之前讲的方法都理解的话,那么相信你也会很容易理解该方法。该方法就是把上个方法的entry的第一项换成@babel/polyfill,并且安装了@babel/polyfill这个包就可以了。

  npm install --save @babel/polyfill

webpack.config.js配置如下

  const path = require('path');

  module.exports = {
    entry: ['@babel/polyfill', './a.js'],
    output: {
      filename: 'b.js',
      path: path.resolve(__dirname, '')
    },
    mode: 'development'
  };

现在再执行npm run dev进行打包,然后index.html就不会在火狐27里报错了。

7. 在前端工程构建工具的配置文件入口里引入core-js/stable与regenerator-runtime/runtime

配套代码是github上的babel08例子。

其实这个方法和上面的例子也是非常像,就是把一个npm包换成了两个而已。我们需要做的就是安装两个npm包

  npm install --save core-js regenerator-runtime

然后webpack.config.js的entry项数组的前两项改为core-js/stable和regenerator-runtime/runtime。

  const path = require('path');

  module.exports = {
    entry: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
    output: {
      filename: 'b.js',
      path: path.resolve(__dirname, '')
    },
    mode: 'development'
  };

现在再执行npm run dev进行打包,然后index.html就可以正常在火狐27.0运行了。

从babel7.4开始,官方不推荐再使用@babel/polyfill了,因为@babel/polyfill本身其实就是两个npm包的集合:core-js与regenerator-runtime。

官方推荐直接使用这两个npm包。虽然@babel/polyfill还在进行版本升级,但其使用的core-js包为2.x.x版本,而core-js这个包本身已经发布到了3.x.x版本了,@babel/polyfill以后也不会使用3.x.x版本的包了。新版本的core-js实现了许多新的功能,例如数组的includes方法。

虽然从babel7.4开始,不推荐再使用@babel/polyfill了,但我们仍然把传统@babel/polyfill的使用方式在本节进行讲解,这对于理解其使用方式是非常有帮助的。

ES6补齐API的方式,除了上述几种在前端工程入口文件或构建工具的配置文件里使用polyfill(或是其子包)的方式,还有使用Babel预设或插件进行补齐API的方式。
上述使用polyfill的方式,是把整个npm包或polyfill.js放到了我们最终的项目里了。完整的polyfill文件非常大,会影响我们的页面加载时间。
如果我们的运行环境已经实现了部分ES6的功能,那实在没有必要把整个polyfill都给引入。我们可以部分引入,这个时候需要使用Babel预设或插件了。

Babel预设或插件不光可以进行补齐API,还可以对API进行转换,这些使用方法在后面两节讲解。

小结

1.本节对使用polyfill进行了详细的梳理与讲解,把每一种使用方法都进行了讲述,并配有代码以便大家理解。
2.这么多的方法,在实际开发中该选择哪一种呢?从babel7.4版本开始,Babel官方已经不推荐再使用@babel/polyfill,这也包括官方的polyfill.js库文件。因此从2019年年中开始,我们的新项目都应该使用core-js和regenerator-runtime这两个包。即,我们应选择方法4与方法7。这两种方法,都是把两个npm包全部都引入到了我们的前端打包后的文件里了,对于部分引入的方法,我们将在后面两节进行讲解。

1.polyfill这个名词,现在有多种含义。可以是指polyfill.js,也可以是babel-polyfill,也可以是@babel/polyfill,也可以是core-js和regenerator-runtime等等。我们应该根据语境来理解其具体指代。总体来说,提到polyfill这个词,一般就是指我们开发过程需要对环境的缺失API特性提供支持。

笔记与思考

  1. babel-polyfill在Babel7以后名子是@babel/polyfill。
    这里有个错别字,名子->名字,谢谢作者的付出!

  2. 受教了,插件的历史变更竟能讲的如此清楚,真的是用心在写文章啊,受教了,可以像廖老师那样贴一张收款码,精美的文章就像良心的开源产品一样,创作不易,值得支持

  3. 作者的文章很用心 我每篇都认真看了 这里反馈个错别字(本来我认为错别在所难免的 在使用输入法时常常出现 但上面有人指明了 所以我也就指出来 希望作者的文章越来越好)
    小结中 “2019年年中开始”后面 我就的-->我觉得

  4. 意外发现的这个宝藏网站,真的真的太赞了,每篇文章都想非常赞,感觉就是站在小白我的角度在答疑解惑,太感谢了,大牛很多,能讲的这么详细且易懂的大牛很少👍

  5. 疑问,文中说:“从babel7.4开始,官方不推荐再使用@babel/polyfill了”。问,babel 的版本 具体指的是哪个包?babel 一般大家安装的三剑客就是:@babel/cli、@babel/core、@babel/preset-env。说的 v7.4 是指哪个版本,有点懵。希望博主给解释一下。

  6. 太感谢了,这一节竟然还学习到了一个关于webpack的知识点。
    entry属性如果是一个字符串数组,那么还依旧属于是`单入口打包`,这样的目的是没必要在代码里显式地引入polyfill了,webpack会帮助打包且打包后的代码里,polyfill放置到最上面,方便了很多。

  7. 这个火狐27.0.1 下载后,在mac M2 上安装完打开不能用,有朋友遇到类似问题吗?还有其他可以测试低版本的浏览器版本推荐吗?
    谢谢答疑

发表评论

邮箱地址不会被公开。 必填项已用*标注