>  기사  >  웹 프론트엔드  >  Babel을 es6으로 변환하는 단계에 대한 자세한 설명

Babel을 es6으로 변환하는 단계에 대한 자세한 설명

php中世界最好的语言
php中世界最好的语言원래의
2018-04-20 11:23:121567검색

이번에는 Babel을 es6로 변환하는 방법을 단계별로 자세히 안내해드리겠습니다. Babel을 es6으로 변환할 때 주의사항은 무엇인가요? 아래는 실제 사례입니다.

babel은 현재 React 및 Vue 프로젝트를 개발할 때 사용되는 트랜스코더입니다. es6+ 구문을 es5는 물론 JSX 및 기타 구문으로 변환할 수 있습니다.

우리 프로젝트에서는 모두 플러그인과 프리셋(여러 플러그인의 집합)을 구성하여 env, stage-0 등과 같은 특정 코드를 변환합니다.

사실 Babel은 커스텀 플러그인을 통해 어떤 코드든 변환할 수 있습니다. 다음으로 “es6의 class를 es5로 변환”하는 예제를 통해 Babel에 대해 알아 보겠습니다. class 转换为es5”的例子来了解一下babel。

内容如下:

webpack环境配置

大家应该都配置过babel-core这个loader,它的作用是提供babel的核心Api,实际上我们的代码转换都是通过插件来实现的。

接下来我们不用第三方的插件,自己实现一个es6类转换插件。先执行以下几步初始化一个项目:

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

  2. 新建一个webpack.config.js

  3. 配置webpack.config.js

如果我们的插件名字想叫transform-class,需要在webpack配置中做如下配置:

接下来我们在node_modules中新建一个babel-plugin-transform-class的文件夹来写插件的逻辑(如果是真实项目,你需要编写这个插件并发布到npm仓库),如下图:

红色区域是我新建的文件夹,它上面的是一个标准的插件的项目结构,为了方便我只写了核心的index.js文件。

如何编写bable插件

babel插件其实是通过AST(抽象语法树)实现的。

babel帮助我们把js代码转换为AST,然后允许我们修改,最后再把它转换成js代码。

那么就涉及到两个问题:js代码和AST之间的映射关系是什么?如何替换或者新增AST?

好,先介绍一个工具:astexplorer.net:

这个工具可以把一段代码转换为AST:

如图,我们写了一个es6的类,然后网页的右边帮我们生成了一个AST,其实就是把每一行代码变成了一个对象,这样我们就实现了一个映射。

再介绍一个文档: babel-types :

这是创建AST节点的api文档。

比如,我们想创建一个类,先到astexplorer.net中转换,发现类对应的AST类型是 ClassDeclaration 。好,我们去文档中搜索,发现调用下面的api就可以了:

创建其他语句也是一样的道理,有了上面这两个东西,我们可以做任何转换了。

下面我们开始真正编写一个插件,分为以下几步:

  1. 在index.js中export一个函数

  2. 函数中返回一个对象,对象有一个visitor参数(必须叫visitor)

  3. 通过astexplorer.net查询class 对应的AST节点为 ClassDeclaration

  4. 在vistor中设置一个捕获函数 ClassDeclaration ,意思是我要捕获js代码中所有 ClassDeclaration

    내용은 다음과 같습니다.
  5. webpack 환경 구성

    모두가 사용하는 babel-core 로더를 구성해야 합니다. Babel의 핵심 API를 제공하기 위해 실제로 코드 변환은 플러그인을 통해 구현됩니다. 🎜🎜다음으로는 타사 플러그인을 사용하지 않고 직접 es6 변환 플러그인을 구현해 보겠습니다. 먼저 다음 단계를 수행하여 프로젝트를 초기화하세요. 🎜
      🎜🎜npm install webpack webpack-cli babel-core -D🎜🎜🎜🎜새 webpack.config.js 만들기🎜🎜 🎜🎜 webpack.config.js 구성🎜🎜
    🎜플러그인 이름을 변환 클래스로 지정하려면 웹팩 구성에서 다음 구성을 수행해야 합니다. 🎜🎜🎜🎜다음으로 node_modules에 babel-plugin-transform-class라는 새 폴더를 생성하여 작성합니다. 아래와 같이 플러그인의 논리(실제 프로젝트의 경우 이 플러그인을 작성하고 npm 저장소에 게시해야 하는 경우): 🎜🎜🎜🎜빨간색 부분은 제가 만든 폴더입니다. 그 위는 표준 플러그인 프로젝트 구조입니다. 편의상 제가 핵심 index.js 파일만 작성했습니다. 🎜🎜babel 플러그인 작성 방법🎜🎜babel 플러그인은 실제로 AST(Abstract Syntax Tree)를 통해 구현됩니다. 🎜🎜babel은 js 코드를 AST로 변환하고 수정하고 마지막으로 js 코드로 변환하는 데 도움을 줍니다. 🎜🎜그러면 관련된 두 가지 질문이 있습니다. js 코드와 AST 간의 매핑 관계는 무엇입니까? 🎜AST를 교체하거나 추가하는 방법은 무엇인가요? 🎜🎜좋아요, 먼저 도구를 소개하겠습니다: astexplorer.net:🎜🎜이 도구는 코드 조각을 AST로 변환할 수 있습니다:🎜🎜🎜🎜그림과 같이 es6 클래스를 작성하고, 웹페이지 오른쪽에 AST를 생성해줬는데, 실제로는 한 줄의 코드를 객체 🎜에 추가하여 매핑을 구현합니다. 🎜🎜또 다른 문서 소개: babel-types:🎜🎜이것은 AST 노드 생성을 위한 API 문서입니다. 🎜🎜예를 들어 클래스를 생성하려면 먼저 astexplorer.net에서 변환한 후 해당 클래스에 해당하는 AST 유형이 ClassDeclaration인지 확인합니다. 자, 문서를 검색하여 다음 API를 호출하는 것만으로도 충분하다는 것을 알아봅시다. 🎜🎜🎜🎜다른 문장을 생성할 때도 마찬가지입니다. 위의 두 가지만 있으면 어떤 변환도 할 수 있습니다. 🎜🎜이제 실제로 플러그인 작성을 시작합니다. 이는 다음 단계로 나뉩니다. 🎜
      🎜🎜index.js에서 함수 내보내기🎜🎜🎜🎜함수는 다음을 반환합니다. 개체, 개체 방문자 매개변수가 있습니다(방문자라고 해야 함)🎜🎜🎜🎜 astexplorer.net을 통해 쿼리🎜 class의 해당 AST 노드는 ClassDeclaration🎜🎜🎜🎜vistor에 캡처 함수 ClassDeclaration을 설정합니다. js 코드를 캡처하고 싶다는 뜻입니다. 모든 ClassDeclaration 노드🎜🎜🎜🎜논리 코드를 작성하고 변환을 완료합니다🎜
