Babel基础

# 【第一篇:Babel】

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

  • 语法转换
  • 通过Polyfill方式在目标环境中添加缺失的特性(通过@babel/polyfill模块)
  • 源码转换(codemods)

通俗来讲,Babel就是一个工具集,主要是将高版本的代码转换成浏览器或其他环境能够识别运行的代码;

1. Babel的使用方式

Babel总共有三种使用方式:

  • 使用单体文件(standalone script)

    
    
    
    
  • 命令行(cli)

  • 构建工具的插件(如:webpack的babel-loader,rollup的rollup-plugin-babel等)

其中后面两种比较常见,第二种多见于在package.json中的scripts对象下添加某条命令;第三种就直接集成到构建工具中,如webpack等。

但是这三种方式只有入口不同而已,调用的babel内核及处理方式都是一样的。

2. plugin

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

3. preset

一般来说我们转译ES6代码需要使用到很多插件,比如转译class的、转译箭头函数的等等,如果每次开发都要逐一添加并安装,配置文件很长不说,安装的时间也会很长。

为了解决这个问题,Babel官方提供了preset,也就是一组常用插件的集合。

preset分为以下几种:

  • 官方内容,目前包括 env, react, flow, minify 等;这里最重要的是 env;
  • stage-x,这里面包含的都是当年最新规范的草案,每年更新。这里面还可细分为:
    • Stage 0 - 稻草人: 只是一个想法,经过 TC39 成员提出即可。
    • Stage 1 - 提案: 初步尝试。
    • Stage 2 - 初稿: 完成初步规范。
    • Stage 3 - 候选: 完成规范和浏览器初步实现。
    • Stage 4 - 完成: 将被添加到下一年度发布。

此外,低一级的 stage 会包含所有高级 stage 的内容,例如 stage-1 会包含 stage-2, stage-3 的所有内容。
stage-4 在下一年更新会直接放到 env 中,所以没有单独的 stage-4 可供使用。

  • es201x, latest
    这些是已经纳入到标准规范的语法。例如 es2015 包含 arrow-functions,es2017 包含 syntax-trailing-function-commas;但因为 env 的出现,使得 es2016 和 es2017 都已经废弃。所以我们经常可以看到 es2015 被单独列出来,但极少看到其他两个。
    latest 是 env 的雏形,它是一个每年更新的 preset,目的是包含所有 es201x。但也是因为更加灵活的 env 的出现,已经废弃。
4. 执行顺序
  • Plugin 会运行在 Preset 之前。
  • Plugin 会从前到后顺序执行。
  • Preset 的顺序则 刚好相反(从后向前)

preset 的逆向顺序主要是为了保证向后兼容,因为大多数用户的编写顺序是 ['es2015', 'stage-0']。这样必须先执行 stage-0 才能确保 babel 不报错。因此我们编排 preset 的时候,也要注意顺序,其实只要按照规范的时间顺序列出即可。

5. env

env 的核心目的是通过配置得知目标环境的特点,然后只做必要的转换。例如目标浏览器支持 es2015,那么 es2015 这个 preset 其实是不需要的,于是转化后的代码就可以小一点(一般转化后的代码总是更长),构建时间也可以缩短一些。

如果不写任何配置项,env 等价于 latest,也等价于 es2015 + es2016 + es2017 三个相加(不包含 stage-x 中的插件);

下面列出几种比较常用的配置方法:

