@tomjs/vite-plugin-vscode 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,17 +4,18 @@
4
4
 
5
5
  **English** | [中文](./README.zh_CN.md)
6
6
 
7
- > The [vite](https://cn.vitejs.dev/) plugin for [vscode extension](https://code.visualstudio.com/api), supports `esm` and `cjs`.
7
+ > Use `vue`/`react` to develop [vscode extension webview](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel), supporting `esm` and `cjs`.
8
8
 
9
- Inject [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview) into vscode extension code and web client code, so that webview can support HMR during the development stage.
9
+ In development mode, inject the code of [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview) into `vscode extension code` and `web page code`, use To support `HMR`; during production build, the final generated `index.html` code is injected into `vscode extension code` to reduce the workload.
10
10
 
11
11
  ## Features
12
12
 
13
- - Fast build `extension` with [tsup](https://github.com/egoist/tsup)
14
- - Little configuration, focus on business
13
+ - Use [tsup](https://github.com/egoist/tsup) to quickly build `extension code`
14
+ - Simple configuration, focus on business
15
15
  - Support `esm` and `cjs`
16
16
  - Support webview `HMR`
17
- - Support `vue` and `react` and other [frameworks](https://vitejs.dev/guide/#trying-vite-online) supported by `vite`
17
+ - Support [Multi-Page App](https://vitejs.dev/guide/build.html#multi-page-app)
18
+ - Supports `vue` and `react` and other [frameworks](https://cn.vitejs.dev/guide/#trying-vite-online) supported by `vite`
18
19
 
19
20
  ## Install
20
21
 
@@ -75,39 +76,11 @@ const panel = window.createWebviewPanel('showHelloWorld', 'Hello World', ViewCol
75
76
  enableScripts: true,
76
77
  localResourceRoots: [Uri.joinPath(extensionUri, 'dist/webview')],
77
78
  });
78
- ```
79
-
80
- ```ts
81
- private _getWebviewContent(webview: Webview, extensionUri: Uri) {
82
- // The CSS file from the Vue build output
83
- const stylesUri = getUri(webview, extensionUri, ['dist', 'webview', 'assets', 'index.css']);
84
- // The JS file from the Vue build output
85
- const scriptUri = getUri(webview, extensionUri, ['dist', 'webview', 'assets', 'index.js']);
86
-
87
- const nonce = uuid();
88
-
89
- if (process.env.VITE_DEV_SERVER_URL) {
90
- return __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL);
91
- }
92
79
 
93
- // Tip: Install the es6-string-html VS Code extension to enable code highlighting below
94
- return /*html*/ `
95
- <!doctype html>
96
- <html lang="en">
97
- <head>
98
- <meta charset="UTF-8" />
99
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
100
- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
101
- <script type="module" crossorigin nonce="${nonce}" src="${scriptUri}"></script>
102
- <link rel="stylesheet" crossorigin href="${stylesUri}">
103
- <title>Hello World</title>
104
- </head>
105
- <body>
106
- <div id="app"></div>
107
- </body>
108
- </html>
109
- `;
110
- }
80
+ // Vite development mode and production mode inject different webview codes to reduce development work
81
+ panel.webview.html = process.env.VITE_DEV_SERVER_URL
82
+ ? __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL)
83
+ : __getWebviewHtml__(webview, context);
111
84
  ```
112
85
 
113
86
  - `package.json`
@@ -157,6 +130,70 @@ export default defineConfig({
157
130
  });
158
131
  ```
159
132
 
133
+ ### Multi-page application
134
+
135
+ See [vue-import](./examples/vue-import) example
136
+
137
+ - `vite.config.ts`
138
+
139
+ ```ts
140
+ import path from 'node:path';
141
+ import vscode from '@tomjs/vite-plugin-vscode';
142
+
143
+ export default defineConfig({
144
+ build: {
145
+ plugins: [vscode()]
146
+ rollupOptions: {
147
+ // https://cn.vitejs.dev/guide/build.html#multi-page-app
148
+ input: [path.resolve(__dirname, 'index.html'), path.resolve(__dirname, 'index2.html')],
149
+ // You can also customize the name
150
+ // input:{
151
+ // 'index': path.resolve(__dirname, 'index.html'),
152
+ // 'index2': path.resolve(__dirname, 'index2.html'),
153
+ // }
154
+ },
155
+ },
156
+ });
157
+ ```
158
+
159
+ - page one
160
+
161
+ ```ts
162
+ process.env.VITE_DEV_SERVER_URL
163
+ ? __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL)
164
+ : __getWebviewHtml__(webview, context);
165
+ ```
166
+
167
+ - page two
168
+
169
+ ```ts
170
+ process.env.VITE_DEV_SERVER_URL
171
+ ? __getWebviewHtml__(`${process.env.VITE_DEV_SERVER_URL}/index2.html`)
172
+ : __getWebviewHtml__(webview, context, 'index2');
173
+ ```
174
+
175
+ **getWebviewHtml** Description
176
+
177
+ ```ts
178
+ /**
179
+ * `[vite serve]` Gets the html of webview in development mode.
180
+ * @param options serverUrl: The url of the vite dev server.
181
+ */
182
+ function __getWebviewHtml__(options?: string | { serverUrl: string }): string;
183
+
184
+ /**
185
+ * `[vite serve]` Gets the html of webview in production mode.
186
+ * @param webview The WebviewPanel instance of the extension.
187
+ * @param context The ExtensionContext instance of the extension.
188
+ * @param inputName vite build.rollupOptions.input name. Default is `index`.
189
+ */
190
+ function __getWebviewHtml__(
191
+ webview: Webview,
192
+ context: ExtensionContext,
193
+ inputName?: string,
194
+ ): string;
195
+ ```
196
+
160
197
  ## Documentation
161
198
 
162
199
  - [API Documentation](https://paka.dev/npm/@tomjs/vite-plugin-vscode) provided by [paka.dev](https://paka.dev).
@@ -206,15 +243,15 @@ Based on [Options](https://paka.dev/npm/tsup) of [tsup](https://tsup.egoist.dev/
206
243
 
207
244
  - `development` mode
208
245
 
209
- | Variable | Description |
210
- | --------------------- | ------------------------------- |
211
- | `VITE_DEV_SERVER_URL` | The url of the vite dev server. |
246
+ | Variable | Description |
247
+ | --------------------- | ------------------------------ |
248
+ | `VITE_DEV_SERVER_URL` | The url of the vite dev server |
212
249
 
213
250
  - `production` mode
214
251
 
215
- | Variable | Description |
216
- | --- | --- |
217
- | `VITE_DIST_FILES` | All js files in the dist directory, excluding index.js. It's to be a json string. |
252
+ | Variable | Description |
253
+ | ------------------- | ----------------------------- |
254
+ | `VITE_WEBVIEW_DIST` | vite webview page output path |
218
255
 
219
256
  ## Debug
220
257
 
@@ -232,7 +269,15 @@ Run `Debug Extension` through `vscode` to debug. For debugging tools, refer to [
232
269
  "request": "launch",
233
270
  "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
234
271
  "outFiles": ["${workspaceFolder}/dist/extension/*.js"],
235
- "preLaunchTask": "${defaultBuildTask}"
272
+ "preLaunchTask": "npm: dev"
273
+ },
274
+ {
275
+ "name": "Preview Extension",
276
+ "type": "extensionHost",
277
+ "request": "launch",
278
+ "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
279
+ "outFiles": ["${workspaceFolder}/dist/extension/*.js"],
280
+ "preLaunchTask": "npm: build"
236
281
  }
237
282
  ]
238
283
  }
@@ -272,6 +317,15 @@ Run `Debug Extension` through `vscode` to debug. For debugging tools, refer to [
272
317
  "kind": "build",
273
318
  "isDefault": true
274
319
  }
320
+ },
321
+ {
322
+ "type": "npm",
323
+ "script": "build",
324
+ "group": {
325
+ "kind": "build",
326
+ "isDefault": true
327
+ },
328
+ "problemMatcher": []
275
329
  }
276
330
  ]
277
331
  }
