바벨 (4) (플러그인 제작)

jaehan·2023년 2월 14일
0

babel

목록 보기
4/4
post-thumbnail

플러그인 제작

console.log AST

https://astexplorer.net/ 에 들어가서 @babel/parser로 console.log('abc')에 대해 AST를 만들면 아래와 같다

  • 콘솔 로그 코드는 ExpressionStatement 노드로 시작한다.
  • 함수 또는 메서드를 호출하는 코드는 CallExpression 노드로 만들어진다.
  • 메서드 호출은 CallExpression 노드 내부에서 MemberExpression 노드로 만들어 진다.
  • MemberExpression 노드 내부에 객체와 메서드의 이름 정보가 있다.

console.log 제거 플러그인

플러그인 제작

plugins/remove-log-js

module.exports = function ({ types: t }) {
  return {
    visitor: {
      ExpressionStatement(path) {
        if (t.isCallExpression(path.node.expression)) {
          if (t.isMemberExpression(path.node.expression.callee)) {
            const memberExp = path.node.expression.callee;
            if (
              memberExp.object.name === "console" &&
              memberExp.property.name === "log"
            ) {
              path.remove();
            }
          }
        }
      },
    },
  };
};

위의 AST와 같이 비교해 보면

  • ExpressionStatement 노드가 생성되면 호출되도록 메서드를 등록했다.
  • path.node.expression의 타입이 CallExpression인지 확인한다
  • path.node.expression.callee의 타입이 MemberExpression인지 확인한다.
  • ...callee노드를 memberExp로 정의
  • MemberExp.object와 property의 이름이 각각 console, log이면 이 ExpressionStatement노드를 삭제한다.

실행

babel.config.js

const plugins = [
  "./plugins/remove-log.js",
];

module.exports = { plugins };

src/consoleCode.js

console.log("aaa");
const v1 = 123;
console.log("bbb");
function onClick(e) {
  const v = e.target.value;
}
function add(a, b) {
  return a + b;
}

npx babel src/consoleCode.js

결과

const v1 = 123;
function onClick(e) {
  const v = e.target.value;
}
function add(a, b) {
  return a + b;
}

console.log 추가 플러그인

function AST

아래는 function func(p1) {let v1;}의 AST이다

  • 함수를 정의하는 코드는 FunctionDeclaration으로 만들어 진다.
  • 함수 이름은 id의 name에 정의되어 있다.
  • BlockStatement 노드의 body안에 함수 내부의 코드에 대한 내용이 배열로 담겨 있다.

플러그인 제작

이름이 on으로 시작하는 함수에 console.log('call 함수 이름')을 넣어주는 플러그인을 만들 것이다.

plugins/insert-log-js

module.exports = function ({ types: t }) {
  return {
    visitor: {
      FunctionDeclaration(path) {
        if (path.node.id.name.substr(0, 2) === "on") {
          path
            .get("body")
            .unshiftContainer(
              "body",
              t.expressionStatement(
                t.callExpression(
                  t.memberExpression(
                    t.identifier("console"),
                    t.identifier("log")
                  ),
                  [t.stringLiteral(`call ${path.node.id.name}`)]
                )
              )
            );
        }
      },
    },
  };
};

위의 AST와 같이 비교해 보면

  • FunctionDeclaration 노드가 생성되면 호출되도록 메서드를 등록했다.
  • path.node.id.name(함수 이름)이 on으로 시작하는지 확인한다.
  • path의 body를 가져온다
  • BlockStatement의 body의 앞쪽에 노드를 추가하기 위해 unShiftContainer 호출
  • 위의 console.log의 AST를 만들어서 body 앞쪽에 삽입

실행

babel.config.js

const plugins = [
  "./plugins/insert-log.js",
];

module.exports = { plugins };

src/consoleCode.js

const v1 = 123;
function onClick(e) {
  const v = e.target.value;
}
function add(a, b) {
  return a + b;
}

npx babel src/consoleCode.js

결과

const v1 = 123;
function onClick(e) {
  console.log("call onClick");
  const v = e.target.value;
}
function add(a, b) {
  return a + b;
}

📌 이번에 해본 FunctionDeclaration, ExpressionStatement이외에도 다양한 노드 들이 많기 때문에 필요할떄 마다 공식문서를 보면서 해야 할 것 같다.

참고 : 실전 리액트 프로그래밍
https://babeljs.io/

0개의 댓글