Babel插件,通过 AST 为元素添加 data-id 埋点
Babel 的工作流程是「解析(Parse)→转换(Transform)→生成(Generate)」,插件的核心是在「转换阶段」通过@babel/types(AST 节点工具)遍历 DOM 相关节点(如 JSXElement、Element),为其添加data-id属性。
本文环境是react+vite+pnpm
- 安装依赖
1 2
| pnpm add @babel/core @babel/types @babel/traverse --save-dev
|
- 插件核心代码(
babel-plugin-add-data-id.js)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import * as t from '@babel/types';
function generateDataId(node, path) { const componentName = path.findParent((p) => p.isJSXElement() && p.node.openingElement.name.name) ?.node.openingElement.name.name || 'unknown'; const nodeType = node.openingElement.name.name; const random = Math.random().toString(36).slice(2, 8); return `${componentName}-${nodeType}-${random}`; }
export default function (babelApi, options = { prefix: '' }) { const { types: t } = babelApi; return { visitor: { JSXElement(path) { const openingElement = path.node.openingElement; const ignoreTags = ['Fragment', 'br', 'hr']; const nodeName = openingElement.name.name; if (ignoreTags.includes(nodeName)) return;
const hasDataId = openingElement.attributes.some( (attr) => t.isJSXAttribute(attr) && attr.name.name === 'data-id' );
if (hasDataId) return;
const dataIdAttr = t.jsxAttribute( t.jsxIdentifier('data-id'), t.stringLiteral(`${options.prefix}${generateDataId(path.node, path)}`) ); openingElement.attributes.push(dataIdAttr); }, }, }; }
|
- 在
vite.config.ts中添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import addDataIdPlugin from './babel-plugin-add-data-id.js';
export default defineConfig({ plugins: [ react({ babel: { plugins: [[addDataIdPlugin, { prefix: 'track-' }]], }, }), ], });
|
- 验证是否有效
1 2 3 4 5
| <div id="root"> <div class="home" > <button >提交</button> </div> </div>
|
1 2 3 4 5
| <div id="root"> <div class="home" data-id="track-unknown-div-k53ym8"> <button data-id="track-div-button-gn0bwx">提交</button> </div> </div>
|