@@ -288,6 +342,6 @@ pnpm build
288
342
 
289
343
  Open the [examples](./examples) directory, there are `vue` and `react` examples.
290
344
 
291
- - [react](./examples/react): simple react example.
292
- - [vue](./examples/vue): simple vue example.
293
- - [vue-import](./examples/vue-import): dynamic import() example.
345
+ - [react](./examples/react): Simple react example.
346
+ - [vue](./examples/vue): Simple vue example.
347
+ - [vue-import](./examples/vue-import): Dynamic import() and multi-page examples.
package/README.zh_CN.md CHANGED
@@ -4,17 +4,18 @@
4
4
 
5
5
  [English](./README.md) | **中文**
6
6
 
7
- > [vscode extension](https://code.visualstudio.com/api) 的 [vite](https://cn.vitejs.dev/) 插件,支持 `esm` 和 `cjs`。
7
+ > 用 `vue`/`react` 来开发 [vscode extension webview](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel) ,支持 `esm` 和 `cjs`。
8
8
 
9
- vscode 扩展代码和 web 客户端代码中注入 [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview),可以让 webview 在开发阶段支持 `HMR`
9
+ 在开发模式时,给 `vscode 扩展代码` 和 `web 页面代码`中注入 [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview) 的代码,用来支持 `HMR`;生产构建时,将最终生成的`index.html` 代码注入到 `vscode 扩展代码` 中,减少工作量。
10
10
 
11
11
  ## 特性
12
12
 
13
- - 使用 [tsup](https://github.com/egoist/tsup) 快速构建 `main` 和 `preload`
13
+ - 使用 [tsup](https://github.com/egoist/tsup) 快速构建 `扩展代码`
14
14
  - 配置简单,专注业务
15
15
  - 支持 `esm`和 `cjs`
16
16
  - 支持 webview `HMR`
17
- - 支持 `vue` 和 `react` 等其他 `vite` 支持的[框架](https://cn.vitejs.dev/guide/#trying-vite-online)
17
+ - 支持[多页面应用](https://cn.vitejs.dev/guide/build.html#multi-page-app)
18
+ - 支持 `vue` 、`react` 等其他 `vite` 支持的[框架](https://cn.vitejs.dev/guide/#trying-vite-online)
18
19
 
19
20
  ## 安装
20
21
 
@@ -75,39 +76,15 @@ const panel = window.createWebviewPanel('showHelloWorld', 'Hello World', ViewCol
75
76
  enableScripts: true,
76
77
  localResourceRoots: [Uri.joinPath(extensionUri, 'dist/webview')],
77
78
  });
78
- ```
79
-
80
- ```ts
81
- private _getWebviewContent(webview: Webview, extensionUri: Uri) {
82
- // The CSS file from the Vue build output
83
- const stylesUri = getUri(webview, extensionUri, ['dist/webview/assets/index.css']);
84
- // The JS file from the Vue build output
85
- const scriptUri = getUri(webview, extensionUri, ['dist/webview/assets/index.js']);
86
79
 
87
- const nonce = uuid();
88
-
89
- if (process.env.VITE_DEV_SERVER_URL) {
90
- return __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL);
91
- }
80
+ // vite 开发模式和生产模式注入不同的webview代码,减少开发工作
81
+ function getHtml(webview: Webview, context: ExtensionContext) {
82
+ process.env.VITE_DEV_SERVER_URL
83
+ ? __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL)
84
+ : __getWebviewHtml__(webview, context);
85
+ }
92
86
 
93
- // Tip: Install the es6-string-html VS Code extension to enable code highlighting below
94
- return /*html*/ `
95
- <!doctype html>
96
- <html lang="en">
97
- <head>
98
- <meta charset="UTF-8" />
99
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
100
- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
101
- <script type="module" crossorigin nonce="${nonce}" src="${scriptUri}"></script>
102
- <link rel="stylesheet" crossorigin href="${stylesUri}">
103
- <title>Hello World</title>
104
- </head>
105
- <body>
106
- <div id="app"></div>
107
- </body>
108
- </html>
109
- `;
110
- }
87
+ panel.webview.html = getHtml(webview, context);
111
88
  ```
112
89
 
113
90
  - `package.json`
@@ -157,6 +134,70 @@ export default defineConfig({
157
134
  });
158
135
  ```
159
136
 
137
+ ### **getWebviewHtml**
138
+
139
+ 可查看 [vue-import](./examples/vue-import) 示例
140
+
141
+ - `vite.config.ts`
142
+
143
+ ```ts
144
+ import path from 'node:path';
145
+ import vscode from '@tomjs/vite-plugin-vscode';
146
+
147
+ export default defineConfig({
148
+ build: {
149
+ plugins: [vscode()]
150
+ rollupOptions: {
151
+ // https://cn.vitejs.dev/guide/build.html#multi-page-app
152
+ input: [path.resolve(__dirname, 'index.html'), path.resolve(__dirname, 'index2.html')],
153
+ // 也可自定义名称
154
+ // input:{
155
+ // 'index': path.resolve(__dirname, 'index.html'),
156
+ // 'index2': path.resolve(__dirname, 'index2.html'),
157
+ // }
158
+ },
159
+ },
160
+ });
161
+ ```
162
+
163
+ - 页面一
164
+
165
+ ```ts
166
+ process.env.VITE_DEV_SERVER_URL
167
+ ? __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL)
168
+ : __getWebviewHtml__(webview, context);
169
+ ```
170
+
171
+ - 页面二
172
+
173
+ ```ts
174
+ process.env.VITE_DEV_SERVER_URL
175
+ ? __getWebviewHtml__(`${process.env.VITE_DEV_SERVER_URL}/index2.html`)
176
+ : __getWebviewHtml__(webview, context, 'index2');
177
+ ```
178
+
179
+ **getWebviewHtml** 说明
180
+
181
+ ```ts
182
+ /**
183
+ * `[vite serve]` 在开发模式获取webview的html
184
+ * @param options serverUrl: vite开发服务器的url
185
+ */
186
+ function __getWebviewHtml__(options?: string | { serverUrl: string }): string;
187
+
188
+ /**
189
+ * `[vite serve]` 在生产模式获取webview的html
190
+ * @param webview 扩展的 Webview 实例
191
+ * @param context 扩展的 ExtensionContext 实例
192
+ * @param inputName vite build.rollupOptions.input 设置的名称. 默认 `index`.
193
+ */
194
+ function __getWebviewHtml__(
195
+ webview: Webview,
196
+ context: ExtensionContext,
197
+ inputName?: string,
198
+ ): string;
199
+ ```
200
+
160
201
  ## 文档
161
202
 
162
203
  - [paka.dev](https://paka.dev) 提供的 [API文档](https://paka.dev/npm/@tomjs/vite-plugin-vscode).
@@ -205,15 +246,15 @@ export default defineConfig({
205
246
 
206
247
  - `development` 模式
207
248
 
208
- | 变量 | 描述 |
209
- | --------------------- | --------------------- |
210
- | `VITE_DEV_SERVER_URL` | vite开发服务器的url |
249
+ | 变量 | 描述 |
250
+ | --------------------- | ------------------- |
251
+ | `VITE_DEV_SERVER_URL` | vite开发服务器的url |
211
252
 
212
253
  - `production` 模式
213
254
 
214
- | 变量 | 描述 |
215
- | ----------------- | --------------------------------------------------------------- |
216
- | `VITE_DIST_FILES` | dist目录下的所有js文件,不包括index.js。 它是一个 json 字符串。 |
255
+ | 变量 | 描述 |
256
+ | ------------------- | ------------------------- |
257
+ | `VITE_WEBVIEW_DIST` | vite webview 页面输出路径 |
217
258
 
218
259
  ## Debug
219
260
 
@@ -231,7 +272,15 @@ export default defineConfig({
231
272
  "request": "launch",
232
273
  "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
233
274
  "outFiles": ["${workspaceFolder}/dist/extension/*.js"],
234
- "preLaunchTask": "${defaultBuildTask}"
275
+ "preLaunchTask": "npm: dev"
276
+ },
277
+ {
278
+ "name": "Preview Extension",
279
+ "type": "extensionHost",
280
+ "request": "launch",
281
+ "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
282
+ "outFiles": ["${workspaceFolder}/dist/extension/*.js"],
283
+ "preLaunchTask": "npm: build"
235
284
  }
236
285
  ]
237
286
  }
@@ -271,6 +320,15 @@ export default defineConfig({
271
320
  "kind": "build",
272
321
  "isDefault": true
273
322
  }
323
+ },
324
+ {
325
+ "type": "npm",
326
+ "script": "build",
327
+ "group": {
328
+ "kind": "build",
329
+ "isDefault": true
330
+ },
331
+ "problemMatcher": []
274
332
  }
275
333
  ]
276
334
  }
@@ -289,4 +347,4 @@ pnpm build
289
347
 
290
348
  - [react](./examples/react):简单的 react 示例。
291
349
  - [vue](./examples/vue):简单的 vue 示例。
292
- - [vue-import](./examples/vue-import):动态 import() 示例。
350
+ - [vue-import](./examples/vue-import):动态 import() 和多页面示例。
package/dist/index.d.mts CHANGED
@@ -43,19 +43,23 @@ interface PluginOptions {
43
43
  /**
44
44
  * Inject [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview) into vscode extension code and web client code, so that webview can support HMR during the development stage.
45
45
  *
46
- * * extension: Inject `import getDevWebviewHtml from '@tomjs/vscode-extension-webview';` above the file that calls the `getDevWebviewHtml` method
47
- * * web: Add `<script>` tag to index.html and inject `@tomjs/vscode-extension-webview/client` code
46
+ * * vite serve
47
+ * * extension: Inject `import __getWebviewHtml__ from '@tomjs/vscode-extension-webview';` above the file that calls the `__getWebviewHtml__` method
48
+ * * web: Add `<script>` tag to index.html and inject `@tomjs/vscode-extension-webview/client` code
49
+ * * vite build
50
+ * * extension: Inject `import __getWebviewHtml__ from '@tomjs/vite-plugin-vscode-inject';` above the file that calls the `__getWebviewHtml__` method
48
51
  *
49
- * If is string, will set inject method name. Default is 'getDevWebviewHtml'.
52
+ * If is string, will set inject method name. Default is '__getWebviewHtml__'.
50
53
  *
51
54
  * @example
52
55
  * extension file
53
56
  * ```ts
54
- * if(process.env.VITE_DEV_SERVER_URL){
55
- * webview.html = getDevWebviewHtml(process.env.VITE_DEV_SERVER_URL)
56
- * } else {
57
- * webview.html = `<html></html>`
58
- * }
57
+ *function setupHtml(webview: Webview, context: ExtensionContext) {
58
+ * if (process.env.VITE_DEV_SERVER_URL) {
59
+ * return __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL);
60
+ * }
61
+ * return __getWebviewHtml__(webview, context);
62
+ *}
59
63
  * ```
60
64
  * webview client
61
65
  * ```html
package/dist/index.d.ts CHANGED
@@ -43,19 +43,23 @@ interface PluginOptions {
43
43
  /**
44
44
  * Inject [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview) into vscode extension code and web client code, so that webview can support HMR during the development stage.
45
45
  *
46
- * * extension: Inject `import getDevWebviewHtml from '@tomjs/vscode-extension-webview';` above the file that calls the `getDevWebviewHtml` method
47
- * * web: Add `<script>` tag to index.html and inject `@tomjs/vscode-extension-webview/client` code
46
+ * * vite serve
47
+ * * extension: Inject `import __getWebviewHtml__ from '@tomjs/vscode-extension-webview';` above the file that calls the `__getWebviewHtml__` method
48
+ * * web: Add `<script>` tag to index.html and inject `@tomjs/vscode-extension-webview/client` code
49
+ * * vite build
50
+ * * extension: Inject `import __getWebviewHtml__ from '@tomjs/vite-plugin-vscode-inject';` above the file that calls the `__getWebviewHtml__` method
48
51
  *
49
- * If is string, will set inject method name. Default is 'getDevWebviewHtml'.
52
+ * If is string, will set inject method name. Default is '__getWebviewHtml__'.
50
53
  *
51
54
  * @example
52
55
  * extension file
53
56
  * ```ts
54
- * if(process.env.VITE_DEV_SERVER_URL){
55
- * webview.html = getDevWebviewHtml(process.env.VITE_DEV_SERVER_URL)
56
- * } else {
57
- * webview.html = `<html></html>`
58
- * }
57
+ *function setupHtml(webview: Webview, context: ExtensionContext) {
58
+ * if (process.env.VITE_DEV_SERVER_URL) {
59
+ * return __getWebviewHtml__(process.env.VITE_DEV_SERVER_URL);
60
+ * }
61
+ * return __getWebviewHtml__(webview, context);
62
+ *}
59
63
  * ```
60
64
  * webview client
61
65
  * ```html
package/dist/index.js CHANGED
@@ -4,10 +4,12 @@ var _path = require('path'); var _path2 = _interopRequireDefault(_path);
4
4
  var _process = require('process');
5
5
  var _lodashclonedeep = require('lodash.clonedeep'); var _lodashclonedeep2 = _interopRequireDefault(_lodashclonedeep);
6
6
  var _lodashmerge = require('lodash.merge'); var _lodashmerge2 = _interopRequireDefault(_lodashmerge);
7
+ var _nodehtmlparser = require('node-html-parser');
7
8
  var _tsup = require('tsup');
8
9
 
9
10
  // src/constants.ts
10
11
  var PLUGIN_NAME = "@tomjs:vscode";
12
+ var PACKAGE_NAME = "@tomjs/vite-plugin-vscode";
11
13
  var WEBVIEW_PACKAGE_NAME = "@tomjs/vscode-extension-webview";
12
14
  var WEBVIEW_METHOD_NAME = "__getWebviewHtml__";
13
15
 
@@ -61,6 +63,12 @@ function readJson(path2) {
61
63
  return JSON.parse(_fs2.default.readFileSync(path2, "utf8"));
62
64
  }
63
65
  }
66
+ function emptyPath(dest) {
67
+ if (_fs2.default.existsSync(dest)) {
68
+ _fs2.default.rmSync(dest, { recursive: true });
69
+ }
70
+ _fs2.default.mkdirSync(dest, { recursive: true });
71
+ }
64
72
  function resolveHostname(hostname) {
65
73
  const loopbackHosts = /* @__PURE__ */ new Set([
66
74
  "localhost",
@@ -152,12 +160,69 @@ function preMergeOptions(options) {
152
160
  opts.webview = _nullishCoalesce(opts.webview, () => ( WEBVIEW_METHOD_NAME));
153
161
  return opts;
154
162
  }
155
- function readAllFiles(dir) {
156
- return _fs2.default.readdirSync(dir).reduce((files, file) => {
157
- const name = _path2.default.join(dir, file);
158
- const isDir = _fs2.default.statSync(name).isDirectory();
159
- return isDir ? [...files, ...readAllFiles(name)] : [...files, name];
160
- }, []);
163
+ var prodCachePkgName = `${PACKAGE_NAME}-inject`;
164
+ function genProdWebviewCode(cache) {
165
+ const prodCacheFolder = _path2.default.join(_process.cwd.call(void 0, ), "node_modules", prodCachePkgName);
166
+ emptyPath(prodCacheFolder);
167
+ const destFile = _path2.default.join(prodCacheFolder, "index.ts");
168
+ function handleHtmlCode(html) {
169
+ const root = _nodehtmlparser.parse.call(void 0, html);
170
+ const head = root.querySelector("head");
171
+ if (!head) {
172
+ root == null ? void 0 : root.insertAdjacentHTML("beforeend", "<head></head>");
173
+ }
174
+ head.insertAdjacentHTML(
175
+ "afterbegin",
176
+ `
177
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';">`
178
+ );
179
+ const tags = {
180
+ script: "src",
181
+ link: "href"
182
+ };
183
+ Object.keys(tags).forEach((tag) => {
184
+ const elements = root.querySelectorAll(tag);
185
+ elements.forEach((element) => {
186
+ const attr = element.getAttribute(tags[tag]);
187
+ if (attr) {
188
+ element.setAttribute(tags[tag], `{{baseUri}}${attr}`);
189
+ }
190
+ element.setAttribute("nonce", "{{nonce}}");
191
+ });
192
+ });
193
+ return root.toString();
194
+ }
195
+ const cacheCode = (
196
+ /* js */
197
+ `const htmlCode = {
198
+ ${Object.keys(cache).map((s) => `${s}: \`${handleHtmlCode(cache[s])}\`,`).join("\n")}
199
+ };`
200
+ );
201
+ const code = (
202
+ /* js */
203
+ `import { ExtensionContext, Uri, Webview } from 'vscode';
204
+
205
+ ${cacheCode}
206
+
207
+ function uuid() {
208
+ let text = '';
209
+ const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
210
+ for (let i = 0; i < 32; i++) {
211
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
212
+ }
213
+ return text;
214
+ }
215
+
216
+ export default function getWebviewHtml(webview: Webview, context: ExtensionContext, inputName?:string){
217
+ const nonce = uuid();
218
+ const baseUri = webview.asWebviewUri(Uri.joinPath(context.extensionUri, (process.env.VITE_WEBVIEW_DIST || 'dist')));
219
+ const html = htmlCode[inputName || 'index'] || '';
220
+ return html.replaceAll('{{cspSource}}',webview.cspSource).replaceAll('{{nonce}}', nonce).replaceAll('{{baseUri}}', baseUri);
221
+ }
222
+ `
223
+ );
224
+ _fs2.default.writeFileSync(destFile, code, { encoding: "utf8" });
225
+ return destFile.replaceAll("\\", "/");
161
226
  }
162
227
  function useVSCodePlugin(options) {
163
228
  const opts = preMergeOptions(options);
@@ -208,6 +273,7 @@ function useVSCodePlugin(options) {
208
273
  }
209
274
  }
210
275
  let buildConfig;
276
+ const prodHtmlCache = {};
211
277
  return [
212
278
  {
213
279
  name: "@tomjs:vscode",
@@ -275,26 +341,63 @@ function useVSCodePlugin(options) {
275
341
  {
276
342
  name: "@tomjs:vscode",
277
343
  apply: "build",
344
+ enforce: "post",
278
345
  config(config) {
279
346
  return handleConfig(config);
280
347
  },
281
348
  configResolved(config) {
282
349
  buildConfig = config;
283
350
  },
351
+ transformIndexHtml(html, ctx) {
352
+ var _a;
353
+ if (!opts.webview) {
354
+ return html;
355
+ }
356
+ prodHtmlCache[(_a = ctx.chunk) == null ? void 0 : _a.name] = html;
357
+ return html;
358
+ },
284
359
  closeBundle() {
285
- const { outDir } = buildConfig.build;
286
- const cwd2 = process.cwd();
287
- const allFiles = readAllFiles(outDir).filter((file) => file.endsWith(".js") && !file.endsWith("index.js")).map((s) => s.replace(cwd2, "").replaceAll("\\", "/").substring(1));
360
+ let webviewPath;
361
+ if (opts.webview) {
362
+ webviewPath = genProdWebviewCode(prodHtmlCache);
363
+ }
364
+ let outDir = buildConfig.build.outDir.replace(_process.cwd.call(void 0, ), "").replaceAll("\\", "/");
365
+ if (outDir.startsWith("/")) {
366
+ outDir = outDir.substring(1);
367
+ }
368
+ const env = {
369
+ NODE_ENV: buildConfig.mode || "production",
370
+ VITE_WEBVIEW_DIST: outDir
371
+ };
372
+ logger.info("extension build start");
288
373
  const { onSuccess: _onSuccess, ...tsupOptions } = opts.extension || {};
289
374
  _tsup.build.call(void 0,
290
375
  _lodashmerge2.default.call(void 0, tsupOptions, {
291
- env: {
292
- VITE_DIST_FILES: JSON.stringify(allFiles)
293
- },
376
+ env,
377
+ silent: true,
378
+ esbuildPlugins: !opts.webview ? [] : [
379
+ {
380
+ name: "@tomjs:vscode:inject",
381
+ setup(build) {
382
+ build.onLoad({ filter: /\.ts$/ }, async (args) => {
383
+ const file = _fs2.default.readFileSync(args.path, "utf-8");
384
+ if (file.includes(`${opts.webview}(`)) {
385
+ return {
386
+ contents: `import ${opts.webview} from \`${webviewPath}\`;
387
+ ` + file,
388
+ loader: "ts"
389
+ };
390
+ }
391
+ return {};
392
+ });
393
+ }
394
+ }
395
+ ],
294
396
  async onSuccess() {
295
397
  if (typeof _onSuccess === "function") {
296
398
  await _onSuccess();
297
399
  }
400
+ logger.info("extension build success");
298
401
  }
