Vite中Rollup插件Transform时SourceMap不匹配的解决方法
我正在开发一款用于Vite构建的Rollup插件,目的是在构建过程中动态转换文件。使用transform(code: string, id: string)方法能正常完成代码转换,但构建时会出现转换后文件SourceMap不匹配的警告。根据Rollup文档,转换代码时需要手动创建SourceMap,于是我尝试用magic-string来生成映射,但最终Bundle的SourceMap始终不包含转换后的文件状态映射——传递自己生成的map和返回null效果一样,要么保留原文件映射,要么完全丢失转换后的映射。
我的插件代码如下:
export default function () { return { name: 'exclude-msw', transform(code: string, id: string) { if (id.match(/main\.ts/)) { const s = new MagicString(code) // 我的转换逻辑——本质是从文件中移除一段代码 // ... const map = s.generateMap({ source: id, file: id + '.map', includeContent: true }) return { code: s.toString(), map: map.toString() } } } } }
Rollup文档提到:
如果转换没有移动代码,可以返回
null来保留现有sourcemap:
return { code: transformedCode, map: null };
但不管是返回自己生成的map还是null,都无法得到包含转换后状态的SourceMap,请问该如何解决?
问题出在两个关键地方:
SourceMap格式错误:Rollup的
transform钩子要求返回的map是符合SourceMap规范的对象,而你把magic-string生成的map对象转成了JSON字符串(map.toString()),这会导致Rollup无法正确解析这个映射,相当于没有传递有效的SourceMap,效果自然和返回null一致。generateMap参数配置不当:
file参数不需要手动设置为id + '.map',这个参数应该指向转换后代码对应的map文件名,Rollup会自动处理映射文件的关联,手动设置反而可能导致路径不匹配。
修改后的插件代码:
export default function () { return { name: 'exclude-msw', transform(code: string, id: string) { if (id.match(/main\.ts/)) { const s = new MagicString(code) // 你的转换逻辑 // ... const map = s.generateMap({ source: id, includeContent: true, // 移除file参数,让Rollup自动处理 hires: true // 可选,生成高精度映射 }) // 直接返回map对象,不要转成字符串 return { code: s.toString(), map: map } } } } }
如果你的项目基于Vite,还可以额外处理source路径,将其转为相对于项目根目录的路径(避免绝对路径导致的映射异常):
// 在transform函数内 const relativeId = this.resolveId(id)?.id || id; // 然后在generateMap中设置source: relativeId
这样修改后,Rollup就能正确识别你生成的SourceMap,最终的Bundle映射会包含转换后的文件状态,同时消除SourceMap不匹配的警告。
内容的提问来源于stack exchange,提问作者Guy Passy