module.exports = function ({ types: t }) {
 return {
  visitor: {
   ClassDeclaration(path) {
    //在这里完成转换
   }
  }
 };
}

코드에는 두 개의 매개변수가 있습니다. 첫 번째 {types:t}변수 {types:t} 东西是从参数中解构出变量t,它其实就是babel-types文档中的t(下图红框),它是用来创建节点的:

第二个参数 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 = Object.create(Parent) ,当然别忘了处理 super 关键字。

打包后代码

 

运行 npm start 打包后,我们看到打包后的文件里 classt는 노드를 생성하는 데 사용되는 babel-types 문서(아래 그림의 빨간색 상자)에서 실제로 t입니다.

두번째 파라미터인 path는 캡쳐된 해당 노드 정보이고, path.node를 통해 이 노드의 AST를 얻을 수 있으며 이를 기반으로 수정하여 목표를 달성할 수 있습니다.

es6 클래스를 es5 클래스로 변환하는 방법

위는 모두 준비 작업이며 실제 논리는 이제 시작됩니다. 두 가지를 고려해 보겠습니다. 문제 먼저: 다음 변환을 수행해야 합니다. 먼저 es6 클래스를 es5 클래스 작성(즉, 일반 함수)으로 변환해야 합니다. 함수 이름, 함수 내부의 코드 블록을 포함하여 많은 코드를 재사용할 수 있다는 것을 확인했습니다. , 등.

를 정의하지 않은 경우 클래스 생성자 메서드를 사용하면 JavaScript 엔진이 자동으로 빈 생성자( ) 메서드를 사용하려면 호환성 처리가 필요합니다. <br>

다음으로 코드 작성을 시작합니다.

  1. 이전 AST 노드 가져오기
  2. 새 AST 노드를 저장할 배열을 만듭니다. (원래 클래스는 하나의 노드이지만 교체 후 여러 함수 노드로 대체됩니다) 기본 constructor 노드를 초기화합니다(위에서 언급했듯이 클래스에 정의된 생성자가 없을 수도 있습니다)🎜🎜
  3. 🎜이전 노드의 AST 개체를 반복합니다(여러 함수 노드가 반복됩니다)🎜🎜
  4. 🎜함수 유형이 constructor인지 확인합니다. 그렇다면 일반 노드를 만듭니다. 데이터 함수 노드를 가져와 기본 constructor 노드를 업데이트하고 🎜🎜
  5. 🎜constructor가 아닌 나머지 노드를 처리하고 prototype을 데이터를 통해 es5Fns🎜🎜
  6. 🎜에 넣습니다. 루프가 끝나면 constructor 노드를 es5Fns에 넣습니다. >🎜🎜
  7. 🎜판단 es5Fns의 길이가 1보다 큽니까? 1보다 큰 경우 replaceWithMultiple를 사용하여 AST🎜🎜🎜rrreee🎜상속 최적화🎜🎜실제로 클래스에도 상속이 포함되며 아이디어는 복잡하지 않습니다. AST가 있는 경우 Bird.prototype = Object.create(Parent) 코드 한 줄을 더 추가해야 합니다. 물론 super를 처리하는 것을 잊지 마세요. > 키워드. 🎜🎜패키지 코드🎜🎜 🎜🎜npm start 실행 패키징 후 패키징된 파일의 class🎜🎜 구문이 하나씩 es5 함수로 성공적으로 변환된 것을 확인할 수 있습니다. 🎜🎜이 기사의 사례를 읽은 후 방법을 마스터했다고 생각합니다. 더 흥미로운 정보를 보려면 PHP 중국어 웹사이트의 다른 관련 기사를 주목하세요! 🎜🎜추천 도서: 🎜🎜🎜vue cli webapck4 업그레이드 방법🎜🎜🎜🎜🎜AngularJS 애플리케이션 모듈화를 위한 세부 단계🎜🎜🎜🎜🎜vue-cli 3.0 초보자가 알아야 할 사항🎜🎜🎜

위 내용은 Babel을 es6으로 변환하는 단계에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.