Babel基础知识

babel

先放一张Babel的基本流程图javascript

一、babel是什么

babel是一个JavaScript代码转换器,主要目的是将ES2015+的代码转换成llq或者其余环境识别的代码,主要目的有如下几个:java

  • 转换语法(babylon)
  • 兼容新方法( @babel/polyfill)
  • 源码转换(babel-generator)

二、babel的基本用法

2-一、经过引入babel核心包使用

安装node

npm install @babel/core -D
复制代码

使用git

const babel = require('@babel/core')
babel.transform("code",optionsObject)
复制代码

Babel的核心包提供了一些最基础的API,好比:babel.transformFilebabel.transformFromAst等等,具体可查看,这里es6

2-二、经过命令行使用

@babel/cli包依赖@babel/core,因此须要同时安装这两个包。github

npm install @babel/core @babel/cli
复制代码

安装完这两个包后,Babel提供了一个babel命令,假如如今要 将src文件夹下的js文件编译到lib目录下,执行以下命令:web

./node_modules/.bin/babel src --out-dir lib
复制代码

或者:npm

npx babel src --out-dir lib
复制代码

固然,在使用命令行时能够给babel传递参数,好比下面这样传递plugins:json

./node_modules/.bin/babel src --out-dir lib --plugins=@babel/plugin-transform-arrow-functions
复制代码

或者传递presetsapi

./node_modules/.bin/babel src --out-dir lib --presets=@babel/env
复制代码

三、插件和预设的区别

Babel核心包并不会去转换代码,核心包只提供一些核心API,真正的代码转换工做由插件或者预设来完成,好比要转换箭头函数,会用到这个plugin@babel/plugin-transform-arrow-functions,当须要转换的要求增长时,咱们不可能去一一配置相应的plugin,这个时候就能够用到预设了,也就是presetspresetsplugins的集合,一个presets内部包含了不少plugin

四、polyfill

Babel转换代码分为两部分,第一部分是将新的语法转换为普通语法,好比下面这样,将ES6中的箭头函数转换为ES5:

转换前:

let fn = (a, b) => a + b;
复制代码

转换后:

var fn = function fn(a, b) {
  return a + b;
};
复制代码

第二部分是,模拟新的API,好比说,咱们代码中使用了Promise,而目标环境不支持Promise,那么Babel会手动实现一个Promise,使得目标环境支持Promise,这个过程叫作polyfill

看个例子,下面咱们建立一个项目,目录以下:

  • node_modules 项目依赖包
  • src 源文件
  • babel.config.js Babel的配置文件
  • package.json 项目描述文件

src文件下有个index.js文件,也就是须要编译的文件,内容以下:

let count = 1; //let 声明的变量
let fn = (a, b) => a + b;  //箭头函数

let obj = { a: 1, b: 2 }
let b = { ...obj } //解构赋值


let promise = new Promise(() => {  //promise
    resolve(1)
})
function* it() {  //generator 函数
    yield 1;
    yield 2;
    return 3;
}
复制代码

babel.config.js内容以下:

module.exports = {
    presets: [
    [
        "@babel/env",
            {
                useBuiltIns: "usage",//也能够写entry
                corejs: "2.6.9"
            },
        ]
    ]
}
复制代码

编译后代码以下:

"use strict";

require("core-js/modules/es6.array.for-each");

require("core-js/modules/es6.array.filter");

require("core-js/modules/es6.symbol");

require("core-js/modules/web.dom.iterable");

require("core-js/modules/es6.array.iterator");

require("core-js/modules/es6.object.keys");

require("core-js/modules/es6.object.define-property");

require("regenerator-runtime/runtime");

require("core-js/modules/es6.promise");

require("core-js/modules/es6.object.to-string");

var _marked =
/*#__PURE__*/
regeneratorRuntime.mark(it);

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

var count = 1; //let 声明的变量

var fn = function fn(a, b) {
  return a + b;
}; //箭头函数


var obj = {
  a: 1,
  b: 2
};

var b = _objectSpread({}, obj); //解构赋值


var promise = new Promise(function (resolve) {
  //promise
  resolve(1);
});

function it() {
  return regeneratorRuntime.wrap(function it$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          _context.next = 2;
          return 1;

        case 2:
          _context.next = 4;
          return 2;

        case 4:
          return _context.abrupt("return", 3);

        case 5:
        case "end":
          return _context.stop();
      }
    }
  }, _marked);
}
复制代码

