Skip to content

Babel 总结 #15

@winnieBear

Description

@winnieBear

Babel

ECMAScript 的变化

ECMAScript Current Proposals

  • stage0 只是一个美好激进的想法,有 Babel 插件实现了对这些特性的支持,但是不确定是否会被定为标准;
  • stage1 值得被纳入标准的特性;
  • stage2 该特性规范已经被起草,将会被纳入标准里;
  • stage3 该特性规范已经定稿,各大浏览器厂商和 Node.js 社区开始着手实现;
  • stage4 在接下来的一年将会加入到标准里去。

stageX

Babel的作用

  • 想在代码中使用新的js语法提议,例如async/await
  • 添加对新的框架语法的支持,例如jsx
  • 添加对新的语言支持,例如Flow and TypeScript

ES特性分类

分为三种

  • 最新ES 语法:比如,let, const, 箭头函数,import,解构赋值,对象属性展开,class, jsx, flow 等等
  • 最新ES API:,比如,Promise,Aync/await等等
  • 最新ES 实例方法:比如,String.protorype.includes

Babel处理方法

  1. 对于上述第1种新的ES语法,Babel通过plugin的方式进行转换,把新的语法转换成为ES5支持的语法,例如transform-es2015-arrow-functions
  2. 对于上述2,3种特性,Babel通过添加polyfills进行兼容

插件列表

Babel 插件列表

Babel工作原理

Babel 的三个主要处理步骤分别是:

解析(parse),转换(transform),生成(generate)。

Babel工作原理过程

Babel变化

  • Babel7 不再建议使用stage-x presets,而是根据你配置的目标环境的兼容情况来加载相应的plugins
    各 stage 的插件

  • Babel7 配置的语法也发生变化,包的名字和插件名字都变化了

Babel配置的语法

{
    "presets": [//数组
        "presetA", // 字符串
        ["presetA"], // 数组包裹的字符串
        ["presetA", {}]// 数组,第一项是字符串,第二项是个对象,对象里面配置各种属性
    ],
    "plugins": [
        "plugin-A",
        ["plugin-A"],
        ["plugin-A", {}]
  ]
}




  • 执行的顺序
    plugins是先于presets之前执行
  • 配置项的执行顺序
    presets 的执行顺序是倒序,最后一个先执行,最后执行的是第一个
    而plugins的执行顺序是顺序,按照配置的顺序依次执行
// presets执行顺序:倒序,下面的preset的执行属性是c,b,a
{ "presets":
    [
        "a",
        "b",
        "c"
    ]
}

// plugins是顺序执行,依次执行array-includes,transform-class-properties,transform-decorators-legacy
{
    "plugins": [
        "array-includes",
        "transform-class-properties",
        "transform-decorators-legacy"
    ]

}

Babel的使用方法

  1. 自己根据代码用到的语法,自己添加相应的polyfill和配置需要的plugins
  2. 使用presets

presets

  1. 如果没有配置presets和plugins,babel是如何选择哪些插件进行处理?
    如果没有配置presets,babel什么也不转换

  2. babel推荐使用preset-env,属性说明

targets 属性

preset-env 根据配置的targets属性,就是目标浏览器,加载需要的插件;如果没配置targes属性,默认会加载ES2015,ES2016,ES2017 需要的插件;

即使配置了targets属性,babel不会根据你代码中用到了哪些新语法而加载相应的插件,而是根据你的preset配置来加载需要的插件;如果没有配置targets属性,但是package.json配置了browserslist,会把这个属性作为targets来使用。

useBuiltIns属性(Babel7才支持下面前2中属性)

  • useBuiltIns: 'entry' 导致引用了太多不需要的polyfill,因为是根据targets来决定来引用哪些polyfill

需要在入口文件中直接添加对 @babel/polyfill的引用,注意只能导入一次;例如

import "@babel/polyfill";
// 或
require("@babel/polyfill")

// 或在webpack的entry配置里添加

module.exports = {
  entry: ["@babel/polyfill", "./app/js"],
};

babel根据target来替换成对应的polyfill同时把@babel/polyfill 添加到项目的依赖中,例如

npm install @babel/polyfill --save
  • useBuiltIns: 'usage' 按需引用需要的polyfill,不需要在入口文件中添加引用,但依然需要把@babel/polyfill 添加到项目的依赖中

根据文件中使用情况,添加相应的polyfill

  • useBuiltIns: false
    不会自动添加polyfill

polyfill

Babel7 如果不设置useBuiltIns属性,babel转换时不会自动插入需要的polyfill,例如promise等,因此需要自己在代码中自行引入。
当运行环境中不支持一些方法时,babel-polyfill 会给其做兼容。 但是这样做也有一个缺点,就是会污染全局变量,而且项目打包以后体积会增大很多,当不使用useBuiltIns: 'usage'属性时,会把整个依赖包也打了进去。所以并不推荐在一些方法类库中去使用。

Babel-plugin-transform-runtime 与Babel-runtime

  • Babel在转换代码时,有时候会在全局polyfill一些方法,例如,array.prototype.includs,Promise等
  • 会添加一些附加的方法,例如asyncGeneratorStep, _asyncToGenerator, _createClass,_defineProperty 等等,每一个被转换的文件中都会根据需要添加对应的辅助方法

基于以上,一方面为了开发一个lib时不污染全局变量,另一方面为了减少由于辅助代码带来的冗余代码,有了Babel-runtime

runtime的使用方法

  1. 需要添加项目依赖babel-runtime
npm install --save @babel/runtime

  1. 添加dev依赖babel-plugin-transform-runtime,作为babel的一个插件使用
npm install --save-dev @babel/plugin-transform-runtime

注意: babel-runtime 不会转码实例方法,比如这样的代码,

'!!!'.repeat(3);
'hello'.includes('h');

只会通过添加相应的polyfill来处理

webpack使用

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions