babel 개발 시작하기(babel 플러그인 개발 방법)

바벨 개발

사전 지식

바벨을 배우기 전에 반드시 이해해야 할 핵심 개념은 AST입니다.

동시에 babel 관련 의존성이 프로젝트에 설치되길 바랍니다.

npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill

AST 란 무엇입니까?

Wikipedia의 설명:

컴퓨터 과학에서 추상 구문 트리(Abstract Syntax Tree, AST) 또는 간단히 구문 트리(Syntax tree)는 소스 코드의 문법 구조를 추상적으로 표현한 것입니다. 프로그래밍 언어의 문법적 구조를 트리 형태로 나타내며 트리의 각 노드는 소스 코드의 구조를 나타냅니다.
"소스 코드의 문법적 구조에 대한 추상적 표현" , 이 문장에 주목하세요. AST에 대한 이해의 핵심입니다. 이 문장의 일반적인 의미는 JS 엔진과 이스케이퍼가 이해할 수 있도록 합의된 특정 사양에 따라 트리 모양의 데이터 구조로 코드를 설명하는 것입니다.
예를 들어 react 및 vue와 같은 프런트 엔드 프레임워크의 가상 DOM은 실제로 HTML의 실제 DOM을 JS의 가상 머신 DOM으로 설명하는 것입니다. 페이지의 실제 DOM을 수정하는 작업은 JS의 가상 DOM에서 수행되어 최종 DOM 구조를 얻고 최종적으로 실제 DOM에 반영되어 실제 DOM의 작업을 줄이고 브라우저의 소비를 줄입니다. 성능 . 기본 코드의 경우 AST는 가상 머신 DOM에 상대적입니다.
물론 AST가 JS에 고유한 것은 아니다. 모든 언어는 해당 AST로 변환될 수 있으며 AST 구조의 많은 사양이 있다. 다른 언어는 다른 사양에 해당하며 JS에서 사용하는 사양의 대부분은 estree이다. 이 사양, 우리는 단지 간단한 이해를 할 뿐입니다.

AST는 어떻게 생겼습니까?

AST에 대한 기본적인 이해를 마친 후 AST는 어떻게 생겼습니까?
astexplorer.net 웹사이트는 온라인에서 AST를 생성할 수 있으며, AST의 구조를 배우기 위해 그 안에서 AST를 생성해 볼 수 있습니다.
아래 그림과 같이 왼쪽은 코드, 상수 const a = 1만 선언, 오른쪽은 AST 구조

바벨 프로세스

AST를 이해한 후에 바벨 학습을 시작할 수 있습니다.
먼저 바벨은 우리에게 익숙하면서도 생소한 도구로, 코드 처리에 도움이 된다면 크게 다음과 같은 단계로 나눌 수 있습니다.

  1. 코드의 AST 구조를 얻기 위한 코드의 구문 분석, AST 컴파일
  2. 요구 사항에 따라 코드의 AST를 변환 및 처리하고 처리된 AST 구조를 가져옵니다.
  3. AST를 다시 변환하여 개체 코드를 생성하는 생성

분석하다

파서를 통해 소스코드를 추상문법집 AST로 변환합니다.
이 단계의 주요 작업은 코드를 AST로 변환하는 것입니다. 이 단계는 어휘 분석구문 분석의 두 단계를 거칩니다 . 파서 단계가 시작되면 문서가 먼저 스캔되고 그 동안 어휘 분석이 수행됩니다. 예: "const a = 1"은 어휘 분석에 의해 "const", "a", "=", "1"과 같은 가장 세분화된 토큰으로 분해됩니다 .