299
402
  })
300
403
  );
package/dist/index.mjs CHANGED
@@ -4,10 +4,12 @@ import path from "path";
4
4
  import { cwd } from "process";
5
5
  import cloneDeep from "lodash.clonedeep";
6
6
  import merge from "lodash.merge";
7
+ import { parse as htmlParser } from "node-html-parser";
7
8
  import { build as tsupBuild } from "tsup";
8
9
 
9
10
  // src/constants.ts
10
11
  var PLUGIN_NAME = "@tomjs:vscode";
12
+ var PACKAGE_NAME = "@tomjs/vite-plugin-vscode";
11
13
  var WEBVIEW_PACKAGE_NAME = "@tomjs/vscode-extension-webview";
12
14
  var WEBVIEW_METHOD_NAME = "__getWebviewHtml__";
13
15
 
@@ -60,6 +62,12 @@ function readJson(path2) {
60
62
  return JSON.parse(fs.readFileSync(path2, "utf8"));
61
63
  }
62
64
  }
65
+ function emptyPath(dest) {
66
+ if (fs.existsSync(dest)) {
67
+ fs.rmSync(dest, { recursive: true });
68
+ }
69
+ fs.mkdirSync(dest, { recursive: true });
70
+ }
63
71
  function resolveHostname(hostname) {
64
72
  const loopbackHosts = /* @__PURE__ */ new Set([
65
73
  "localhost",
@@ -151,12 +159,69 @@ function preMergeOptions(options) {
151
159
  opts.webview = opts.webview ?? WEBVIEW_METHOD_NAME;
152
160
  return opts;
153
161
  }
154
- function readAllFiles(dir) {
155
- return fs2.readdirSync(dir).reduce((files, file) => {
156
- const name = path.join(dir, file);
157
- const isDir = fs2.statSync(name).isDirectory();
158
- return isDir ? [...files, ...readAllFiles(name)] : [...files, name];
159
- }, []);
162
+ var prodCachePkgName = `${PACKAGE_NAME}-inject`;
163
+ function genProdWebviewCode(cache) {
164
+ const prodCacheFolder = path.join(cwd(), "node_modules", prodCachePkgName);
165
+ emptyPath(prodCacheFolder);
166
+ const destFile = path.join(prodCacheFolder, "index.ts");
167
+ function handleHtmlCode(html) {
168
+ const root = htmlParser(html);
169
+ const head = root.querySelector("head");
170
+ if (!head) {
171
+ root == null ? void 0 : root.insertAdjacentHTML("beforeend", "<head></head>");
172
+ }
173
+ head.insertAdjacentHTML(
174
+ "afterbegin",
175
+ `
176
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';">`
177
+ );
178
+ const tags = {
179
+ script: "src",
180
+ link: "href"
181
+ };
182
+ Object.keys(tags).forEach((tag) => {
183
+ const elements = root.querySelectorAll(tag);
184
+ elements.forEach((element) => {
185
+ const attr = element.getAttribute(tags[tag]);
186
+ if (attr) {
187
+ element.setAttribute(tags[tag], `{{baseUri}}${attr}`);
188
+ }
189
+ element.setAttribute("nonce", "{{nonce}}");
190
+ });
191
+ });
192
+ return root.toString();
193
+ }
194
+ const cacheCode = (
195
+ /* js */
196
+ `const htmlCode = {
197
+ ${Object.keys(cache).map((s) => `${s}: \`${handleHtmlCode(cache[s])}\`,`).join("\n")}
198
+ };`
199
+ );
200
+ const code = (
201
+ /* js */
202
+ `import { ExtensionContext, Uri, Webview } from 'vscode';
203
+
204
+ ${cacheCode}
205
+
206
+ function uuid() {
207
+ let text = '';
208
+ const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
209
+ for (let i = 0; i < 32; i++) {
210
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
211
+ }
212
+ return text;
213
+ }
214
+
215
+ export default function getWebviewHtml(webview: Webview, context: ExtensionContext, inputName?:string){
216
+ const nonce = uuid();
217
+ const baseUri = webview.asWebviewUri(Uri.joinPath(context.extensionUri, (process.env.VITE_WEBVIEW_DIST || 'dist')));
218
+ const html = htmlCode[inputName || 'index'] || '';
219
+ return html.replaceAll('{{cspSource}}',webview.cspSource).replaceAll('{{nonce}}', nonce).replaceAll('{{baseUri}}', baseUri);
220
+ }
221
+ `
222
+ );
223
+ fs2.writeFileSync(destFile, code, { encoding: "utf8" });
224
+ return destFile.replaceAll("\\", "/");
160
225
  }
161
226
  function useVSCodePlugin(options) {
162
227
  const opts = preMergeOptions(options);
@@ -207,6 +272,7 @@ function useVSCodePlugin(options) {
207
272
  }
208
273
  }
209
274
  let buildConfig;
275
+ const prodHtmlCache = {};
210
276
  return [
211
277
  {
212
278
  name: "@tomjs:vscode",
@@ -274,26 +340,63 @@ function useVSCodePlugin(options) {
274
340
  {
275
341
  name: "@tomjs:vscode",
276
342
  apply: "build",
343
+ enforce: "post",
277
344
  config(config) {
278
345
  return handleConfig(config);
279
346
  },
280
347
  configResolved(config) {
281
348
  buildConfig = config;
282
349
  },
350
+ transformIndexHtml(html, ctx) {
351
+ var _a;
352
+ if (!opts.webview) {
353
+ return html;
354
+ }
355
+ prodHtmlCache[(_a = ctx.chunk) == null ? void 0 : _a.name] = html;
356
+ return html;
357
+ },
283
358
  closeBundle() {
284
- const { outDir } = buildConfig.build;
285
- const cwd2 = process.cwd();
286
- const allFiles = readAllFiles(outDir).filter((file) => file.endsWith(".js") && !file.endsWith("index.js")).map((s) => s.replace(cwd2, "").replaceAll("\\", "/").substring(1));
359
+ let webviewPath;
360
+ if (opts.webview) {
361
+ webviewPath = genProdWebviewCode(prodHtmlCache);
362
+ }
363
+ let outDir = buildConfig.build.outDir.replace(cwd(), "").replaceAll("\\", "/");
364
+ if (outDir.startsWith("/")) {
365
+ outDir = outDir.substring(1);
366
+ }
367
+ const env = {
368
+ NODE_ENV: buildConfig.mode || "production",
369
+ VITE_WEBVIEW_DIST: outDir
370
+ };
371
+ logger.info("extension build start");
287
372
  const { onSuccess: _onSuccess, ...tsupOptions } = opts.extension || {};
288
373
  tsupBuild(
289
374
  merge(tsupOptions, {
290
- env: {
291
- VITE_DIST_FILES: JSON.stringify(allFiles)
292
- },
375
+ env,
376
+ silent: true,
377
+ esbuildPlugins: !opts.webview ? [] : [
378
+ {
379
+ name: "@tomjs:vscode:inject",
380
+ setup(build) {
381
+ build.onLoad({ filter: /\.ts$/ }, async (args) => {
382
+ const file = fs2.readFileSync(args.path, "utf-8");
383
+ if (file.includes(`${opts.webview}(`)) {
384
+ return {
385
+ contents: `import ${opts.webview} from \`${webviewPath}\`;
386
+ ` + file,
387
+ loader: "ts"
388
+ };
389
+ }
390
+ return {};
391
+ });
392
+ }
393
+ }
394
+ ],
293
395
  async onSuccess() {
294
396
  if (typeof _onSuccess === "function") {
295
397
  await _onSuccess();
296
398
  }
399
+ logger.info("extension build success");
297
400
  }
