@tomjs/vite-plugin-vscode
v5.1.0
Published
Use vue/react to develop 'vscode extension webview', supporting esm/cjs
Maintainers
Readme
@tomjs/vite-plugin-vscode
English | 中文
用
vue/react来开发 vscode extension webview ,支持esm和cjs。
在开发模式时,给 vscode 扩展代码 和 web 页面代码中注入代码,用来支持 HMR;生产构建时,将最终生成的index.html 代码注入到 vscode 扩展代码 中,减少工作量。
特性
- 使用 tsdown 快速构建
扩展代码 - 配置简单,专注业务
- 支持
esm和cjs - 支持 ESM 扩展(vscode
v1.100.0+) - 支持 webview
HMR - 支持 @types/vscode-webview 的
acquireVsCodeApi - 支持多页面应用
- 支持
vue、react等其他vite支持的框架
ESM 扩展
NodeJS 扩展现在(v1.100.0+)支持使用 JavaScript 模块 (ESM) 的扩展。它只需要在扩展的 package.json 文件中添加 "type": "module" 条目即可。这样,JavaScript 代码就可以使用 import 和 export 语句,包括特殊的模块 import('vscode')
安装
# pnpm
pnpm add @tomjs/vite-plugin-vscode -D
# yarn
yarn add @tomjs/vite-plugin-vscode -D
# npm
npm i @tomjs/vite-plugin-vscode -D使用说明
推荐约定
设置 recommended 参数会修改一些预置配置,详细查看 PluginOptions 和 recommended 参数说明。
目录结构
- 默认情况下,
recommended:true会根据如下目录结构作为约定
|--extension // extension code
| |--index.ts
|--src // front-end code
| |--App.vue
| |--main.ts
|--index.html- 零配置,默认 dist 输出目录
|--dist
| |--extension
| | |--index.js
| | |--index.js.map
| |--webview
| | |--index.html- 如果你想修改
extension源码目录为src,可以设置{ extension: { entry: 'src/index.ts' } }
|--src // extension code
| |--index.ts
|--webview // front-end code
| |--App.vue
| |--main.ts
|--index.htmlextension
代码片段,更多配置看示例
const panel = window.createWebviewPanel('showHelloWorld', 'Hello World', ViewColumn.One, {
enableScripts: true,
localResourceRoots: [Uri.joinPath(extensionUri, 'dist/webview')],
});
// vite 开发模式和生产模式注入不同的webview代码,减少开发工作
panel.webview.html = __getWebviewHtml__({
// vite 开发模式
serverUrl: process.env.VITE_DEV_SERVER_URL,
// vite 生产模式
webview,
context,
inputName: 'index',
injectCode: `<script>window.__FLAG1__=666;window.__FLAG2__=888;</script>`,
});package.json
{
"main": "dist/extension/index.js"
}vue
vite.config.ts
import vscode from '@tomjs/vite-plugin-vscode';
import vue from '@vitejs/plugin-vue';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag: string) => tag.startsWith('vscode-'),
},
},
}),
vscode(),
// 修改扩展源码入口路径,同时修改`index.html`入口文件路径
// vscode({ extension: { entry: 'src/index.ts' } }),
],
});react
vite.config.ts
import vscode from '@tomjs/vite-plugin-vscode';
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), vscode()],
});getWebviewHtml
可查看 vue-import 示例
vite.config.ts
import path from 'node:path';
import vscode from '@tomjs/vite-plugin-vscode';
export default defineConfig({
plugins: [vscode()],
build: {
rollupOptions: {
// https://cn.vitejs.dev/guide/build.html#multi-page-app
input: [path.resolve(__dirname, 'index.html'), path.resolve(__dirname, 'index2.html')],
// 也可自定义名称
// input:{
// 'index': path.resolve(__dirname, 'index.html'),
// 'index2': path.resolve(__dirname, 'index2.html'),
// }
},
},
});- 页面一
__getWebviewHtml__({
// vite 开发模式
serverUrl: process.env.VITE_DEV_SERVER_URL,
// vite 生产模式
webview,
context,
});- 页面二
__getWebviewHtml__({
// vite 开发模式
serverUrl: `${process.env.VITE_DEV_SERVER_URL}/index2.html`,
// vite 生产模式
webview,
context,
inputName: 'index2',
});- 单个页面通过不同参数来实现不同功能
__getWebviewHtml__({
// vite 开发模式
serverUrl: `${process.env.VITE_DEV_SERVER_URL}?id=666`,
// vite 生产模式
webview,
context,
injectCode: `<script>window.__id__=666;</script>`,
});getWebviewHtml 说明
interface WebviewHtmlOptions {
/**
* `[vite serve]` vite开发服务器的url, 请用 `process.env.VITE_DEV_SERVER_URL`
*/
serverUrl?: string;
/**
* `[vite build]` 扩展的 Webview 实例
*/
webview: Webview;
/**
* `[vite build]` 扩展的 ExtensionContext 实例
*/
context: ExtensionContext;
/**
* `[vite build]` vite build.rollupOptions.input 设置的名称. 默认 `index`.
*/
inputName?: string;
/**
* `[vite build]` 向 head 元素的结束前注入代码 <head>--inject--
*/
injectCode?: string;
}
/**
* 获取webview的html
*/
function __getWebviewHtml__(options?: WebviewHtmlOptions): string;警告
使用 @types/vscode-webview 的 acquireVsCodeApi().getState() 方法时,要使用 await 调用。由于 acquireVsCodeApi 是插件对该方法的模拟实现,故与原方法出现不一致性,非常抱歉。如果有其他方案,请分享,非常感谢。
const value = await acquireVsCodeApi().getState();文档
- unpkg.com 提供的 index.d.ts.
参数
PluginOptions
| 参数名 | 类型 | 默认值 | 说明 |
| ----------- | -------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| recommended | boolean | true | 这个选项是为了提供推荐的默认参数和行为 |
| extension | ExtensionOptions | | vscode extension 可选配置 |
| webview | boolean | string | WebviewOption | __getWebviewHtml__ | 注入 html 代码 |
| devtools | boolean | true | 注入 script 代码用于 react-devtools 或 vue-devtools 调试 |
Notice
recommended 选项用于设置默认配置和行为,几乎可以达到零配置使用,默认为 true 。如果你要自定义配置,请设置它为false。以下默认的前提条件是使用推荐的 项目结构。
输出目录根据
vite的build.outDir参数, 将extension、src分别输出到dist/extension、dist/webview其他待实现的行为
Webview
在 vscode 扩展代码和 web 客户端代码中注入 @tomjs/vscode-extension-webview,使 webview 在开发阶段能够支持 HMR。
- vite serve
- extension: 在调用
__getWebviewHtml__方法的文件顶部注入import __getWebviewHtml__ from '@tomjs/vscode-extension-webview'; - web: 在 index.html 中添加
<script>标签,注入@tomjs/vscode-extension-webview/client代码
- extension: 在调用
- vite build
- extension: 在调用
__getWebviewHtml__方法的文件顶部注入import __getWebviewHtml__ from '@tomjs/vite-plugin-vscode-inject';
- extension: 在调用
如果为字符串,则设置注入方法名,默认为 __getWebviewHtml__。
devtools
开发阶段,支持 react 和 vue 的独立开发工具应用,默认开启。
react: 注入<script src="http://localhost:8097"></script>,支持 react-devtoolsvue: 注入<script src="http://localhost:8098"></script>,支持 vue-devtools
ExtensionOptions
继承自 tsdown 的 Options,添加了一些默认值,方便使用。
| 参数名 | 类型 | 默认值 | 说明 |
| ---------- | -------------------- | --------------------- | ------------------------ |
| entry | string | extension/index.ts | 入口文件 |
| outDir | string | dist-extension/main | 输出文件夹 |
| watchFiles | string/string[] | `` | 开发时监听扩展代码的文件 |
WebviewOption
| 参数名 | 类型 | 默认值 | 说明 |
| ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| name | string | __getWebviewHtml__ | 注入的方法名 |
| csp | string | <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';"> | webview 的 CSP |
{{cspSource}}: webview.cspSource{{nonce}}: uuid
补充说明
extension未配置相关参数时的默认值
| 参数 | 开发模式默认值 | 生产模式默认值 |
| --------- | -------------- | -------------- |
| sourcemap | true | false |
| minify | false | true |
环境变量
vscode extension 使用
development模式
| 变量 | 描述 |
| --------------------- | ------------------- |
| VITE_DEV_SERVER_URL | vite开发服务器的url |
production模式
| 变量 | 描述 |
| ------------------- | ------------------------- |
| VITE_WEBVIEW_DIST | vite webview 页面输出路径 |
Debug
扩展调试
通过 vscode 运行 Debug Extension 调试,调试工具参考 官方文档
launch.json 配置如下:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Extension",
"type": "extensionHost",
"request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/extension/*.js"],
"preLaunchTask": "npm: dev"
},
{
"name": "Preview Extension",
"type": "extensionHost",
"request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/extension/*.js"],
"preLaunchTask": "npm: build"
}
]
}tasks.json 配置如下:
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "dev",
"problemMatcher": {
"owner": "typescript",
"fileLocation": "relative",
"pattern": {
"regexp": "^([a-zA-Z]\\:/?([\\w\\-]/?)+\\.\\w+):(\\d+):(\\d+): (ERROR|WARNING)\\: (.*)$",
"file": 1,
"line": 3,
"column": 4,
"code": 5,
"message": 6
},
"background": {
"activeOnStart": true,
"beginsPattern": "^.*extension build start*$",
"endsPattern": "^.*extension (build|rebuild) success.*$"
}
},
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]
}网页调试
可以使用 react-devtools 和 vue-devtools 的独立应用调试 webview
示例
先执行以下命令安装依赖,并生成库文件:
pnpm install
pnpm build打开 examples 目录,有 vue 和 react 示例。
- react:简单的 react 示例。
- vue:简单的 vue 示例。
- vue-esm:简单的 vue(ESM 扩展)示例。
- vue-import:动态 import() 和多页面示例。
关联
- @tomjs/vscode: 一些实用工具,用于简化 vscode 扩展 的开发。
- @tomjs/vscode-dev: 一些开发工具,用于简化 vscode 扩展 的开发。
- @tomjs/vscode-webview: 优化
webview页面与 vscode 扩展 的postMessage问题
重要说明
v5.0.0
破坏性更新:
v4.0.0
破坏性更新:
- 开发和生产的
__getWebviewHtml__方法合并为同一个,参考 getWebviewHtml
v3.0.0
破坏性更新:
- 模拟的
acquireVsCodeApi与 @types/vscode-webview 的acquireVsCodeApi保持一致,改用sessionStorage.getItem和sessionStorage.setItem来实现getState和setState。
