English | 中文
Use
vue/reactto develop vscode extension webview, supportingesmandcjs.
During development, inject code into both vscode extension code and web page code to support HMR; during production builds, inject the final generated index.html code into the vscode extension code to minimize manual effort.
- Use tsdown to quickly build
extension code - Simple configuration, focus on business
- Support
esmandcjs - Support ESM extension (vscode
v1.100.0+) - Support webview
HMR - Support
acquireVsCodeApiof @types/vscode-webview - Support Multi-Page App
- Supports
vueandreactand other frameworks supported byvite
The NodeJS extension host now (v1.100.0+) supports extensions that use JavaScript-modules (ESM). All it needs is the "type": "module" entry in your extension's package.json file. With that, the JavaScript code can use import and export statements, including the special module 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 -DSetting recommended will modify some preset configurations. See PluginOptions and recommended parameter descriptions in detail.
- By default,
recommended:truewill be based on the following directory structure as a convention.
|--extension // extension code
| |--index.ts
|--src // front-end code
| |--App.vue
| |--main.ts
|--index.html
- Zero configuration, default dist output directory
|--dist
| |--extension
| | |--index.js
| | |--index.js.map
| |--webview
| | |--index.html
- If you want to modify the
extensionsource code directory tosrc, you can set{ extension: { entry: 'src/index.ts' } }
|--src // extension code
| |--index.ts
|--webview // front-end code
| |--App.vue
| |--main.ts
|--index.html
code snippet, more code see examples
const panel = window.createWebviewPanel('showHelloWorld', 'Hello World', ViewColumn.One, {
enableScripts: true,
localResourceRoots: [Uri.joinPath(extensionUri, 'dist/webview')],
});
// Vite development mode and production mode inject different webview codes to reduce development work
panel.webview.html = __getWebviewHtml__({
// vite dev mode
serverUrl: process.env.VITE_DEV_SERVER_URL,
// vite prod mode
webview,
context,
inputName: 'index',
injectCode: `<script>window.__FLAG1__=666;window.__FLAG2__=888;</script>`,
});package.json
{
"main": "dist/extension/index.js"
}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(),
// Modify the extension source code entry path, and also modify the `index.html` entry file path
// vscode({ extension: { entry: 'src/index.ts' } }),
],
});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()],
});See vue-import example
vite.config.ts
import path from 'node:path';
import vscode from '@tomjs/vite-plugin-vscode';
import { defineConfig } from 'vite';
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')],
// You can also customize the name
// input:{
// 'index': path.resolve(__dirname, 'index.html'),
// 'index2': path.resolve(__dirname, 'index2.html'),
// }
},
},
});- page one
__getWebviewHtml__({
// vite dev mode
serverUrl: process.env.VITE_DEV_SERVER_URL,
// vite prod mode
webview,
context,
});- page two
__getWebviewHtml__({
// vite dev mode
serverUrl: `${process.env.VITE_DEV_SERVER_URL}/index2.html`,
// vite prod mode
webview,
context,
inputName: 'index2',
});- A single page uses different parameters to achieve different functions
__getWebviewHtml__({
// vite dev mode
serverUrl: `${process.env.VITE_DEV_SERVER_URL}?id=666`,
// vite prod mode
webview,
context,
injectCode: `<script>window.__id__=666;</script>`,
});getWebviewHtml Description
interface WebviewHtmlOptions {
/**
* `[vite serve]` The url of the vite dev server. Please use `process.env.VITE_DEV_SERVER_URL`
*/
serverUrl?: string;
/**
* `[vite build]` The Webview instance of the extension.
*/
webview: Webview;
/**
* `[vite build]` The ExtensionContext instance of the extension.
*/
context: ExtensionContext;
/**
* `[vite build]` vite build.rollupOptions.input name. Default is `index`.
*/
inputName?: string;
/**
* `[vite build]` Inject code into the afterbegin of the head element.
*/
injectCode?: string;
}
/**
* Gets the html of webview
*/
function __getWebviewHtml__(options?: WebviewHtmlOptions): string;When using the acquireVsCodeApi().getState() method of @types/vscode-webview, you must use await to call it. Since acquireVsCodeApi is a simulated implementation of this method by the plugin, it is inconsistent with the original method. I am very sorry. If you have other solutions, please share them. Thank you very much.
const value = await acquireVsCodeApi().getState();- index.d.ts provided by unpkg.com.
| Property | Type | Default | Description |
|---|---|---|---|
| recommended | boolean |
true |
This option is intended to provide recommended default parameters and behavior. |
| extension | ExtensionOptions | Configuration options for the vscode extension. | |
| webview | boolean | string | WebviewOption |
__getWebviewHtml__ |
Inject html code |
| devtools | boolean |
true |
Inject script code for react-devtools or vue-devtools debugging |
The recommended option is used to set the default configuration and behavior, which can be used with almost zero configuration. The default is true. If you want to customize the configuration, set it to false. The following default prerequisites are to use the recommended project structure.
- The output directory is based on the
build.outDirparameter ofvite, and outputsextensionandsrctodist/extensionanddist/webviewrespectively. - Other behaviors to be implemented
Inject @tomjs/vscode-extension-webview into vscode extension code and web client code, so that webview can support HMR during the development stage.
- vite serve
- extension: Inject
import __getWebviewHtml__ from '@tomjs/vite-plugin-vscode/webview';at the top of the file that calls the__getWebviewHtml__method - web: Add
<script>tag to index.html and inject@tomjs/vite-plugin-vscode/clientcode
- extension: Inject
- vite build
- extension: Inject
import __getWebviewHtml__ from '@tomjs/vite-plugin-vscode-inject';at the top of the file that calls the__getWebviewHtml__method
- extension: Inject
If is string, will set inject method name. Default is __getWebviewHtml__.
During development, support standalone development tool applications for react and vue, enabled by default.
react: inject<script src="http://localhost:8097"></script>, support react-devtoolsvue: inject<script src="http://localhost:8098"></script>, support vue-devtools
Based on Options of tsdown, some default values are added for ease of use.
| Property | Type | Default | Description |
|---|---|---|---|
| entry | string |
extension/index.ts |
The vscode extension entry file. |
| outDir | string |
dist-extension/main |
The output directory for the vscode extension file |
| watchFiles | string/string[] |
`` | Watch extension code files during development |
| Property | Type | Default | Description |
|---|---|---|---|
| name | string |
__getWebviewHtml__ |
The inject method name |
| csp | string |
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';"> |
The CSP meta for the webview |
{{cspSource}}: webview.cspSource{{nonce}}: uuid
- Default values for
extensionwhen the relevant parameters are not configured
| Parameter | Development Mode Default | Production Mode Default |
|---|---|---|
| sourcemap | true |
false |
| minify | false |
true |
vscode extension use.
developmentmode
| Variable | Description |
|---|---|
VITE_DEV_SERVER_URL |
The url of the vite dev server |
productionmode
| Variable | Description |
|---|---|
VITE_WEBVIEW_DIST |
vite webview page output path |
Run Debug Extension through vscode to debug. For debugging tools, refer to Official Documentation
launch.json is configured as follows:
{
"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 is configured as follows:
{
"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": []
}
]
}First execute the following command to install dependencies and generate library files:
pnpm install
pnpm buildOpen the examples directory, there are vue and react examples.
- react: Simple react example.
- vue: Simple vue example.
- vue-esm: Simple vue (ESM Extension) example.
- vue-import: Dynamic import() and multi-page examples.
- @tomjs/vscode: Some utilities to simplify the development of VSCode Extensions.
- @tomjs/vscode-dev: Some development tools to simplify the development of vscode extensions.
- @tomjs/vscode-webview: Optimize the
postMessageissue betweenwebviewpage and vscode extensions
Breaking Updates:
- Using tsdown instead of tsup, the vscode extension extension configuration is changed to inherit tsdown.
Breaking Updates:
- Merge the
__getWebviewHtml__method for development and production into one, see getWebviewHtml
Breaking Updates:
- The simulated
acquireVsCodeApiis consistent with theacquireVsCodeApiof @types/vscode-webview, andsessionStorage.getItemandsessionStorage.setItemare used to implementgetStateandsetState.