VS Code 插件 Webview 本地文件链接修复记录



VS Code 插件 Webview 本地文件链接修复记录


1. 问题现象

在 VS Code 的某 AI 插件 Webview 中,回复里的本地文件链接点击后没有走编辑器内的 open-file 能力,而是被当成普通网页链接打开浏览器,表现为跳转到类似下面的地址:

1
https://file+.vscode-resource.vscode-cdn.net/c%3A/Users/...

这会导致以下文件引用无法正常在编辑器内跳转。以下为路径示例:

1
2
3
4
5
c:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go#L17
C:\Users\<USER>\<WORKSPACE>\internal\module\example_file.go:73
/C:/Users/<USER>/<WORKSPACE>/internal/http/example_test.go:1
file:///C:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go#L71
c%3A/Users/<USER>/<WORKSPACE>/internal/module/example_file.go#L25


2. 根因分析

问题不是单点故障,而是两层处理叠加导致:

  1. 本地文件路径格式不统一
  2. Markdown 渲染阶段过早改写了本地文件 href

具体来说:

  1. 本地文件路径格式不统一
    Webview 里的文件引用可能以 c:/C:\/C:/file:///C:/c%3A/... 等不同形式出现,原始解析逻辑没有先做 Windows 路径规范化。

  2. Markdown 渲染阶段过早改写了本地文件 href
    在文件链接被 renderPromptLink -> FileLink -> open-file 接管之前,urlTransform 已经先把它按普通链接处理并改写,因此点击时直接走浏览器。

结论:仅修复文件引用解析函数还不够,必须同时修复 urlTransform 对本地文件链接的判定。


3. 修复方案

本次修复直接修改已安装扩展的 Webview bundle。以下安装路径已脱敏:

1
C:\Users\<USER>\.vscode\extensions\<publisher>.<extension>-<version>\webview\assets\markdown-*.js

并保留原始备份:

1
C:\Users\<USER>\.vscode\extensions\<publisher>.<extension>-<version>\webview\assets\markdown-*.js.bak

修复分为两部分。

3.1 增加 Windows 本地文件引用规范化

新增 normalizeWindowsFileReference(),在 parseFileReference 的入口统一处理:

  • decodeURIComponent
  • file:///C:/... 去协议头
  • /C:/... 去前导斜杠
  • C:\... 转成 C:/...

这样文件引用在进入后续判断前会被统一成可识别的本地路径。

3.2 修改 kT(),阻止本地文件链接被改写成浏览器 URL

原逻辑只对 apppluginagent 之类的特殊链接保留原始 href
修复后把 _b(e)vb(e) 识别出的本地文件链接也纳入保留范围,避免它们被 Xc(e) 转成 vscode-resource 风格 URL。


4. 证据代码

以下证据来自修复后的 bundle 文件。

4.1 文件引用解析入口已经增加 Windows 路径规范化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function normalizeWindowsFileReference(e){
let t=e.replace(/`/g,'').trim();
try{t=decodeURIComponent(t)}catch{}
let n=t.toLowerCase();
return n.startsWith('file:///')&&(t=t.slice(8)),
/^\/[A-Za-z]:[\\/]/.test(t)&&(t=t.replace(/^\/+/g,'')),
/^[A-Za-z]:[\\/]/.test(t)&&(t=t.replace(/\\/g,'/')),
t
}

function pb(e){
let t=normalizeWindowsFileReference(e),n=t.match(...)
...
}

说明:pb() 即文件引用解析入口,修复后不再直接对原始字符串做正则匹配,而是先做规范化。

4.2 文件链接识别逻辑本身存在,并最终走 open-file

1
2
3
4
5
6
7
8
function Qw({className:e,cwd:t,elementKey:n,href:r,label:i}){
...
if(_b(r)||vb(r)){
let i=pb(r),o=mb(i);
return (0,V.jsx)(yb,{...})
}
return null
}
1
2
3
4
5
function wb(e){
let {...,path:o,line:s,column:l,cwd:u}=e,d=Ke(`open-file`)
...
d.mutate({path:o,line:s,column:e,cwd:u})
}

说明:这证明插件本身已经有“识别文件链接并调用 open-file”的能力,问题不在跳转能力缺失,而在前序处理把链接提前改坏了。

4.3 关键修复点:kT() 现在对本地文件链接保留原始 href

修复后的代码:

1
2
3
4
5
6
function kT(e,t,n){
return t===`href`&&n.tagName===`a`&&(q_(e)||X_(e)||J_(e)||Y_(e)||_b(e)||vb(e))
|| t===`src`&&n.tagName===`img`&&(uT.test(e)||et(e))
? e
: Xc(e)
}

关键变化是新增:

1
||_b(e)||vb(e)

说明:这一步让本地文件链接不再被 Xc(e) 改写,从而能够继续流入 Qw(),最终由 open-file 打开。


5. 验证结果

已验证以下输入都可以被解析为统一的本地文件路径,并保留行号。以下样例均已脱敏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
c:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go#L17
=> {"path":"c:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go","line":17}

c%3A/Users/<USER>/<WORKSPACE>/internal/module/example_file.go#L17
=> {"path":"c:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go","line":17}

C:\Users\<USER>\<WORKSPACE>\internal\module\example_file.go:25
=> {"path":"C:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go","line":25}

/C:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go:31
=> {"path":"C:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go","line":31}

file:///C:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go#L71
=> {"path":"C:/Users/<USER>/<WORKSPACE>/internal/module/example_file.go","line":71}

实际操作上,在执行 Developer: Reload Window 后,点击 Webview 中的本地文件链接,已经能够回到 VS Code 内部打开文件,而不再跳转浏览器。


6. 回滚方式

如果后续扩展升级或补丁需要撤回,直接用备份文件覆盖:

1
2
3
4
5
源文件:
C:\Users\<USER>\.vscode\extensions\<publisher>.<extension>-<version>\webview\assets\markdown-*.js.bak

目标文件:
C:\Users\<USER>\.vscode\extensions\<publisher>.<extension>-<version>\webview\assets\markdown-*.js


7. 结论

这次问题的本质是:

  • Windows 本地文件路径格式不统一
  • Webview 的 URL 转换流程对本地文件链接处理顺序不正确

最终有效修复不是单纯“增强文件路径解析”,而是同时修正:

  • 文件路径规范化入口
  • Markdown href 的 URL 保留策略

只有两者一起改,文件链接才能稳定落到 open-file,而不是被浏览器接管。