分析结论
非 setup 的 <script lang="ts"> 在 sourcemap 生成时会产生冲突。具体原因如下:
根本原因
当一个 .vue 文件使用 <script lang="ts">(非 setup)时,Vite 的处理链路是:
@vitejs/plugin-vue先将.vue文件拆分为 template、script、style 三个虚拟模块- template 部分编译后会生成 render 函数,其 sourcemap 指向原始
.vue文件 - script 部分(
<script lang="ts">)需要经过 TypeScript 编译,其 sourcemap 也指向原始.vue文件 - 最终 rollup 在
traceMappings()中合并 sourcemap 时,发现同一个源文件(index.vue)对应了两份不同的sourcesContent——一份来自 template 的 transform,一份来自 script 的 TypeScript transform
关键代码在 rollup 的 traceMappings() 中(第 20113-20114 行):
js
else if (content != null && sourcesContent[sourceIndex] !== content) {
return error(logConflictingSourcemapSources(filename));
}当同一个 filename 被两个不同的 transform 链处理后,产生了不同的 sourcesContent,就会触发这个错误。
为什么 <script setup lang="ts"> 不会报错?
<script setup> 的编译方式不同——setup script 会被 @vitejs/plugin-vue 在 SFC 编译阶段一起处理(template 和 script 合并编译),生成的是一个统一的 sourcemap,不会出现同一个源文件有多份不同 content 的情况。
为什么 pvp-next 不报错?
pvp-next 的 vue 文件全部使用的是 <script>(纯 JS,不带 lang="ts"),不需要经过 TypeScript 编译这一步,所以不会产生额外的 sourcemap transform 链,自然不会出现冲突。
对比总结
| 对比项 | val-match-next | pvp-next |
|---|---|---|
| script 类型 | <script lang="ts"> (15个) + <script setup lang="ts"> (41个) | <script> (纯 JS) |
| TS 编译 | 需要额外的 TS transform | 不需要 |
| sourcemap 冲突 | ✅ template + TS 两条链产生不同 content | ❌ 只有一条链 |
解决方案
有以下几种方式:
方案一(最简单):在
vite.config.ts中关闭 sourcemaptsbuildOptions: { sourcemap: false }方案二(推荐,保留 sourcemap 功能):将报错的
<script lang="ts">改为<script setup lang="ts">,这样 SFC 编译器会统一处理 template 和 script 的 sourcemap