Home  >  Article  >  Web Front-end  >  Babel conversion es6 method implementation

Babel conversion es6 method implementation

php中世界最好的语言
php中世界最好的语言Original
2018-05-02 11:50:441713browse

This time I will bring you the implementation of the babel conversion to es6 method. What are the precautions for babel conversion to es6? The following is a practical case, let's take a look.

In our projects, we all convert specific codes, such as env, stage-0, etc., by configuring plug-ins and presets (a collection of multiple plug-ins).

In fact, Babel can convert any code through custom plug-ins. Next, let’s learn about Babel through an example of “converting es6’s

class to es5”.

The content is as follows:

webpack environment configuration

Everyone should have configured the babel-core loader and its role It provides the core API of Babel. In fact, our code conversion is implemented through plug-ins.

Next, we will implement an es6 class conversion plug-in ourselves without using third-party plug-ins. First perform the following steps to initialize a project:

  1. npm install webpack webpack-cli babel-core -D

  2. Create a new webpack.config.js

  3. Configure webpack.config.js

If our plug-in name wants to be called transform-class, we need to make the following configuration in the webpack configuration:

Next we create a new folder of babel-plugin-transform-class in node_

modules to write the logic of the plug-in (if it is true project, you need to write this plug-in and publish it to the npm repository), as shown below:

The red area is my newly created folder, and what is above it is a standard plug-in Project structure, for convenience I only wrote the core index.js file.

How to write a babel plug-in

The babel plug-in is actually implemented through AST (Abstract Syntax Tree).

babel helps us convert js code into AST, then allows us to modify it, and finally convert it into js code.

So there are two questions involved: What is the mapping relationship between js code and AST? How to replace or add a new AST?

Okay, let’s first introduce a tool: astexplorer.net:

This tool can convert a piece of code into AST:

As shown in the figure , we wrote an es6 class, and then the right side of the webpage generated an AST for us, which actually turned each line of code into an object, so that we implemented a mapping.

Introducing another document: babel-types:

This is the API document for creating AST nodes.

For example, if we want to create a class, we first convert it in astexplorer.net and find that the AST type corresponding to the class is

ClassDeclaration. Okay, let’s search in the documentation and find that just calling the following api is enough:

The same goes for creating other statements. With the above two things, we can No conversions were made.

Now we start to actually write a plug-in, which is divided into the following steps:

  1. Export a function in index.js

  2. The function returns an object, the object has a visitor parameter (must be called visitor)

  3. Query through astexplorer.net

    Outputclass corresponding The AST node is ClassDeclaration

  4. Set a capture function

    ClassDeclaration in the vistor, which means I want to capture all in the js code ClassDeclaration Node

  5. Write logical code and complete the conversion

  6. module.exports = function ({ types: t }) {
     return {
      visitor: {
       ClassDeclaration(path) {
        //在这里完成转换
       }
      }
     };
    }
There are two parameters in the code, the first

{ types:t} The thing is to deconstruct the variablet from the parameters. It is actually t in the babel-types document (red box in the picture below), which is used to create nodes:

第二个参数 path ,它是捕获到的节点对应的信息,我们可以通过 path.node 获得这个节点的AST,在这个基础上进行修改就能完成了我们的目标。

如何把es6的class转换为es5的类

上面都是预备工作,真正的逻辑从现在才开始,我们先考虑两个问题:

我们要做如下转换,首先把es6的类,转换为es5的类写法(也就是普通函数),我们观察到,很多代码是可以复用的,包括函数名字、函数内部的代码块等。

 

如果不定义class中的 constructor 方法,JavaScript引擎会自动为它添加一个空的 constructor() 方法,这需要我们做兼容处理。

接下来我们开始写代码,思路是:

  1. 拿到老的AST节点

  2. 创建一个数组用来盛放新的AST节点(虽然原class只是一个节点,但是替换后它会被若干个函数节点取代) 初始化默认的 constructor 节点(上文提到,class中有可能没有定义constructor)

  3. 循环老节点的AST对象(会循环出若干个函数节点)

  4. 判断函数的类型是不是 constructor ,如果是,通过取到数据创建一个普通函数节点,并更新默认 constructor 节点

  5. 处理其余不是 constructor 的节点,通过数据创建 prototype 类型的函数,并放到 es5Fns

  6. 循环结束,把 constructor 节点也放到 es5Fns

  7. 判断es5Fns的长度是否大于1,如果大于1使用 replaceWithMultiple 这个API更新AST

module.exports = function ({ types: t }) {
 return {
  visitor: {
   ClassDeclaration(path) {
    //拿到老的AST节点
    let node = path.node
    let className = node.id.name
    let classInner = node.body.body
    //创建一个数组用来成盛放新生成AST
    let es5Fns = []
    //初始化默认的constructor节点
    let newConstructorId = t.identifier(className)
    let constructorFn = t.functionDeclaration(newConstructorId, [t.identifier('')], t.blockStatement([]), false, false)
    //循环老节点的AST对象
    for (let i = 0; i < classInner.length; i++) {
     let item = classInner[i]
     //判断函数的类型是不是constructor
     if (item.kind == &#39;constructor&#39;) {
      let constructorParams = item.params.length ? item.params[0].name : []
      let newConstructorParams = t.identifier(constructorParams)
      let constructorBody = classInner[i].body
      constructorFn = t.functionDeclaration(newConstructorId, [newConstructorParams], constructorBody, false, false)
     } 
     //处理其余不是constructor的节点
     else {
      let protoTypeObj = t.memberExpression(t.identifier(className), t.identifier(&#39;prototype&#39;), false)
      let left = t.memberExpression(protoTypeObj, t.identifier(item.key.name), false)
      //定义等号右边
      let prototypeParams = classInner[i].params.length ? classInner[i].params[i].name : []
      let newPrototypeParams = t.identifier(prototypeParams)
      let prototypeBody = classInner[i].body
      let right = t.functionExpression(null, [newPrototypeParams], prototypeBody, false, false)
      let protoTypeExpression = t.assignmentExpression("=", left, right)
      es5Fns.push(protoTypeExpression)
     }
    }
    //循环结束,把constructor节点也放到es5Fns中
    es5Fns.push(constructorFn)
    //判断es5Fns的长度是否大于1
    if (es5Fns.length > 1) {
     path.replaceWithMultiple(es5Fns)
    } else {
     path.replaceWith(constructorFn)
    }
   }
  }
 };
}

优化继承

其实,类还涉及到继承,思路也不复杂,就是判断AST中没有 superClass 属性,如果有的话,我们需要多添加一行代码 Bird.prototype = <a href="http://www.php.cn/wiki/60.html" target="_blank">Object</a>.create(Parent) ,当然别忘了处理 super 关键字。

打包后代码

 

运行 npm start 打包后,我们看到打包后的文件里 class

语法已经成功转换为一个个的es5函数。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

JS实现停留在界面提示框vue 

cli升级webpack4步骤详解

vue 单页应用前端路由如何配置

The above is the detailed content of Babel conversion es6 method implementation. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn