Vite插件在build时如何修改React组件的输出内容?

南宫一涵 阅读 74

我在开发Vite插件时遇到了问题,想在构建阶段自动给所有React组件添加跟踪代码。按照文档写了transform函数,但build时提示”Unexpected token”,代码根本没生效:


export default vitePlugin = () => ({
  transform(code, id) {
    if (id.endsWith('.jsx')) {
      return `
        console.log('Tracking:', ${id});
        ${code}
      `
    }
  }
})

尝试过用模板字符串拼接,但生成的JS里直接出现组件JSX结构,比如某个按钮组件的build输出变成了:


console.log('Tracking: ./Button.jsx');
function Button() {
  return ; // 这里报Unexpected token <
}

难道transform返回的代码没有经过JSX转换?应该怎样正确修改组件内容同时保持Vite的默认处理流程?

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
UE丶莉霞
你这个问题,是因为直接返回的 JSX 没有经过 Babel 或 TypeScript 的解析,导致构建失败。应该用 @vitejs/plugin-react 或者 @babel/parser 来处理 JSX,然后再注入代码。

正确做法是写个插件,在 transform 阶段用 parser 把 code 转成 AST,然后在合适的位置插入 log,最后返回处理后的 code。直接拼字符串是行不通的。

下面是一个简单的修改方式:

import { parse } from '@babel/parser';
import traverse from '@babel/traverse';
import generate from '@babel/generator';
import * as t from '@babel/types';

export default function reactTrackPlugin() {
return {
name: 'react-track',
transform(code, id) {
if (!id.endsWith('.jsx')) return;

const ast = parse(code, {
sourceType: 'module',
plugins: ['jsx'],
});

traverse.default(ast, {
FunctionDeclaration(path) {
const funcName = path.node.id.name;
const insertCode = t.expressionStatement(
t.callExpression(t.identifier('console.log'), [
t.stringLiteral(Tracking: ${id} - ${funcName}),
])
);
path.node.body.body.unshift(insertCode);
},
});

return generate.default(ast).code;
},
};
}
点赞 10
2026-02-03 15:02
百里冬冬
你遇到的问题是因为在 transform 阶段直接修改代码时,没有考虑到 JSX 的预处理流程。Vite 会先通过插件链对代码进行处理,而 JSX 转换是在特定阶段完成的。如果你直接拼接字符串,生成的代码可能会绕过这个转换过程,导致报错。

正确的做法是使用 Vite 提供的 @vitejs/plugin-react 中的 JSX 转换器,或者直接引入 Babel 来处理 JSX。你可以这样改写你的插件:

import { babel } from '@rollup/plugin-babel';

export default function vitePlugin() {
return {
name: 'vite-plugin-tracking',
transform(code, id) {
if (id.endsWith('.jsx')) {
const trackingCode =
console.log('Tracking:', ${JSON.stringify(id)});
;

// 拼接跟踪代码
const modifiedCode = ${trackingCode}n${code};

// 使用 Babel 转换 JSX
const result = babel.transform(modifiedCode, {
presets: ['@babel/preset-react'],
filename: id,
});

return result.code;
}
},
};
}


关键点:
1. 使用 Babel 处理 JSX,确保生成的代码能正确编译。
2. 拼接代码时要注意,id 是字符串,需要用 JSON.stringify 包裹,否则会变成变量引用。
3. 这样做不会打断 Vite 的默认处理流程,同时让你可以安全地注入自定义代码。

另外提醒一下,如果组件很多,这种方式可能会稍微增加构建时间。如果性能是个问题,可以考虑更细粒度地选择需要注入跟踪代码的文件。
点赞 9
2026-01-31 09:02