编译后的代码量增长了不少,仔细分析大概分为这几部分:

一、require语句,大部分是从core.js包分别导入具体API对应的polyfill

二、由于使用了generator函数,须要去regenerator-runtime包中导入对应方法

三、对箭头函数,解构赋值、generator函数进行改写。

由于咱们在配置文件中配置了这项:

{
    useBuiltIns: "usage",
    corejs: "2.6.9"      
},
复制代码

这个配置表示文件内用到了什么API,那么就转换什么API,没用到的不用转,也就是按需加载,因此咱们会看到那么多的require语句。

还有一种方法是,不须要在每一个文件都进行转换,由于这样会致使代码重复,同一个API在不一样的文件都被转换了。

那么咱们只须要在入口文件中手动引入polyfill便可。以下:

import '@babel/polyfill'
复制代码

polyfill后,咱们就能够使用PromiseWeakMapArray.fromObject.assignArray.prototype.includes等方法了。

有种场景下,咱们可能不须要使用这么多方法,好比在编写库或者工具的时候,那咱们就能够使用transform-runtime来取代@babel/polyfill了。

五、Babel的配置形式

5-一、babel.config.js

项目根目录下新建babel.config.js,内容以下:

module.exports = function (api) {
  api.cache(true);

  const presets = [ ... ];
  const plugins = [ ... ];

  return {
    presets,
    plugins
  };
}
复制代码

具体配置,可参考,这里

5-二、.babelrc

项目根目录下新建.babelrc,内容以下:

{
  "presets": [...],
  "plugins": [...]
}
复制代码

具体配置,可参考,这里

5-三、package.json

也能够在package.json文件中配置

{
  "name": "my-package",
  "version": "1.0.0",
  "babel": {
    "presets": [ ... ],
    "plugins": [ ... ],
  }
}
复制代码

5-四、.babelrc.js

这种方法和.babelrc配置的惟一区别就是,能够编写js代码,好比:

const presets = [ ... ];
const plugins = [ ... ];

if (process.env["ENV"] === "prod") {
  plugins.push(...);
}

module.exports = { presets, plugins };
复制代码

5-五、cli中的配置

babel --plugins @babel/plugin-transform-arrow-functions script.js
复制代码

具体配置,可参考https://babeljs.io/docs/en/babel-cli

5-六、核心包中的配置

require("@babel/core").transform("code", {
  plugins: ["@babel/plugin-transform-arrow-functions"]
});
复制代码

具体配置,可参考,这里

六、plugin

6-一、插件的写法

插件的写法:

  1. 直接写插件名称
{
  "plugins": ["babel-plugin-myPlugin"]
}
复制代码
  1. 直接写插件路径,能够是相对路径也能够是绝对路径
{
  "plugins": ["./node_modules/asdf/plugin"]
}
复制代码
  1. 插件缩写,若是插件是以babel-plugin-开头的,就能够缩写
{
  "plugins": [
    "myPlugin",
    "babel-plugin-myPlugin" // equivalent
  ]
}
复制代码

6-二、插件的顺序

几条规则:

    1. 插件在预设以前工做,也就是先pluginpreset
    1. plugin的顺序是从左到右。first to last
    1. preset的顺序是从右到左。last to first

preset的顺序为啥是这样的,官方是这样说的:

This is mostly for ensuring backwards compatibility, since most users list "es2015" before "stage-0"。

6-三、给插件传参数

插件的写法有如下三种,第三种就是传递参数的形式

{                 1           2              3
  "plugins": ["pluginA", ["pluginA"], ["pluginA", {}]]
}

复制代码

具体一点就是这样:

{
  "plugins": [
    [
      "transform-async-to-module-method",
      {
        "module": "bluebird",
        "method": "coroutine"
      }
    ]
  ]
}
复制代码

preset也同样:

{
  "presets": [
    [
      "env",
      {
        "loose": true,
        "modules": false
      }
    ]
  ]
}
复制代码

6-四、编写插件

一个插件长这样:

export default function() {
  return {
    visitor: {
      Identifier(path) {
        const name = path.node.name;
        // reverse the name: JavaScript -> tpircSavaJ
        path.node.name = name
          .split("")
          .reverse()
          .join("");
      },
    },
  };
}
复制代码

具体可参考babel手册

相关文章
相关标签/搜索