美文网首页
如何使用Babel实现polyfill

如何使用Babel实现polyfill

作者: 刷题刷到手抽筋 | 来源:发表于2022-05-22 09:17 被阅读0次

babel是什么

babel官方文档中对babel有明确的定义:

Babel 是一个 JavaScript 编译器

Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

当然babel已不仅仅用于转换ECMAScript 2015+ ,例如它还可以转换typescript、flow。

babel做的工作是

  1. 将源代码解析为AST

  2. 更改/转换AST

  3. 打印AST(转换为源代码)

插件和preset

babel 本身不具有任何转化功能,它把转化的功能都分解到一个个 plugin 里面。因此当我们不配置任何插件时,经过 babel 的代码和输入是相同的。

插件

插件分两种:

  • 语法插件
  • 转换插件

前端面试刷题网站灵题库,收集大厂面试真题,相关知识点详细解析。】

前面已经提到,babel的插件实际做的工作是

  1. 将源代码解析为AST

  2. 更改/转换AST

  3. 打印AST(转换为源代码)

语法插件做的工作就是第1步,将源代码解析为AST,而转换插件则是3步都要进行。因此如果已经配置了转换插件,就不需要再额外配置相应的语法插件。这一点官方文档中也有说明:

转换插件将启用相应的语法插件,因此你不必同时指定这两种插件。

预设

因为通常我们在项目中使用es2015代码转换或者react语法转换,会用到多个插件,如果一个一个配置,繁琐而且容易出错。预设就是用来解决这个问题的。

Babel 的预设(preset)可以被看作是一组 Babel 插件和/或 options 配置的可共享模块。\

常用的preset:preset-env,用来转换es2015,preset-react,用来转换jsx等,preset-typescript

插件和预设的执行顺序

如果两个转换插件都将处理“程序(Program)”的某个代码片段,则将根据转换插件或 preset 的排列顺序依次执行。

• 插件在 Presets 前运行。

• 插件顺序从前往后排列。

• Preset 顺序是颠倒的(从后往前)。

babel的使用

官方文档-使用指南

babel主要有3种使用方法

  1. 命令行
  2. node API
  3. babel-loader

命令行

npm install --save-dev @babel/core @babel/cli @babel/preset-env

注:babel7中的核心逻辑被抽离到@babel/core中,因此使用babel必须安装babel/core

{
  "presets": [
    "@babel/preset-env"
  ]
}

使用babel命令行工具进行代码转换

./node_modules/.bin/babel src --out-dir lib

node API

npm install --save-dev @babel/core
const babel = require("@babel/core");

babel.transformSync("code", optionsObject);

集成(babel-loader)

{
  // ...other config
  module: {
    rules: [
      {
        test: /.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
}

可以在.babelrcpackage.jsonbabel-loaderoption中配置插件和preset.

推荐.babelrc

使用babel进行polyfill

babel的一些插件和预设可以转换新语法特性(如箭头函数),而内建的变量(如Promise、Symbol)却无法兼容。

为了兼容内建变量,需要用到polyfill的技术。

polyfill技术就是用兼容语法(ES5)实现新的内建变量、扩展内建变量的静态属性(Array.from)和实例属性([].includes)。

polyfill库

最流行的polyfill库有两个:core-jsregenerator

core-js

zloirock/core-js,它提供了 ES5、ES6 的 polyfills,包括 promise 、symbols、collections、iterators、typed arrays、ECMAScript 7+ proposals、setImmediate 等等。

regenerator

facebook/regenerator,它实现 ES6/ES7 中 generators、yield、async 及 await 等相关的语法。

babel-polyfill

babel-polyfill做的事情就是引入了core-jsregenerator,使用的时候直接import,如果使用webpack打包,直接在入口entry中引入即可。

在babel@7.4.0以后已经不推荐,可以直接引入core-jsregenerator代替。

@babel/runtime

同样是引入了core-jsregenerator,以支持polyfill的能力。

除了支持polyfill能力,@babel/runtime还提供了运行时代码复用的能力,后面会提到。

在之前的版本中都是直接引用所有的polyfill到项目中,这样有两个问题

  1. 体积过大,有些浏览器版本已经支持一些新的内建的对象和属性,不需要polyfill;项目中也不是每个polyfill的特性都用到,引用所有的polyfill会造成很大的冗余。
  2. 污染全局变量,polyfill方法是创建全局的变量以支持内建变量,给内建变量添加静态方法或者实例属性,这样会污染到全局变量。

preset-env

preset-env支持通过设置useBuildIn选项来控制polyfill的体积。

该选项有以下几个可选值

false

这是默认的值,选择该值,preset-env不做操作,需要手动引入polyfil(babel-polyfill或者core-js + regenerator

entry

需要手动引polyfill,preset-env会根据browserslist改写引用polyfill的语句(包括babel-polyfillcore-jsregenerator),引入必要的polyfill,而不会安装环境中已经支持的特性,从而达到缩减包体积的目的。

例如我们项目中手动引入了core-js

import "core-js";

preset-env会转换为

// 根据browserslist判断,只引入环境中不支持的特性
import "core-js/modules/es.string.pad-start";
import "core-js/modules/es.string.pad-end";

usage

使用该值,不需要手动引入polyfill,preset-env会自动给用到某个特性的文件添加polyfill的引入,这样就实现了按需加载。

babel-plugin-transform-runtime

插件功能

这个插件有两个功能

  • 让所有用到babel的runtime的文件,只引用一份运行时,就是@babel/runtime。

  • 自动引入core-js和regenerater,并给core-js和@babel/polyfill的内置(如Promise、Map、Set)命名别名,这样可以避免污染全局变量。

下面两种配置都可以支持按需加载,也都能支持实例属性。

第一种配置会污染全局,第二种不会。

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}
{
  "presets": [
    [
      "@babel/preset-env"
    ]
  ],
  "plugins": [
    ["@babel/plugin-transform-runtime", {
      "corejs": 3
    }]
  ]
}

core-js2只支持全局变量和静态属性,而core-js3已经可以支持实例属性。

babel corejs@3 是如何按需polyfill原型对象方法的

注意事项

  1. core-js3之前,如果需要实例属性的polyfill,只能用污染全局的方式。
  2. 使用@babel/plugin-transform-runtime + corejs@3,需要安装@babel/runtime-corejs3https://www.babeljs.cn/docs/babel-plugin-transform-runtime#corejs
  3. babel-plugin-transform-runtime依赖@babel/runtime,插件是dev安装,runtime要生产环境安装:https://www.babeljs.cn/docs/babel-plugin-transform-runtime#installation

参考文章

一口(很长的)气了解 Babel

Babel polyfill 知多少

Babel官网

babel corejs@3 是如何按需polyfill原型对象方法的

相关文章

网友评论

      本文标题:如何使用Babel实现polyfill

      本文链接:https://www.haomeiwen.com/subject/irwpurtx.html