//如下配置将考虑所有浏览器的最新2个版本(safari大于等于7.0的版本)的特性,将必要的代码进行转换。
//而这些版本已有的功能就不进行转化了。这里的语法可以参考 browserslist
//https://github.com/browserslist/browserslist
{
  "presets": [
    ["@babel/env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}

//如上配置将目标设置为 nodejs,并且支持 6.10 及以上的版本。
//也可以使用 node: 'current' 来支持最新稳定版本。
//例如箭头函数在 nodejs 6 及以上将不被转化,但如果是 nodejs 0.12 就会被转化了。
{
  "presets": [
    ["@babel/env", {
      "targets": {
        "node": "6.10"
      }
    }]
  ]
}
6.plugin与preset的短名称

插件可以在配置文件里写短名称,如果插件的npm包名称的前缀为 babel-plugin-,可以省略前缀。例如:

module.exports = {
  "presets": [],
  "plugins": ["babel-plugin-transform-class-properties"] //可以简写如下:

  "plugins": ["transform-class-properties"]
}

总体的简写如下:

省略前 省略部分 省略后 注释
babel-plugin-xx babel-plugin- xx A
@babel/plugin-xx plugin- xx B
babel-preset-xx babel-preset- xx C
@babel/preset-env preset- @babel/env D

AC是版本6的简化形式;BD是版本7的简化形式,但babel官方并没有给出明确的说明,所以还是推荐用全称。

7.版本说明

babel-:版本6及以前的plugin或preset
@babel/:版本7的plugin或preset

# 【第二篇:polyfill】

Babel转换代码都是通过plugin的,polyfill也是Babel的一个plugin,但是不同的是其他plugin多数是进行js语法的转换的;但只有polyfill是转换相应的api的。

polyfill俗称‘垫片’,Babel的其他插件,默认只转换js语法,而不转换新的 API,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码。

举例来说,es2015 在 Array 对象上新增了 Array.from 方法。babel 就不会转码这个方法。如果想让这个方法运行,必须使用 babel-polyfill。(内部集成了 core-js 和 regenerator)

  • 两个主要缺点

1.使用 babel-polyfill 会导致打出来的包非常大,因为 babel-polyfill 是一个整体,把所有方法都加到原型链上。比如我们只使用了 Array.from,但它把 Object.defineProperty 也给加上了,这就是一种浪费了。这个问题可以通过单独使用 core-js 的某个类库来解决,core-js 都是分开的。

2.babel-polyfill 会污染全局变量,给很多类的原型链上都作了修改,如果我们开发的也是一个类库供其他开发者使用,这种情况就会变得非常不可控。

  • 使用方式也跟其他插件不同
//首先安装到运行环境中
npm i @babel/polyfill -S
//在入口文件导入,比如vue则在main.js中导入
import '@babel/polyfill';

#【第三篇:Babel的配置文件】

Babel 本身不具有任何转化功能,它把转化的功能都分解到一个个 plugin 里面;如果我们不指定任何配置(不指定plugin或preset),此时Babel虽然能完成转换,但是转码前后的代码是相同的,相当于没有转码。

# .babelrc文件

首先需要在项目根目录新建.babelrc文件,它的配置如下:

//无参数配置时 -- 直接以字符串的形式写到对应的数组中
{
  "presets": ["@babel/env"],
  "plugins": ["transform-class-properties"]
}

//有参数配置时 -- 需要把字符串形式改成数组形式
//参1:字符串类型的plugin或preset名 参2:配置项,一般为对象
{
  "presets": [
    [
      "@babel/env",
      {
        "useBuiltIns": "entry"
      }
    ]
  ],
  "plugins": []
}

# babel.config.js 或 .babelrc.js文件

对于babel.config.js和.babelrc.js,它的配置是一样的,通过module.exports输出配置项;当然,首先先在项目根目录创建对应的文件。

module.exports = {
  "presets": ["@babel/env"],
  "plugins": ["transform-class-properties"]
}

# package.json 中 babel属性

对于package.json,就是在package.json中增加一个babel属性和值,它的配置是这样子:

{
  "name": "Babel",
  "version": "1.0.0",
  "description": "learn babel",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "babel": {
    "presets": ["@babel/env"],
    "plugins": ["transform-class-properties"]
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

# 【第四篇:Babel配套工具】

1. @babel/core

@babel/core是Babel的核心包,作用是将js转成ast(抽象语法树),方便各个插件分析语法进行相应的处理。

2. @babel/cli
  • 【注意】需要@babel/core配合使用;

  • @babel/cli是babel的工具,安装后可以在命令行使用Babel的命令;

  • 可以全局进行安装,也可以安装到项目中的devDependencies中;

    • 全局中:-g
    • 项目中:--save-dev 或 -D 【推荐安装到项目中】
  • 版本差异

    npm i babel-cli -D    //安装的是版本6的babel
    npm i @babel/cli -D   //安装的是最新版的babel,现在是版本7
    
  • 基础使用

    • 转译一个js文件
    babel a.js -o b.js
    //或
    babel a.js -out-file b.js
    
    • 转译一个文件夹目录
    babel one -d two
    //或
    babel one --out-dir two
    
  • 全局安装与项目安装使用差异

    • 全局安装的工具可以直接如上使用
    • 项目安装的工具使用如下:
    //① babel命令前加npx
    npx babel a.js -o b.js
    
    //② 在package.json中scripts属性下添加命令
    {
      "name": "Babel",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "babel": "babel ./a.js -o ./b.js --watch"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
    }
    //直接在命令行运行 npm run babel 即可
    
3. babel-loader

babel-loader是用于webpack的一个loader,以便webpack在构建的时候用Babel对JS代码进行转译,这样我们就不用再通过命令行手动转译了。我们在配置该loader的时候需要先安装它:

npm i babel-loader -D

在webpack配置文件中,我们把babel-loader添加到module的loaders列表中:

module: {
   rules: [
     {
       test: /\.js$/,
       exclude: /(node_modules|bower_components)/,
       use: {
         loader: 'babel-loader',
         options: {
           presets: ['@babel/preset-env']
         }
       }
     }
   ]
 }

在这里,我们通过options属性给babel-loader传递预设和插件等Babel配置项。我们也可以省略这个options,这个时候babel-loader会去读取默认的Babel配置文件,也就是.babelrc,.babelrc.js,babel.config.js等。在现在的前端开发中,建议通过配置文件来传递这些配置项。

4. @babel/node

@babel/node在真正做前端项目开发的时候,是用不到的。该工具执行的时候需要占用大量内存空间,Babel官方不建议在生产环境使用该工具。

@babel/node其实和node的功能非常接近,@babel/node的优点是在执行命令的时候可以配置Babel的编译配置项。如果遇到node.js不支持的ES6语法,我们通过@babel/node就可以完成。

在Babel6版本的时候,@babel/node这个工具是 @babel/cli附带的,所以只要安装了@babel/cli ,就可以直接使用 babel/node。但Babel7里,我们需要单独安装。

#【第五篇:Babel7更新说明】

  • preset 的变更:淘汰 es201x,删除 stage-x,强推 env (重点)

你可能感兴趣的:(Babel基础)