298
401
  })
299
402
  );
package/env.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export {}; // Make this a module
2
-
1
+ import { ExtensionContext, Webview } from 'vscode';
2
+ // Make this a module
3
+ export {};
3
4
  declare global {
4
5
  /**
5
6
  * fix code hint
@@ -19,13 +20,25 @@ declare global {
19
20
  /**
20
21
  * `[vite build]` All js files in the dist directory, excluding index.js. It's to be a json string.
21
22
  */
22
- VITE_DIST_FILES?: string;
23
+ VITE_WEBVIEW_DIST?: string;
23
24
  }
24
25
  }
25
26
 
26
27
  /**
27
- * `[vite serve]` Get the html of the development webview.
28
+ * `[vite serve]` Gets the html of webview in development mode.
28
29
  * @param options serverUrl: The url of the vite dev server.
29
30
  */
30
31
  function __getWebviewHtml__(options?: string | { serverUrl: string }): string;
32
+
33
+ /**
34
+ * `[vite serve]` Gets the html of webview in production mode.
35
+ * @param webview The Webview instance of the extension.
36
+ * @param context The ExtensionContext instance of the extension.
37
+ * @param inputName vite build.rollupOptions.input name. Default is `index`.
38
+ */
39
+ function __getWebviewHtml__(
40
+ webview: Webview,
41
+ context: ExtensionContext,
42
+ inputName?: string,
43
+ ): string;
31
44
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tomjs/vite-plugin-vscode",
3
- "version": "1.5.0",
4
- "description": "The vite plugin for vscode extension, supports esm and cjs.",
3
+ "version": "2.0.0",
4
+ "description": "Use vue/react to develop 'vscode extension webview', supporting esm/cjs",
5
5
  "keywords": [
6
6
  "vite",
7
7
  "plugin",
@@ -47,6 +47,7 @@
47
47
  "kolorist": "^1.8.0",
48
48
  "lodash.clonedeep": "^4.5.0",
49
49
  "lodash.merge": "^4.6.2",
50
+ "node-html-parser": "^6.1.12",
50
51
  "tsup": "7.2.0"
51
52
  },
52
53
  "devDependencies": {