어휘 분석이 끝나면 분석된 토큰은 문법 분석으로 넘어갑니다. 구문 분석의 주요 작업은 토큰을 기반으로 AST를 생성하는 것입니다 . 토큰을 순회 하고 최종적으로 특정 구조의 트리를 생성하며 이 트리가 AST입니다.
const a = 1 AST 구조를 예로 들어 보겠습니다 .
{
    
    "type":"File","start":0,"end":11,"loc":{
    
    "start":{
    
    "line":1,"column":0},"end":{
    
    "line":1,"column":11}},"errors":[],"program":{
    
    "type":"Program","start":0,"end":11,"loc":{
    
    "start":{
    
    "line":1,"column":0},"end":{
    
    "line":1,"column":11}},"sourceType":"script","interpreter":null,"body":[{
    
    "type":"VariableDeclaration","start":0,"end":11,"loc":{
    
    "start":{
    
    "line":1,"column":0},"end":{
    
    "line":1,"column":11}},"declarations":[{
    
    "type":"VariableDeclarator","start":6,"end":11,"loc":{
    
    "start":{
    
    "line":1,"column":6},"end":{
    
    "line":1,"column":11}},"id":{
    
    "type":"Identifier","start":6,"end":7,"loc":{
    
    "start":{
    
    "line":1,"column":6},"end":{
    
    "line":1,"column":7},"identifierName":"a"},"name":"a"},"init":{
    
    "type":"NumericLiteral","start":10,"end":11,"loc":{
    
    "start":{
    
    "line":1,"column":10},"end":{
    
    "line":1,"column":11}},"extra":{
    
    "rawValue":1,"raw":"1"},"value":1}}],"kind":"const"}],"directives":[]},"comments":[]}

아래 그림과 같이 핵심 부분의 스크린 샷을 찍었습니다. 패키지의 외부 레이어 type는 단어의 의미에서 선언이고 used는 유형 선언 임을VariableDeclaration 알 수 있습니다 . description 필드 에는 선언 객체도 있고, id는 객체이기도 한 선언 객체의 이름이고, 그 이름은 선언 객체 이름의 값이고, init는 선언 객체(또는 객체)의 초기화 값입니다. ), 내부의 값이 이 초기값입니다.kindconstdeclarationsVariableDeclarator

위에서 언급한 필드 외에도 행, 열, 값 유형 등의 세부 정보가 있습니다. 이것이 우리가 얻은 AST입니다.

그렇다면 개발 과정에서 어떻게 코드를 AST로 변환해야 할까요? 이를 위해서는 babel 팀이 개발한 것이 아니라 포크 기반 acorn 프로젝트인 이전에 Babylon이라고 불렸던 babel이 제공하는 파서 @babel/parser 가 필요합니다.
사용 프로세스(babel 관련 종속성에 따라):
const parser = require('@babel/parser');
const ast = parser.parse('const a = 1'); // 转换成AST

자세한 내용은 공식 문서를 방문하여 @babel/parser를 참조하십시오.

전환하다

구문 분석 단계에서 AST를 성공적으로 획득했습니다. babel은 AST를 수신한 후 @babel/traverse를 사용하여 깊이 우선 순회를 수행합니다. 이 단계에서 플러그인이 트리거되어 방문자 기능의 형태로 각각 다른 유형의 AST 노드를 방문합니다. 위의 예를 들어 VariableDeclaration함수를 VariableDeclaration노드를 콜백할 수 있으며 이 유형의 각 노드는 이 함수 콜백을 트리거합니다.

const parser = require('@babel/parser');

const traverse = require('@babel/traverse').default

const ast = parser.parse('const a = 1'); // 转换成AST

traverse(ast, {
    
    
    VariableDeclaration(path, state) {
    
    
        // 操作处理...
    }
});

이 함수에는 두 개의 매개변수가 있습니다.

path는 노드 정보, 부모 노드 정보, 노드를 운영하는 방법을 포함하여 현재 접속된 경로입니다. 이러한 메서드를 사용하여 ATS 추가, 업데이트, 이동 및 삭제와 같은 작업을 수행할 수 있습니다.

상태

상태는 현재 플러그인 정보 및 매개 변수 정보 등을 포함하며 노드 간 데이터 전송을 사용자 지정하는 데 사용할 수도 있습니다.

생성하다

최종 단계는 생성 입니다. 소스맵을변환된 AST를 타겟 코드로 출력하고 소스 맵을 생성합니다 .

인스턴스 작업

코드 러닝은 구경만 할 것이 아니라 직접 해봐야 깊이 있게 배울 수 있습니다. 다음으로 ES6에서 ES5로 const변환하는 var
.위의 단계에 따라 단계별로 진행합니다.

AST를 얻기 위해 구문 분석

@babel/parserAST를 생성하는 데 사용하는 것은 비교적 간단하며
, 이는 ast 상수가 변환된 AST인 위의 경우와 동일합니다.

const parser = require('@babel/parser');
const ast = parser.parse('const a = 1'); // 转换成AST

변환 처리 AST

Use @babel/traverseProcessing AST
이 단계에서 우리는 생성된 AST 구조를 분석하고 VariableDeclaration 콜백에서 kind 필드가 const가 될 것이라고 결정하고 kind 필드를 var로 수정하기만 하면 됩니다.

