@tomjs/vite-plugin-vscode 2.1.0 → 2.3.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
@@ -30,19 +30,15 @@ yarn add @tomjs/vite-plugin-vscode -D
30
30
  npm i @tomjs/vite-plugin-vscode --save-dev
31
31
  ```
32
32
 
33
- If you use `pnpm` and enable `webview` debugging, you need to additionally install the dependency [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview)
34
-
35
- ```bash
36
- pnpm add @tomjs/vscode-extension-webview -D
37
- ```
38
-
39
33
  ## Usage
40
34
 
41
- ### Recommended Agreement
35
+ ### Recommended
36
+
37
+ Setting `recommended` will modify some preset configurations. See [PluginOptions](#pluginoptions) and `recommended` parameter descriptions in detail.
42
38
 
43
39
  #### Directory Structure
44
40
 
45
- - Recommend `extension` and page `src` code directory structure
41
+ - By default, `recommended:true` will be based on the following directory structure as a convention.
46
42
 
47
43
  ```
48
44
  |--extension // extension code
@@ -50,6 +46,7 @@ pnpm add @tomjs/vscode-extension-webview -D
50
46
  |--src // front-end code
51
47
  | |--App.vue
52
48
  | |--main.ts
49
+ |--index.html
53
50
  ```
54
51
 
55
52
  - Zero configuration, default dist output directory
@@ -63,9 +60,16 @@ pnpm add @tomjs/vscode-extension-webview -D
63
60
  | | |--index.html
64
61
  ```
65
62
 
66
- #### Default configuration and behavior
63
+ - If you want to modify the `extension` source code directory to `src`, you can set `{ extension: { entry: 'src/index.ts' } }`
67
64
 
68
- See [PluginOptions](#pluginoptions) and `recommended` parameter descriptions in detail
65
+ ```
66
+ |--src // extension code
67
+ | |--index.ts
68
+ |--webview // front-end code
69
+ | |--App.vue
70
+ | |--main.ts
71
+ |--index.html
72
+ ```
69
73
 
70
74
  ### extension
71
75
 
@@ -111,6 +115,8 @@ export default defineConfig({
111
115
  },
112
116
  }),
113
117
  vscode(),
118
+ // Modify the extension source code entry path, and also modify the `index.html` entry file path
119
+ // vscode({ extension: { entry: 'src/index.ts' } }),
114
120
  ],
115
121
  });
116
122
  ```
@@ -207,7 +213,7 @@ function __getWebviewHtml__(
207
213
  | --- | --- | --- | --- |
208
214
  | recommended | `boolean` | `true` | This option is intended to provide recommended default parameters and behavior. |
209
215
  | extension | [ExtensionOptions](#ExtensionOptions) | | Configuration options for the vscode extension. |
210
- | webview | `boolean` | `false` | 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. |
216
+ | webview | `boolean` \| `string` \| [WebviewOption](#WebviewOption) | `__getWebviewHtml__` | Inject html code |
211
217
 
212
218
  **Notice**
213
219
 
@@ -216,6 +222,16 @@ The `recommended` option is used to set the default configuration and behavior,
216
222
  - The output directory is based on the `build.outDir` parameter of `vite`, and outputs `extension` and `src` to `dist/extension` and `dist/webview` respectively.
217
223
  - Other behaviors to be implemented
218
224
 
225
+ **Webview**
226
+
227
+ 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.
228
+
229
+ - vite serve
230
+ - extension: Inject `import __getWebviewHtml__ from '@tomjs/vscode-extension-webview';` above the file that calls the `__getWebviewHtml__` method
231
+ - web: Add `<script>` tag to index.html and inject `@tomjs/vscode-extension-webview/client` code
232
+ - vite build
233
+ - extension: Inject `import __getWebviewHtml__ from '@tomjs/vite-plugin-vscode-inject';` above the file that calls the `__getWebviewHtml__` method If is string, will set inject method name. Default is `__getWebviewHtml__`.
234
+
219
235
  ### ExtensionOptions
220
236
 
221
237
  Based on [Options](https://paka.dev/npm/tsup) of [tsup](https://tsup.egoist.dev/), some default values are added for ease of use.
@@ -226,6 +242,16 @@ Based on [Options](https://paka.dev/npm/tsup) of [tsup](https://tsup.egoist.dev/
226
242
  | outDir | `string` | `dist-extension/main` | The output directory for the vscode extension file |
227
243
  | onSuccess | `() => Promise<void \| undefined \| (() => void \| Promise<void>)>` | `undefined` | A function that will be executed after the build succeeds. |
228
244
 
245
+ ### WebviewOption
246
+
247
+ | Property | Type | Default | Description |
248
+ | --- | --- | --- | --- |
249
+ | name | `string` | `__getWebviewHtml__` | The inject method name |
250
+ | 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 |
251
+
252
+ - `{{cspSource}}`: [webview.cspSource](https://code.visualstudio.com/api/references/vscode-api#Webview)
253
+ - `{{nonce}}`: uuid
254
+
229
255
  ### Additional Information
230
256
 
231
257
  - Default values for `extension` when the relevant parameters are not configured
package/README.zh_CN.md CHANGED
@@ -30,19 +30,15 @@ yarn add @tomjs/vite-plugin-vscode -D
30
30
  npm i @tomjs/vite-plugin-vscode --save-dev
31
31
  ```
