使用 Vue 开发 VS Code 插件前端页面(上)
本文的方案主要参考了这篇博客:
Vscode 的 extension webview 开发示例: Vue 和 React 实现 https://juejin.cn/post/7325132202970136585样例项目地址:
github | vscode-webview-with-vuehttps://github.com/HiMeditator/vscode-webview-with-vue
下篇链接:
使用 Vue 开发 VS Code 插件前端页面(下)https://blog.csdn.net/Hi_KER/article/details/147640591默认读者对 VS Code 插件开发有一定了解。如果对插件开发有不明白的内容,可以参考官方文档:VSCode Extension API。
前言
之前做 VS Code 插件时,webview 页面刚开始用 html+css+js 写,只要页面或逻辑稍微复杂一些修改和维护就会非常麻烦。因此对于页面较为复杂的插件,可以使用前端框架来简化页面的开发。在 VS Code 插件开发中,比较推荐的前端框架是 Vue 和 React。比如开源智能代码插件 Continue 的前端页面就是用 React 构建的。
在我第一次尝试用前端框架构建 webview 页面时,在网上找了好多博客,很多给的方法或是比较麻烦,或是根本无法实现。在根据网上内容摸索了一天后,我才基本整合出了一套适合自己的方法。整体方法主要参考了上面那篇博客,但是对博客的方案进行了较大修改和简化,对初学者来说应该会更简单。
说明
这一篇博客只是整个方案的一部分,介绍如何在同一个文件夹下构建插件子项目、和前端子项目,并让它们能独立运行起来。
这篇博客得到的项目为(注意是提交历史中的最早一次,不包含下节的内容): vscode-webview-with-vue | first commithttps://github.com/HiMeditator/vscode-webview-with-vue/tree/a495a3b5246e1da9b9dfca6161f07a0f0a0150f6经过这篇博客后得到的项目结构如下,其中红色加粗字体的文件是需要修改的。刚看到这幅图你可能会看不懂,先不要管这幅图,按博客的指导自己做一遍,在过程中可以回看这幅图,你应该就能慢慢明白每个文件的含义了。
背景知识
webview 的限制
首先需要知道 VS Code 插件中的 webview 页面和一般网页不同,有很多的限制,其中最重要的两点限制是:
-
资源加载限制:webview 默认情况下不允许加载外部资源,所有资源应该打包在你的扩展中,并通过 asWebViewUri 方法转换为正确的 URI 来引用
-
通信限制:webview 与 VS Code 扩展之间通过 postMessage API 进行通信,这意味着你不能直接调用 VS Code API,必须通过消息传递的方式来请求操作或获取数据(其实可以不使用提供的通信接口而采取其他方式,比如设置一个本地服务器或者使用 WebSocket 进行通信,但使用非标准的通信方法可能会导致代码更复杂,并且可能引入额外的风险)
pnpm 与 npm
本方案使用 pnpm 构建项目,因此需要了解 pnpm 和 npm 的基本概念及其区别:
npm(Node Package Manager) 是 Node.js 官方自带的包管理工具,广泛用于 JavaScript 项目的依赖安装、版本管理和模块分发。它通过将依赖包下载并存储在项目中的 node_modules 文件夹中来工作,默认情况下,每个项目都会独立地下载和保存所有依赖项,这可能会导致磁盘空间的浪费和重复下载。
pnpm(Performant npm) 是一个与 npm 兼容但更高效、快速的包管理器。它的核心优势在于采用了“硬链接”和“内容可寻址存储”的方式来管理依赖包。这意味着 pnpm 会将下载的包存储在全局仓库中,并在不同项目之间共享这些依赖,从而大幅减少磁盘占用并提升安装速度。此外,pnpm 在依赖结构上引入了“扁平化 + 虚拟化”的 node_modules 管理机制,避免了传统嵌套结构可能带来的问题,同时保持了良好的兼容性。
monorepo 的概念
Monorepo(Monolithic Repository 的缩写),即单体仓库,是一种软件开发实践,指的是将多个相关或独立的项目、库或者模块的所有源代码存放在一个单一的版本控制系统仓库中,而不是为每个项目或模块创建单独的仓库。我们要构建的项目就是 monorepo,其包含多个子项目(插件项目、前端项目)。
在 monorepo 项目中选择使用 pnpm 而不是 npm,主要是因为 pnpm 提供了一些针对 monorepo 优化的功能和特性,使得它在这种场景下比 npm 更具优势。
项目初始化
环境中没有 pnpm 的需要先安装:
npm install -g pnpm
首先创建项目文件夹,在项目文件夹中打开命令行,执行
pnpm init
可以看到文件夹中新增了 package.json 文件。
然后创建 pnpm-workspace.yaml 文件,写入如下内容:
packages:- 'packages/*'
该文件是 pnpm 包管理器中用于定义工作区(workspace)配置的文件。写入的内容告诉 pnpm 在 packages 文件夹下每一个子文件夹都是一个独立的包,
然后创建 packages 文件夹,该文件夹用于存放每个子项目。 完成后项目结构如下:
创建插件子项目
进入 packages 文件夹,创建插件项目,参考的执行过程如下:
PS D:\Projects\vscode-webview-with-vue> cd .\packages
PS D:\Projects\vscode-webview-with-vue\packages> yo code_-----_ ╭──────────────────────────╮| | │ Welcome to the Visual │|--(o)--| │ Studio Code Extension │`---------´ │ generator! │( _´U`_ ) ╰──────────────────────────╯/___A___\ /| ~ | __'.___.'__ ´ ` |° ´ Y ` ? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? extension-example
? What's the identifier of your extension? extension-example
? What's the description of your extension?
? Initialize a git repository? No
? Which bundler to use? webpack
? Which package manager to use? pnpm
在 packages 文件夹执行 yo code 来构建插件,注意构建选项中不要选择创建 git 仓库,打包工具选择 webpack,包管理工具选择 pnpm。
创建好后在根目录执行 pnpm install 安装依赖。
配置插件子项目
修改启动路径
创建好插件项目后,将插件项目的 .vscode 文件夹移动到项目根目录下。
然后修改 .vscode/launch.json 中的路径,将 args 和 outFiles 中的路径中新增 /packages/[name],其中 [name] 是你插件项目的名称。修改路径的位置有两处,具体添加的位置如下图所示。
对于上述操作,移动 .vscode 文件夹到根目录是为了能在根目录对插件项目进行操作,修改路径是因为移动的配置文件的位置所以需要调整。
修改插件入口路径
打开插件文件夹下的 webpack.config.js 文件,修改 output 中的 path 属性,添加一个子文件夹,名称可以自己定。如下图。
打开插件文件夹下的 package.json 文件,修改 main 属性中的路径,同样改为添加了子文件夹后的路径,如下图。
经过上面的操作,插件构建时将打包到插件文件夹下的 /dist/extension 文件夹中,这样做的原因是后面前端代码也会打包到这个 /dist 文件夹,因此需要建立子文件夹,保证构建的结构性。
添加调试指令
打开项目根目录下的 package.json 文件,在 scripts 中新增 watch 指令,其中 [name] 是插件名称。
"watch": "pnpm run -F [name] watch"
通过上述操作,在项目根目录下执行 pnpm watch 实际上会执行插件项目中的 watch 脚本。
尝试运行插件
完成上述操作后,尝试运行插件(Windows 用户按 F5,或者在上方菜单找到 Run -> Start Debugging 选项运行)。如果配置正确,那么插件即可正常运行。
创建 Vue 前端子项目
注意 WebView 和 WbeView View 是不同的概念,前者的页面是在编辑器(Editor)区域显示的,而后者是在主侧边栏(Primary Sidebar)或次侧边栏(Secondary Sidebar)或面板(Panel)中显示的。你需要根据需要创建前端子项目,如果你的插件只需要其中一种页面,创建一个就行了。
创建 Webview 前端子项目
这个子项目是用于编辑器区的页面的。
在 packages 文件夹下执行:
pnpm create vue@latest
构建 Vue3 项目,注意构建选项中不要选择 Router,因为不建议在 VS Code 插件页面中使用路由。一方面是使用路由可能导致 webview 资源载入不正确;另一方面插件开发本来就是要页面尽量简洁,没有使用路由的必要,可以用其他方案代替。
一个供参考的构建选项,注意构建选项中需要选择 Pinia,因为后续与插件通信需要用到。
PS D:\Projects\vscode-webview-with-vue\packages> pnpm create vue@latest
┌ Vue.js - The Progressive JavaScript Framework
│
◇ Project name (target directory):
│ gui-webview
│
◆ Select features to include in your project: (↑/↓ to navigate, space to select, a to toggle all, enter to confirm)
│ ◼ TypeScript
│ ◻ JSX Support
│ ◻ Router (SPA development)
│ ◼ Pinia (state management)
│ ◻ Vitest (unit testing)
│ ◻ End-to-End Testing
│ ◻ ESLint (error prevention)
│ ◻ Prettier (code formatting)
└
创建好后在根目录执行 pnpm install 安装依赖。
创建 Webview View 前端子项目
这个子项目是用于侧边栏或面板的。
创建过程同上。创建好后在根目录执行 pnpm install 安装依赖。
创建好之后,现在的项目结构如下:
配置 Vue 前端子项目
修改构建目标路径
打开 Vue 前端子项目的 vite.config.ts 文件,按下图进行修改。一个是注释掉 vueDevTools(不使用 vue 提供的调试工具,可选)。另一个是修改构建路径为插件目录下的 /dist 文件夹下的子文件夹,可以自行命名,这里使用的名称为该前端项目的名称: gui-webview。
如果你创建了两个前端子项目,另一个子项目也进行类似的操作即可,注意构建文件夹不要重名。
添加启动和构建指令
打开根目录下的 package.json 文件,添加前端子项目的启动和构建指令,其中 [proj0] 和 [proj1] 分别是你对两个前端子项目的命名。
"dev:0": "pnpm run -F [proj0] dev",
"dev:1": "pnpm run -F [proj1] dev",
"build:0": "pnpm run -F [proj0] build",
"build:1": "pnpm run -F [proj1] build",
"build": "pnpm build:0 && pnpm build:1",
添加了上述五条指令后,你可以使用 pnpm dev:0 或 pnpm dev:1 启动第一个或第二个前端项目。使用 pnpm build:0 或 pnpm build:1 打包第一个或第二个前端项目。或者使用 pnpm build 同时打包两个前端项目。
检验是否成功
在根目录执行 pnpm dev:0 或 pnpm dev:1 看是否能启动前端项目:
在根目录执行 pnpm build 看插件目录下的 dist 文件夹下是否有前端项目构建的子目录:
总结
经过上面的操作,你已经得到了处于同一个文件夹下的能分别独立运行的插件和前端页面子项目,且它们构建好的内容也在同一个文件夹下:插件文件夹下的 dist 文件夹。看到这里你可以回看一下前面的项目结构图,现在你应该对它有了更深入的了解。
这篇博客得到的项目为(注意是提交历史中的最早一次,不包含下节的内容):
vscode-webview-with-vue | first commithttps://github.com/HiMeditator/vscode-webview-with-vue/tree/a495a3b5246e1da9b9dfca6161f07a0f0a0150f6下节将介绍如何将构建的前端页面嵌入插件以及前端页面和插件的通信。