const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default
const ast = parser.parse('const a = 1'); // 转换成AST
traverse(ast, {
    
    
    // 声明变量都会触发这个VariableDeclaration函数
    VariableDeclaration(path, state) {
    
    
        // 通过 path.node 访问实际的 AST 节点
        path.node.kind = 'var'
    }
});

코드 생성

마지막 단계는 다음을 사용하여 @babel/generator처리된

const parser = require('@babel/parser');

const traverse = require('@babel/traverse').default

const generate = require('@babel/generator').default

const ast = parser.parse('const a = 1'); // 转换成AST
// 转换回code代码
traverse(ast, {
    
    
    // 声明变量都会触发这个VariableDeclaration函数
    VariableDeclaration(path, state) {
    
    
        // 通过 path.node 访问实际的 AST 节点
        path.node.kind = 'var'
    }
});

// 将处理好的 AST 放入 generate
const transformedCode = generate(ast).code
console.log(transformedCode,"new Code")

최종 인쇄된 새 코드 결과는 다음과 같습니다.

플러그인으로 개발하는 방법

위의 단계를 분석한 결과 우리가 집중하고 있는 것이 사실 변환 처리 단계임을 알 수 있습니다. 따라서 플러그인을 개발할 때 이 단계만 주의하면 되고 나머지 두 단계의 webpack 플러그인 구성은 이미 완료되어 있습니다. 결국 플러그인은 객체를 반환해야 하는 함수를 내보내기만 하면 되고 객체의 방문자만 변경하면 되므로 트래버스 변환 처리 단계와 유사합니다.
함수이기 때문에 물론 여러 매개변수를 허용합니다.

  1. api 는 babel에서 제공하는 일련의 메서드를 상속합니다.
  2. options 는 플러그인을 사용할 때 전달되는 매개변수입니다.
  3. dirname 은 처리 기간의 파일 경로입니다.
// myplugin.js 파일에서 ES6 변수 선언 방식을 var로 변환하는 babel 플러그인 코드는 다음과 같습니다.
module.exports = (api, options, dirname) => {
    
    
	return {
    
    
		visitor: {
    
    
            VariableDeclaration(path, state) {
    
    
                path.node.kind = 'var'
            }
	    }
	}
}

우리가 개발한 플러그인을 사용하는 방법

플러그인을 개발했으니 이제 어떻게 사용할까요?
물론 babel과 webpack을 통해서도 사용됩니다!

1. 먼저 webpack을 글로벌로 설치하고 babel-loader를 로컬로 설치합니다.

우리는 webpack을 사용하고 싶기 때문에 우리의 개발 환경에는 당연히 webpack 지침이 필요합니다(가지고 있다면 건너뛰십시오).

npm install webpack -g

또한 프로젝트 파일을 로드하는 데 도움이 되도록 webpack에 babel-loader가 필요합니다.

npm install babel-loader --save
2. webpack.config.js 구성 파일 작성

엔트리 파일 지정, 사용 로더 지정, 출력 파일 주소 지정 등 webpack 관련 설정을 통해
코드는 다음과 같습니다.
// webpack.config.js

module.exports = {
    
    
    mode: "development", // 这里使用开发模式,方便查看输出文件内容
    entry: './main.js',
    // output: {
    
    
    //     filename: 'bundle.js' // 可指定输出路径
    // },
    module: {
    
    
        rules: [{
    
    
            test: /\.js?$/,
            use: ['babel-loader']
        }]
    }
}
3. babel 플러그인 구성 작성

2단계 babel-loader에 의해 webpack이 로드되는 것을 확인한 후 babel-loader의 구성을 시작합니다. babel을 설정하는 방법은 여러 가지가 있는데 자세한 설명은 생략하고 여기서는 .babelrc 파일을 통해 공유 방식으로 설정하겠습니다.
// .babelrc 파일

{
    
    
    "plugins":[
        ["./myplugin.js"] // 这里以相对路径的方式引入自己写的插件
    ]
}
4. webpack 패키지 컴파일 실행

webpack.config.js 디렉토리에서 다음 명령을 입력하십시오.

webpack
5. 결과 보기

항목 파일 내용:

패키징 후 출력 파일 내용:

보시다시피 코드가 성공적으로 변환되었습니다.

이 사례의 코드 GitHub 주소

추천

출처blog.csdn.net/weixin_43589827/article/details/121798316