vite plugin 만들면서 이틀 날렸던 원인
3 minute read
2024-07-17
ast 파싱을 위해 acorn 과 babel 을 계속 사용했다. 근데 문제는 내가 원하는 JSXAttribute 가 확인이 안되는 것이였다.
결론적으로 가장 중요한 설정을 누락해서였다.
export function myPlugin(): Plugin {
return {
name: 'my-plugin',
enforce: 'pre',
// ...
}
}다른 플러그인 보다 먼저 처리되도록 우선순위를 높여야 했다.
(하도 안되서 잠시 미쳤었다…)

이젠 제대로 된 설정을 했으니 자세한 코드를 봐보자.
Plugin
export default defineConfig({
plugins: [react(), myPlugin()],
});vite 플러그인은 기본적으로 왼쪽에서 오른쪽으로 차례대로 실행된다.
transform hook
코드에 대한 접근을 위해서는 transform 훅을 사용해야한다. 이름은 변환과 밀접한 훅이지만, AST 구조체 단위로 접근하기 편리하다.
이처럼 훅 설정을 해준다.
export function myPlugin() {
name: 'my-plugin',
transform(code: string, id: string) {
// ...
},
}상세 로직
code 는 코드 문자 자체를 가지고 있고 id는 파일의 전체 (절대) 경로를 가지고 있다.
난 여기서 tsx 만 처리하기 위해 아래와 같은 분기를 태웠다.
if (!id.endsWith('.tsx')) {
return; // 변환 없이 코드 유지
}이제 핵심 로직이다.
export function findDataGTM(code: string): void {
const ast: ParseResult<File> = parse(code, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
traverse(ast, {
JSXAttribute(path: NodePath<JSXAttribute>): void {
const attrName: string = <string>path.node.name.name;
if (attrName !== 'data-gtm') {
return;
}
let attrValue = '';
if (isStringLiteralOfJSXAttr(path)) {
attrValue = path.node.value.value;
}
console.log({
attrName,
attrValue,
});
},
});
}여기서 이제 슬랙으로 노티를 준다거나 할 수 있을 듯 하다.
특이사항
import _traverse, { type NodePath } from '@babel/traverse';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const a = (_traverse as any).default;
const traverse: typeof _traverse = a;일단 @babel/traverse 의 타입이 올바르지 않다.
{
"compilerOptions": {
"esModuleInterop": false, // 기본값
}
}물론 설정을 참으로 해서