Maison  >  Article  >  interface Web  >  Implémentation de la méthode de conversion Babel Es6

Implémentation de la méthode de conversion Babel Es6

php中世界最好的语言
php中世界最好的语言original
2018-05-02 11:50:441714parcourir

Cette fois, je vais vous présenter l'implémentation de la conversion de Babel en es6. Quelles sont les précautions pour la conversion de Babel en es6. Ce qui suit est un cas pratique, jetons un coup d'œil.

Dans nos projets, nous convertissons tous des codes spécifiques, tels que env, stage-0, etc., en configurant des plug-ins et des préréglages (une collection de plusieurs plug-ins).

En fait, Babel peut convertir n'importe quel code via des plug-ins personnalisés. Ensuite, découvrons Babel à travers un exemple de « conversion d'es6 class en es5 ».

Le contenu est le suivant :

Configuration de l'environnement webpack

Tout le monde devrait avoir configuré le chargeur babel-core et son rôle Il fournit l'API de base de Babel. En fait, notre conversion de code est implémentée via des plug-ins.

Ensuite, nous implémenterons nous-mêmes un plug-in de conversion de classe es6 sans utiliser de plug-ins tiers. Effectuez d'abord les étapes suivantes pour initialiser un projet :

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

  2. Créez un nouveau webpack. config.js

  3. Configurer webpack.config.js

Si le nom de notre plug-in veut être appelé transform-class, nous devons le faire. faites la configuration suivante dans la configuration du webpack :

Ensuite, nous créons un nouveau dossier de babel-plugin-transform-class dans node_modules pour écrire la logique du plug-in (si pour un projet réel, vous devez écrire ce plug-in et le publier dans le référentiel npm), comme indiqué ci-dessous :

La zone rouge est mon dossier nouvellement créé, et au-dessus se trouve un plug-in standard. Pour la structure du projet, j'ai uniquement écrit le fichier principal index.js pour plus de commodité.

Comment écrire un plug-in Babel

Le plug-in Babel est en fait implémenté via AST (Abstract Syntax Tree).

babel nous aide à convertir le code js en AST, puis nous permet de le modifier, et enfin de le convertir en code js.

Il y a donc deux questions en jeu : quelle est la relation de mappage entre le code js et AST ? Comment remplacer ou ajouter un nouvel AST ?

Bien, introduisons d'abord un outil : astexplorer.net :

Cet outil peut convertir un morceau de code en AST :

Comme le montre la figure , nous avons écrit une classe es6, puis le côté droit de la page Web a généré pour nous un AST, qui a en fait transformé chaque ligne de code en objet, de sorte que nous avons implémenté un mappage.

Présentation d'un autre document : babel-types :

Ceci est le document API pour créer des nœuds AST.

Par exemple, si nous voulons créer une classe, nous la convertissons d'abord dans astexplorer.net et constatons que le type AST correspondant à la classe est ClassDeclaration . D'accord, cherchons dans la documentation et constatons qu'il suffit d'appeler l'API suivante :

Il en va de même pour la création d'autres instructions. Avec les deux choses ci-dessus, nous ne pouvons pas. des conversions ont été effectuées.

Maintenant, nous commençons à écrire un plug-in, qui est divisé en les étapes suivantes :

  1. Exporter une fonction dans index.js

  2. La fonction renvoie un objet, et l'objet a un paramètre visiteur (doit être appelé visiteur)

  3. Requête via astexplorer.netclass Le nœud AST correspondant est ClassDeclaration

  4. Définir une fonction de capture ClassDeclaration dans vistor, ce qui signifie que je veux capturer tous les ClassDeclaration nœuds dans le code js

  5. Écrivez le code logique et terminez la conversion

module.exports = function ({ types: t }) {
 return {
  visitor: {
   ClassDeclaration(path) {
    //在这里完成转换
   }
  }
 };
}

Il y a deux paramètres dans le code La première {types:t} chose est déconstruite à partir des paramètres. déconstruisez la variablet , il s'agit en fait de t dans le document babel-types (encadré rouge dans l'image ci-dessous), qui sert à créer des nœuds :

第二个参数 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 单页应用前端路由如何配置

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn