VS Code扩展Webview中tsvscode未定义问题排查与解决求助
VS Code扩展开发:Webview中tsvscode未定义错误排查与解决
问题场景
使用TypeScript+Svelte开发VS Code扩展,点击Webview内按钮时触发两类问题:
- Webview控制台错误:
Uncaught ReferenceError: tsvscode is not defined at HTMLButtonElement.click_handler (sidebar.js:619:4)
- 编译时Svelte插件警告:
Plugin svelte: 'tsvscode' is not defined webviews/components/Sidebar.svelte 35: <input bind:value={text} placeholder="Enter text" /> 36: <button on:click={()=>{ 37: tsvscode.postMessage({type:"onInfo",value:"ok"}); 38: }}>Show info</button>
相关代码片段
Sidebar.svelte
<script lang="ts"> let text=''; </script> <style> .main-container{ height: 98vh; width: 100%; display: flex; flex-direction: column; } .output-container{ border: 1px solid black; border-radius: 10px; margin-bottom: 10px; padding: 10px; height: 100%; } .input-container{ bottom: 0; width: 100%; } input{ margin-bottom: 10px; } </style> <div class="main-container"> <div class="output-container"> Your text will appear here: {text} </div> <div class="input-container"> <input bind:value={text} placeholder="Enter text" /> <button on:click={()=>{ tsvscode.postMessage({type:"onInfo",value:"ok"}); }}>Show info</button> </div> </div>
SidebarProvider.ts
import * as vscode from "vscode"; import { getNonce } from "./getNonce"; import { apiUrl } from "./constants"; export class SidebarProvider implements vscode.WebviewViewProvider { _view?: vscode.WebviewView; _doc?: vscode.TextDocument; constructor(private readonly _extensionUri: vscode.Uri) {} public resolveWebviewView(webviewView: vscode.WebviewView) { this._view = webviewView; webviewView.webview.options = { enableScripts: true, localResourceRoots: [this._extensionUri], }; webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); webviewView.webview.onDidReceiveMessage(async (data) => { switch (data.type) { case "onInfo": { if (!data.value) { return; } vscode.window.showInformationMessage(data.value); break; } case "onError": { if (!data.value) { return; } vscode.window.showErrorMessage(data.value); break; } } }); } public revive(panel: vscode.WebviewView) { this._view = panel; } private _getHtmlForWebview(webview: vscode.Webview) { const styleResetUri = webview.asWebviewUri( vscode.Uri.joinPath(this._extensionUri, "media", "reset.css") ); const scriptUri = webview.asWebviewUri( vscode.Uri.joinPath(this._extensionUri, "out", "compiled/sidebar.js") ); const styleMainUri = webview.asWebviewUri( vscode.Uri.joinPath(this._extensionUri, "out", "compiled/bundle.css") ); const styleVSCodeUri = webview.asWebviewUri( vscode.Uri.joinPath(this._extensionUri, "media", "vscode.css") ); const nonce = getNonce(); return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="Content-Security-Policy" content="img-src https: data:; style-src 'unsafe-inline' ${webview.cspSource}; script-src 'nonce-${nonce}';"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="${styleResetUri}" rel="stylesheet"> <link href="${styleVSCodeUri}" rel="stylesheet"> <link href="${styleMainUri}" rel="stylesheet"> <script nonce ="${getNonce}"> const tsvscode = acquireVsCodeApi(); </script> </head> <body> <script nonce="${nonce}" src="${scriptUri}"></script> </body> </html>`; } }
globals.d.ts
import * as _vscode from "vscode"; declare global { const tsvscode:{ postMessage: ({type: string, value:any})=>void; }; }
错误原因分析
- CSP脚本阻止:
SidebarProvider.ts中创建tsvscode的脚本标签使用了${getNonce}(仅函数引用,未执行获取值),导致脚本的nonce值与CSP声明的nonce-${nonce}不匹配,浏览器直接阻止该脚本执行,tsvscode全局变量未被初始化。 - 类型定义未被识别:
globals.d.ts的全局变量声明未被TypeScript编译器纳入编译范围,导致Svelte组件无法识别tsvscode的类型,触发未定义警告。
解决方法
1. 修正HTML中的nonce值
在SidebarProvider.ts的_getHtmlForWebview方法里,将创建tsvscode的脚本标签修改为:
<script nonce="${nonce}"> const tsvscode = acquireVsCodeApi(); </script>
替换后脚本使用已生成的nonce变量,与CSP策略中的值一致,浏览器允许脚本执行,tsvscode变量正常初始化。
2. 确保全局类型定义被识别
修改项目根目录的tsconfig.json,将globals.d.ts加入include数组:
{ "compilerOptions": { // 原有配置 }, "include": [ "src/**/*", "webviews/**/*", "globals.d.ts" // 添加该行,路径根据实际位置调整 ] }
3. 临时方案(可选)
如果类型定义仍未生效,可在Sidebar.svelte的script标签中显式声明:
<script lang="ts"> let text=''; declare const tsvscode: { postMessage: ({type: string, value: any}) => void; }; </script>
推荐优先使用tsconfig.json的方式,保证全局类型统一。
验证
重新编译并启动扩展,点击Webview内的「Show info」按钮,VS Code会弹出信息提示,Webview控制台无报错,编译时也不会出现Svelte插件警告。
内容的提问来源于stack exchange,提问作者Ppp
相关产品推荐
相关产品推荐