32
32
 
33
- 如果使用 `pnpm` 且开启 `webview` 调试,需要额外安装[@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview) 这个依赖
34
-
35
- ```bash
36
- pnpm add @tomjs/vscode-extension-webview -D
37
- ```
38
-
39
33
  ## 使用说明
40
34
 
41
35
  ### 推荐约定
42
36
 
37
+ 设置 `recommended` 参数会修改一些预置配置,详细查看 [PluginOptions](#pluginoptions) 和 `recommended` 参数说明。
38
+
43
39
  #### 目录结构
44
40
 
45
- - 推荐 `extension` 和 页面 `src` 代码目录结构
41
+ - 默认情况下,`recommended:true` 会根据如下目录结构作为约定
46
42
 
47
43
  ```
48
44
  |--extension // extension code
@@ -50,6 +46,7 @@ pnpm add @tomjs/vscode-extension-webview -D
50
46
  |--src // front-end code
51
47
  | |--App.vue
52
48
  | |--main.ts
49
+ |--index.html
53
50
  ```
54
51
 
55
52
  - 零配置,默认 dist 输出目录
@@ -63,9 +60,16 @@ pnpm add @tomjs/vscode-extension-webview -D
63
60
  | | |--index.html
64
61
  ```
65
62
 
66
- #### 默认配置和行为
63
+ - 如果你想修改 `extension` 源码目录为 `src`,可以设置 `{ extension: { entry: 'src/index.ts' } }`
67
64
 
68
- 详细查看 [PluginOptions](#pluginoptions) 和 `recommended` 参数说明
65
+ ```
66
+ |--src // extension code
67
+ | |--index.ts
68
+ |--webview // front-end code
69
+ | |--App.vue
70
+ | |--main.ts
71
+ |--index.html
72
+ ```
69
73
 
70
74
  ### extension
71
75
 
@@ -115,6 +119,8 @@ export default defineConfig({
115
119
  },
116
120
  }),
117
121
  vscode(),
122
+ // 修改扩展源码入口路径,同时修改`index.html`入口文件路径
123
+ // vscode({ extension: { entry: 'src/index.ts' } }),
118
124
  ],
119
125
  });
120
126
  ```
@@ -211,7 +217,7 @@ function __getWebviewHtml__(
211
217
  | --- | --- | --- | --- |
212
218
  | recommended | `boolean` | `true` | 这个选项是为了提供推荐的默认参数和行为 |
213
219
  | extension | [ExtensionOptions](#ExtensionOptions) | | vscode extension 可选配置 |
214
- | webview | `boolean` | `false` | 在vscode扩展代码和Web客户端代码中注入[@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview),以便webview在开发阶段可以支持HMR。 |
220
+ | webview | `boolean` \| `string` \| [WebviewOption](#WebviewOption) | `__getWebviewHtml__` | 注入 html 代码 |
215
221
 
216
222
  **Notice**
217
223
 
@@ -221,6 +227,16 @@ function __getWebviewHtml__(
221
227
 
222
228
  - 其他待实现的行为
223
229
 
230
+ **Webview**
231
+
232
+ 在 vscode 扩展代码和 web 客户端代码中注入 [@tomjs/vscode-extension-webview](https://github.com/tomjs/vscode-extension-webview),使 `webview` 在开发阶段能够支持 `HMR`。
233
+
234
+ - vite serve
235
+ - extension: 在调用 `__getWebviewHtml__` 方法的文件上方注入 `import __getWebviewHtml__ from '@tomjs/vscode-extension-webview';`
236
+ - web: 在 index.html 中添加 `<script>` 标签,注入 `@tomjs/vscode-extension-webview/client` 代码
237
+ - vite build
238
+ - extension: 在调用 `__getWebviewHtml__` 方法的文件上方注入 `import __getWebviewHtml__ from '@tomjs/vite-plugin-vscode-inject';` 如果为字符串,则设置注入方法名,默认为 `__getWebviewHtml__`。
239
+
224
240
  ### ExtensionOptions
225
241
 
226
242
  继承自 [tsup](https://tsup.egoist.dev/) 的 [Options](https://paka.dev/npm/tsup),添加了一些默认值,方便使用。
@@ -231,6 +247,16 @@ function __getWebviewHtml__(
231
247
  | outDir | `string` | `dist-extension/main` | 输出文件夹 |
232
248
  | onSuccess | `() => Promise<void \| undefined \| (() => void \| Promise<void>)>` | `undefined` | 构建成功后运行的回调函数 |
233
249
 
250
+ ### WebviewOption
251
+
252
+ | 参数名 | 类型 | 默认值 | 说明 |
253
+ | --- | --- | --- | --- |
254
+ | name | `string` | `__getWebviewHtml__` | 注入的方法名 |
255
+ | 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` |
256
+
257
+ - `{{cspSource}}`: [webview.cspSource](https://code.visualstudio.com/api/references/vscode-api#Webview)
258
+ - `{{nonce}}`: uuid
259
+
234
260
  ### 补充说明
235
261
 
236
262
  - `extension` 未配置相关参数时的默认值
package/dist/index.d.mts CHANGED
@@ -28,6 +28,19 @@ interface ExtensionOptions extends Omit<Options, 'entry' | 'format' | 'outDir' |
28
28
  */
29
29
  onSuccess?: () => Promise<void | undefined | (() => void | Promise<void>)>;
30
30
  }
31
+ /**
32
+ * vscode webview options.
33
+ */
34
+ interface WebviewOption {
35
+ /**
36
+ * The method name to inject. Default is '__getWebviewHtml__'
37
+ */
38
+ name?: string;
39
+ /**
40
+ * The CSP meta for the webview. Default is `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';">`
41
+ */
42
+ csp?: string;
43
+ }
31
44
  /**
32
45
  * vite plugin options.
33
46
  */
@@ -70,7 +83,7 @@ interface PluginOptions {
70
83
  * </html>
71
84
  * ```
72
85
  */
73
- webview?: boolean | string;
86
+ webview?: boolean | string | WebviewOption;
74
87
  /**
75
88
  * extension vite config.
76
89
  */
package/dist/index.d.ts CHANGED
@@ -28,6 +28,19 @@ interface ExtensionOptions extends Omit<Options, 'entry' | 'format' | 'outDir' |
28
28
  */
29
29
  onSuccess?: () => Promise<void | undefined | (() => void | Promise<void>)>;
30
30
  }
31
+ /**
32
+ * vscode webview options.
33
+ */
34
+ interface WebviewOption {
35
+ /**
36
+ * The method name to inject. Default is '__getWebviewHtml__'
37
+ */
38
+ name?: string;
39
+ /**
40
+ * The CSP meta for the webview. Default is `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';">`
41
+ */
42
+ csp?: string;
43
+ }
31
44
  /**
32
45
  * vite plugin options.
33
46
  */
@@ -70,7 +83,7 @@ interface PluginOptions {
70
83
  * </html>
71
84
  * ```
72
85
  */
73
- webview?: boolean | string;
86
+ webview?: boolean | string | WebviewOption;
74
87
  /**
75
88
  * extension vite config.
76
89
  */
package/dist/index.js CHANGED
@@ -56,11 +56,14 @@ var createLogger = (tag) => {
56
56
  };
57
57
 
58
58
  // src/utils.ts
59
+ var _child_process = require('child_process');
59
60
 
60
61
  var _module = require('module');
61
- function readJson(path2) {
62
- if (_fs2.default.existsSync(path2)) {
63
- return JSON.parse(_fs2.default.readFileSync(path2, "utf8"));
62
+
63
+
64
+ function readJson(path3) {
65
+ if (_fs2.default.existsSync(path3)) {
66
+ return JSON.parse(_fs2.default.readFileSync(path3, "utf8"));
64
67
  }
65
68
  }
66
69
  function emptyPath(dest) {
@@ -88,11 +91,46 @@ function resolveServerUrl(server) {
88
91
  const options = server.config.server;
89
92
  const protocol = options.https ? "https" : "http";
90
93
  const devBase = server.config.base;
91
- const path2 = typeof options.open === "string" ? options.open : devBase;
92
- const url = path2.startsWith("http") ? path2 : `${protocol}://${hostname}:${port}${path2}`;
94
+ const path3 = typeof options.open === "string" ? options.open : devBase;
95
+ const url = path3.startsWith("http") ? path3 : `${protocol}://${hostname}:${port}${path3}`;
93
96
  return url;
94
97
  }
95
98
  }
99
+ function getWebviewNpmPath() {
100
+ let npmPath = _path2.default.join(_process.cwd.call(void 0, ), "node_modules", WEBVIEW_PACKAGE_NAME);
101
+ if (!_fs2.default.existsSync(npmPath)) {
102
+ try {
103
+ const res = _child_process.spawnSync.call(void 0,
104
+ process.platform === "win32" ? "pnpm.cmd" : "pnpm",
105
+ ["list", "--dev", "--depth=1", "--json"],
106
+ {
107
+ // stdio: ['inherit', 'ignore'],
108
+ cwd: process.cwd(),
109
+ encoding: "utf-8"
110
+ }
111
+ );
112
+ if (res.status === 0 && res.stdout) {
113
+ const list = JSON.parse(res.stdout.trim());
114
+ if (list.length === 0) {
115
+ return;
116
+ }
117
+ const self = (list[0].devDependencies || {})[PACKAGE_NAME];
118
+ if (!self) {
119
+ return;
120
+ }
121
+ const dep = self.dependencies[WEBVIEW_PACKAGE_NAME];
122
+ if (dep) {
123
+ npmPath = dep.path;
124
+ }
125
+ }
126
+ } catch (e) {
127
+ npmPath = "";
128
+ }
129
+ if (npmPath) {
130
+ return _path2.default.join(npmPath, "dist");
131
+ }
132
+ }
133
+ }
96
134
 
97
135
  // src/index.ts
98
136
  var isDev = process.env.NODE_ENV === "development";
@@ -154,14 +192,18 @@ function preMergeOptions(options) {
154
192
  );
155
193
  }
156
194
  opts.extension = opt;
157
- if (opts.webview === true) {
158
- opts.webview = WEBVIEW_METHOD_NAME;
195
+ if (opts.webview !== false) {
196
+ let name = WEBVIEW_METHOD_NAME;
197
+ if (typeof opts.webview === "string") {
198
+ name = _nullishCoalesce(opts.webview, () => ( WEBVIEW_METHOD_NAME));
199
+ }
200
+ opts.webview = Object.assign({ name }, opts.webview);
159
201
  }
160
- opts.webview = _nullishCoalesce(opts.webview, () => ( WEBVIEW_METHOD_NAME));
161
202
  return opts;
162
203
  }
163
204
  var prodCachePkgName = `${PACKAGE_NAME}-inject`;
164
- function genProdWebviewCode(cache) {
205
+ function genProdWebviewCode(cache, webview) {
206
+ webview = Object.assign({}, webview);
165
207
  const prodCacheFolder = _path2.default.join(_process.cwd.call(void 0, ), "node_modules", prodCachePkgName);
166
208
  emptyPath(prodCacheFolder);
167
209
  const destFile = _path2.default.join(prodCacheFolder, "index.ts");
@@ -171,26 +213,25 @@ function genProdWebviewCode(cache) {
171
213
  if (!head) {
172
214
  root == null ? void 0 : root.insertAdjacentHTML("beforeend", "<head></head>");
173
215
  }
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}}");
216
+ const csp = (webview == null ? void 0 : webview.csp) || `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';">`;
217
+ head.insertAdjacentHTML("afterbegin", csp);
218
+ if (csp && csp.includes("{{nonce}}")) {
219
+ const tags = {
220
+ script: "src",
221
+ link: "href"
222
+ };
223
+ Object.keys(tags).forEach((tag) => {
224
+ const elements = root.querySelectorAll(tag);
225
+ elements.forEach((element) => {
226
+ const attr = element.getAttribute(tags[tag]);
227
+ if (attr) {
228
+ element.setAttribute(tags[tag], `{{baseUri}}${attr}`);
229
+ }
230
+ element.setAttribute("nonce", "{{nonce}}");
231
+ });
191
232
  });
192
- });
193
- return root.toString();
233
+ }
234
+ return root.removeWhitespace().toString();
194
235
  }
195
236
  const cacheCode = (
196
237
  /* js */
@@ -217,7 +258,7 @@ export default function getWebviewHtml(webview: Webview, context: ExtensionConte
217
258
  const nonce = uuid();
218
259
  const baseUri = webview.asWebviewUri(Uri.joinPath(context.extensionUri, (process.env.VITE_WEBVIEW_DIST || 'dist')));
219
260
  const html = htmlCode[inputName || 'index'] || '';
220
- return html.replaceAll('{{cspSource}}',webview.cspSource).replaceAll('{{nonce}}', nonce).replaceAll('{{baseUri}}', baseUri);
261
+ return html.replaceAll('{{cspSource}}', webview.cspSource).replaceAll('{{nonce}}', nonce).replaceAll('{{baseUri}}', baseUri);
221
262
  }
222
263
  `
223
264
  );
@@ -259,8 +300,8 @@ function useVSCodePlugin(options) {
259
300
  let webviewClient;
260
301
  let webviewNpmPath;
261
302
  if (opts.webview) {
262
- webviewNpmPath = _path2.default.join(_process.cwd.call(void 0, ), "node_modules", WEBVIEW_PACKAGE_NAME, "/dist");
263
- if (!_fs2.default.existsSync(webviewNpmPath)) {
303
+ webviewNpmPath = getWebviewNpmPath();
304
+ if (!webviewNpmPath || !_fs2.default.existsSync(webviewNpmPath)) {
264
305
  logger.warn(`[${WEBVIEW_PACKAGE_NAME}] is not installed, please install it first!`);
265
306
  } else {
266
307
  const fileName = "client.global.js";
@@ -293,21 +334,22 @@ function useVSCodePlugin(options) {
293
334
  };
294
335
  logger.info("extension build start");
295
336
  let buildCount = 0;
337
+ const webview = opts == null ? void 0 : opts.webview;
296
338
  const { onSuccess: _onSuccess, ...tsupOptions } = opts.extension || {};
297
339
  await _tsup.build.call(void 0,
298
340
  _lodashmerge2.default.call(void 0, tsupOptions, {
299
341
  watch: true,
300
342
  env,
301
343
  silent: true,
302
- esbuildPlugins: [
344
+ esbuildPlugins: !webview ? [] : [
303
345
  {
304
346
  name: "@tomjs:vscode:inject",
305
347
  setup(build) {
306
348
  build.onLoad({ filter: /\.ts$/ }, async (args) => {
307
349
  const file = _fs2.default.readFileSync(args.path, "utf-8");
308
- if (file.includes(`${opts.webview}(`)) {
350
+ if (file.includes(`${webview.name}(`)) {
309
351
  return {
310
- contents: `import ${opts.webview} from '@tomjs/vscode-extension-webview';
352
+ contents: `import ${webview.name} from '@tomjs/vscode-extension-webview';
311
353
  ` + file,
312
354
  loader: "ts"
313
355
  };
@@ -358,8 +400,9 @@ function useVSCodePlugin(options) {
358
400
  },
359
401
  closeBundle() {
360
402
  let webviewPath;
361
- if (opts.webview) {
362
- webviewPath = genProdWebviewCode(prodHtmlCache);
403
+ const webview = opts == null ? void 0 : opts.webview;
404
+ if (webview) {
405
+ webviewPath = genProdWebviewCode(prodHtmlCache, webview);
363
406
  }
364
407
  let outDir = buildConfig.build.outDir.replace(_process.cwd.call(void 0, ), "").replaceAll("\\", "/");
365
408
  if (outDir.startsWith("/")) {
@@ -375,15 +418,15 @@ function useVSCodePlugin(options) {
375
418
  _lodashmerge2.default.call(void 0, tsupOptions, {
376
419
  env,
377
420
  silent: true,
378
- esbuildPlugins: !opts.webview ? [] : [
421
+ esbuildPlugins: !webview ? [] : [
379
422
  {
380
423
  name: "@tomjs:vscode:inject",
381
424
  setup(build) {
382
425
  build.onLoad({ filter: /\.ts$/ }, async (args) => {
383
426
  const file = _fs2.default.readFileSync(args.path, "utf-8");
384
- if (file.includes(`${opts.webview}(`)) {
427
+ if (file.includes(`${webview.name}(`)) {
385
428
  return {
386
- contents: `import ${opts.webview} from \`${webviewPath}\`;
429
+ contents: `import ${webview.name} from \`${webviewPath}\`;
387
430
  ` + file,
388
431
  loader: "ts"
389
432
  };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/index.ts
2
2
  import fs2 from "fs";
3
- import path from "path";
4
- import { cwd } from "process";
3
+ import path2 from "path";
4
+ import { cwd as cwd2 } from "process";
5
5
  import cloneDeep from "lodash.clonedeep";
6
6
  import merge from "lodash.merge";
7
7
  import { parse as htmlParser } from "node-html-parser";
@@ -56,10 +56,13 @@ var createLogger = (tag) => {
56
56
  };
57
57
 
58
58
  // src/utils.ts
59
+ import { spawnSync } from "child_process";
59
60
  import fs from "fs";
60
- function readJson(path2) {
61
- if (fs.existsSync(path2)) {
62
- return JSON.parse(fs.readFileSync(path2, "utf8"));
61
+ import path from "path";
62
+ import { cwd } from "process";
63
+ function readJson(path3) {
64
+ if (fs.existsSync(path3)) {
65
+ return JSON.parse(fs.readFileSync(path3, "utf8"));
63
66
  }
64
67
  }
65
68
  function emptyPath(dest) {
@@ -87,17 +90,52 @@ function resolveServerUrl(server) {
87
90
  const options = server.config.server;
88
91
  const protocol = options.https ? "https" : "http";
89
92
  const devBase = server.config.base;
90
- const path2 = typeof options.open === "string" ? options.open : devBase;
91
- const url = path2.startsWith("http") ? path2 : `${protocol}://${hostname}:${port}${path2}`;
93
+ const path3 = typeof options.open === "string" ? options.open : devBase;
94
+ const url = path3.startsWith("http") ? path3 : `${protocol}://${hostname}:${port}${path3}`;
92
95
  return url;
93
96
  }
94
97
  }
98
+ function getWebviewNpmPath() {
99
+ let npmPath = path.join(cwd(), "node_modules", WEBVIEW_PACKAGE_NAME);
100
+ if (!fs.existsSync(npmPath)) {
101
+ try {
102
+ const res = spawnSync(
103
+ process.platform === "win32" ? "pnpm.cmd" : "pnpm",
104
+ ["list", "--dev", "--depth=1", "--json"],
105
+ {
106
+ // stdio: ['inherit', 'ignore'],
107
+ cwd: process.cwd(),
108
+ encoding: "utf-8"
109
+ }
110
+ );
111
+ if (res.status === 0 && res.stdout) {
112
+ const list = JSON.parse(res.stdout.trim());
113
+ if (list.length === 0) {
114
+ return;
115
+ }
116
+ const self = (list[0].devDependencies || {})[PACKAGE_NAME];
117
+ if (!self) {
118
+ return;
119
+ }
120
+ const dep = self.dependencies[WEBVIEW_PACKAGE_NAME];
121
+ if (dep) {
122
+ npmPath = dep.path;
123
+ }
124
+ }
125
+ } catch {
126
+ npmPath = "";
127
+ }
128
+ if (npmPath) {
129
+ return path.join(npmPath, "dist");
130
+ }
131
+ }
132
+ }
95
133
 
96
134
  // src/index.ts
97
135
  var isDev = process.env.NODE_ENV === "development";
98
136
  var logger = createLogger();
99
137
  function getPkg() {
100
- const pkgFile = path.resolve(process.cwd(), "package.json");
138
+ const pkgFile = path2.resolve(process.cwd(), "package.json");
101
139
  if (!fs2.existsSync(pkgFile)) {
102
140
  throw new Error("Main file is not specified, and no package.json found");
103
141
  }
@@ -153,43 +191,46 @@ function preMergeOptions(options) {
153
191
  );
154
192
  }
155
193
  opts.extension = opt;
156
- if (opts.webview === true) {
157
- opts.webview = WEBVIEW_METHOD_NAME;
194
+ if (opts.webview !== false) {
195
+ let name = WEBVIEW_METHOD_NAME;
196
+ if (typeof opts.webview === "string") {
197
+ name = opts.webview ?? WEBVIEW_METHOD_NAME;
198
+ }
199
+ opts.webview = Object.assign({ name }, opts.webview);
158
200
  }
159
- opts.webview = opts.webview ?? WEBVIEW_METHOD_NAME;
160
201
  return opts;
161
202
  }
162
203
  var prodCachePkgName = `${PACKAGE_NAME}-inject`;
163
- function genProdWebviewCode(cache) {
164
- const prodCacheFolder = path.join(cwd(), "node_modules", prodCachePkgName);
204
+ function genProdWebviewCode(cache, webview) {
205
+ webview = Object.assign({}, webview);
206
+ const prodCacheFolder = path2.join(cwd2(), "node_modules", prodCachePkgName);
165
207
  emptyPath(prodCacheFolder);
166
- const destFile = path.join(prodCacheFolder, "index.ts");
208
+ const destFile = path2.join(prodCacheFolder, "index.ts");
167
209
  function handleHtmlCode(html) {
168
210
  const root = htmlParser(html);
169
211
  const head = root.querySelector("head");
170
212
  if (!head) {
171
213
  root == null ? void 0 : root.insertAdjacentHTML("beforeend", "<head></head>");
172
214
  }
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}}");
215
+ const csp = (webview == null ? void 0 : webview.csp) || `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src {{cspSource}} 'unsafe-inline'; script-src 'nonce-{{nonce}}' 'unsafe-eval';">`;
216
+ head.insertAdjacentHTML("afterbegin", csp);
217
+ if (csp && csp.includes("{{nonce}}")) {
218
+ const tags = {
219
+ script: "src",
220
+ link: "href"
221
+ };
222
+ Object.keys(tags).forEach((tag) => {
223
+ const elements = root.querySelectorAll(tag);
224
+ elements.forEach((element) => {
225
+ const attr = element.getAttribute(tags[tag]);
226
+ if (attr) {
227
+ element.setAttribute(tags[tag], `{{baseUri}}${attr}`);
228
+ }
229
+ element.setAttribute("nonce", "{{nonce}}");
230
+ });
190
231
  });
191
- });
192
- return root.toString();
232
+ }
233
+ return root.removeWhitespace().toString();
193
234
  }
194
235
  const cacheCode = (
195
236
  /* js */
@@ -216,7 +257,7 @@ export default function getWebviewHtml(webview: Webview, context: ExtensionConte
216
257
  const nonce = uuid();
217
258
  const baseUri = webview.asWebviewUri(Uri.joinPath(context.extensionUri, (process.env.VITE_WEBVIEW_DIST || 'dist')));
218
259
  const html = htmlCode[inputName || 'index'] || '';
219
- return html.replaceAll('{{cspSource}}',webview.cspSource).replaceAll('{{nonce}}', nonce).replaceAll('{{baseUri}}', baseUri);
260
+ return html.replaceAll('{{cspSource}}', webview.cspSource).replaceAll('{{nonce}}', nonce).replaceAll('{{baseUri}}', baseUri);
220
261
  }
221
262
  `
222
263
  );
@@ -230,8 +271,8 @@ function useVSCodePlugin(options) {
230
271
  let outDir = ((_a = config == null ? void 0 : config.build) == null ? void 0 : _a.outDir) || "dist";
231
272
  opts.extension ??= {};
232
273
  if (opts.recommended) {
233
- opts.extension.outDir = path.resolve(outDir, "extension");
234
- outDir = path.resolve(outDir, "webview");
274
+ opts.extension.outDir = path2.resolve(outDir, "extension");
275
+ outDir = path2.resolve(outDir, "webview");
235
276
  }
236
277
  const assetsDir = ((_b = config == null ? void 0 : config.build) == null ? void 0 : _b.assetsDir) || "assets";
237
278
  const output = {
@@ -258,12 +299,12 @@ function useVSCodePlugin(options) {
258
299
  let webviewClient;
259
300
  let webviewNpmPath;
260
301
  if (opts.webview) {
261
- webviewNpmPath = path.join(cwd(), "node_modules", WEBVIEW_PACKAGE_NAME, "/dist");
262
- if (!fs2.existsSync(webviewNpmPath)) {
302
+ webviewNpmPath = getWebviewNpmPath();
303
+ if (!webviewNpmPath || !fs2.existsSync(webviewNpmPath)) {
263
304
  logger.warn(`[${WEBVIEW_PACKAGE_NAME}] is not installed, please install it first!`);
264
305
  } else {
265
306
  const fileName = "client.global.js";
266
- const clientFile = path.join(webviewNpmPath, fileName);
307
+ const clientFile = path2.join(webviewNpmPath, fileName);
267
308
  if (!fs2.existsSync(clientFile)) {
268
309
  logger.warn(`[${fileName}] is does not exist, please update the package!`);
269
310
  } else {
@@ -292,21 +333,22 @@ function useVSCodePlugin(options) {
292
333
  };
293
334
  logger.info("extension build start");
294
335
  let buildCount = 0;
336
+ const webview = opts == null ? void 0 : opts.webview;
295
337
  const { onSuccess: _onSuccess, ...tsupOptions } = opts.extension || {};
296
338
  await tsupBuild(
297
339
  merge(tsupOptions, {
298
340
  watch: true,
299
341
  env,
300
342
  silent: true,
301
- esbuildPlugins: [
343
+ esbuildPlugins: !webview ? [] : [
302
344
  {
303
345
  name: "@tomjs:vscode:inject",
304
346
  setup(build) {
305
347
  build.onLoad({ filter: /\.ts$/ }, async (args) => {
306
348
  const file = fs2.readFileSync(args.path, "utf-8");
307
- if (file.includes(`${opts.webview}(`)) {
349
+ if (file.includes(`${webview.name}(`)) {
308
350
  return {
309
- contents: `import ${opts.webview} from '@tomjs/vscode-extension-webview';
351
+ contents: `import ${webview.name} from '@tomjs/vscode-extension-webview';
310
352
  ` + file,
311
353
  loader: "ts"
312
354
  };
@@ -357,10 +399,11 @@ function useVSCodePlugin(options) {
357
399
  },
358
400
  closeBundle() {
359
401
  let webviewPath;
360
- if (opts.webview) {
361
- webviewPath = genProdWebviewCode(prodHtmlCache);
402
+ const webview = opts == null ? void 0 : opts.webview;
403
+ if (webview) {
404
+ webviewPath = genProdWebviewCode(prodHtmlCache, webview);
362
405
  }
363
- let outDir = buildConfig.build.outDir.replace(cwd(), "").replaceAll("\\", "/");
406
+ let outDir = buildConfig.build.outDir.replace(cwd2(), "").replaceAll("\\", "/");
364
407
  if (outDir.startsWith("/")) {
365
408
  outDir = outDir.substring(1);
366
409
  }
@@ -374,15 +417,15 @@ function useVSCodePlugin(options) {
374
417
  merge(tsupOptions, {
375
418
  env,
376
419
  silent: true,
377
- esbuildPlugins: !opts.webview ? [] : [
420
+ esbuildPlugins: !webview ? [] : [
378
421
  {
379
422
  name: "@tomjs:vscode:inject",
380
423
  setup(build) {
381
424
  build.onLoad({ filter: /\.ts$/ }, async (args) => {
382
425
  const file = fs2.readFileSync(args.path, "utf-8");
383
- if (file.includes(`${opts.webview}(`)) {
426
+ if (file.includes(`${webview.name}(`)) {
384
427
  return {
385
- contents: `import ${opts.webview} from \`${webviewPath}\`;
428
+ contents: `import ${webview.name} from \`${webviewPath}\`;
386
429
  ` + file,
387
430
  loader: "ts"
388
431
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomjs/vite-plugin-vscode",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "Use vue/react to develop 'vscode extension webview', supporting esm/cjs",
5
5
  "keywords": [
6
6
  "vite",
@@ -66,7 +66,6 @@
66
66
  "eslint": "^8.56.0",
67
67
  "husky": "^8.0.3",
68
68
  "lint-staged": "^15.2.0",
69
- "np": "^9.2.0",
70
69
  "npm-run-all": "^4.1.5",
71
70
  "prettier": "^3.2.2",
72
71
  "rimraf": "^5.0.5",