@tomjs/vite-plugin-vscode 2.5.4 → 2.5.5

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/dist/index.mjs ADDED
@@ -0,0 +1,404 @@
1
+ // node_modules/.pnpm/tsup@7.2.0_@swc+core@1.3.100_postcss@8.4.32_typescript@5.3.3/node_modules/tsup/assets/esm_shims.js
2
+ import { fileURLToPath } from "url";
3
+ import path from "path";
4
+ var getFilename = () => fileURLToPath(import.meta.url);
5
+ var getDirname = () => path.dirname(getFilename());
6
+ var __dirname = /* @__PURE__ */ getDirname();
7
+
8
+ // src/index.ts
9
+ import fs from "fs";
10
+ import os from "os";
11
+ import path2 from "path";
12
+ import { cwd } from "process";
13
+ import cloneDeep from "lodash.clonedeep";
14
+ import merge from "lodash.merge";
15
+ import { parse as htmlParser } from "node-html-parser";
16
+ import { build as tsupBuild } from "tsup";
17
+ import { emptyDirSync, readFileSync, readJsonSync } from "@tomjs/node";
18
+
19
+ // src/constants.ts
20
+ var PLUGIN_NAME = "tomjs:vscode";
21
+ var PACKAGE_NAME = "@tomjs/vite-plugin-vscode";
22
+ var WEBVIEW_METHOD_NAME = "__getWebviewHtml__";
23
+
24
+ // src/logger.ts
25
+ import dayjs from "dayjs";
26
+ import { blue, gray, green, red, yellow } from "kolorist";
27
+ var Logger = class {
28
+ constructor(tag, withTime) {
29
+ this.tag = PLUGIN_NAME;
30
+ this.withTime = true;
31
+ this.tag = `[${tag}]`;
32
+ this.withTime = withTime ?? true;
33
+ }
34
+ getTime() {
35
+ return `${this.withTime ? dayjs().format("HH:mm:ss") : ""} `;
36
+ }
37
+ /**
38
+ * 调试
39
+ */
40
+ debug(msg, ...rest) {
41
+ console.log(`${this.getTime()}${gray(this.tag)}`, msg, ...rest);
42
+ }
43
+ /**
44
+ * 调试日志 等同 debug
45
+ */
46
+ log(msg, ...rest) {
47
+ this.debug(msg, ...rest);
48
+ }
49
+ info(msg, ...rest) {
50
+ console.log(`${this.getTime()}${blue(this.tag)}`, msg, ...rest);
51
+ }
52
+ warn(msg, ...rest) {
53
+ console.log(`${this.getTime()}${yellow(this.tag)}`, msg, ...rest);
54
+ }
55
+ error(msg, ...rest) {
56
+ console.log(`${this.getTime()}${red(this.tag)}`, msg, ...rest);
57
+ }
58
+ success(msg, ...rest) {
59
+ console.log(`${this.getTime()}${green(this.tag)}`, msg, ...rest);
60
+ }
61
+ };
62
+ var createLogger = (tag) => {
63
+ return new Logger(tag || PLUGIN_NAME, true);
64
+ };
65
+
66
+ // src/utils.ts
67
+ function resolveHostname(hostname) {
68
+ const loopbackHosts = /* @__PURE__ */ new Set([
69
+ "localhost",
70
+ "127.0.0.1",
71
+ "::1",
72
+ "0000:0000:0000:0000:0000:0000:0000:0001"
73
+ ]);
74
+ const wildcardHosts = /* @__PURE__ */ new Set(["0.0.0.0", "::", "0000:0000:0000:0000:0000:0000:0000:0000"]);
75
+ return loopbackHosts.has(hostname) || wildcardHosts.has(hostname) ? "localhost" : hostname;
76
+ }
77
+ function resolveServerUrl(server) {
78
+ const addressInfo = server.httpServer.address();
79
+ const isAddressInfo = (x) => x == null ? void 0 : x.address;
80
+ if (isAddressInfo(addressInfo)) {
81
+ const { address, port } = addressInfo;
82
+ const hostname = resolveHostname(address);
83
+ const options = server.config.server;
84
+ const protocol = options.https ? "https" : "http";
85
+ const devBase = server.config.base;
86
+ const path3 = typeof options.open === "string" ? options.open : devBase;
87
+ const url = path3.startsWith("http") ? path3 : `${protocol}://${hostname}:${port}${path3}`;
88
+ return url;
89
+ }
90
+ }
91
+
92
+ // src/index.ts
93
+ var isDev = process.env.NODE_ENV === "development";
94
+ var logger = createLogger();
95
+ function getPkg() {
96
+ const pkgFile = path2.resolve(process.cwd(), "package.json");
97
+ if (!fs.existsSync(pkgFile)) {
98
+ throw new Error("Main file is not specified, and no package.json found");
99
+ }
100
+ const pkg = readJsonSync(pkgFile);
101
+ if (!pkg.main) {
102
+ throw new Error("Main file is not specified, please check package.json");
103
+ }
104
+ return pkg;
105
+ }
106
+ function preMergeOptions(options) {
107
+ const pkg = getPkg();
108
+ const opts = merge(
109
+ {
110
+ webview: true,
111
+ recommended: true,
112
+ debug: false,
113
+ extension: {
114
+ entry: "extension/index.ts",
115
+ outDir: "dist-extension",
116
+ target: ["es2019", "node14"],
117
+ format: "cjs",
118
+ shims: true,
119
+ clean: true,
120
+ dts: false,
121
+ treeshake: isDev ? false : "smallest",
122
+ outExtension() {
123
+ return { js: ".js" };
124
+ },
125
+ external: ["vscode"],
126
+ skipNodeModulesBundle: isDev
127
+ }
128
+ },
129
+ cloneDeep(options)
130
+ );
131
+ const opt = opts.extension || {};
132
+ ["entry", "format"].forEach((prop) => {
133
+ const value = opt[prop];
134
+ if (!Array.isArray(value) && value) {
135
+ opt[prop] = [value];
136
+ }
137
+ });
138
+ if (isDev) {
139
+ opt.sourcemap = opt.sourcemap ?? true;
140
+ } else {
141
+ opt.minify ??= true;
142
+ }
143
+ opt.external = ["vscode"].concat(opt.external ?? []);
144
+ if (!opt.skipNodeModulesBundle) {
145
+ opt.noExternal = Object.keys(pkg.dependencies || {}).concat(
146
+ Object.keys(pkg.peerDependencies || {})
147
+ );
148
+ }
149
+ opts.extension = opt;
150
+ if (opts.webview !== false) {
151
+ let name = WEBVIEW_METHOD_NAME;
152
+ if (typeof opts.webview === "string") {
153
+ name = opts.webview ?? WEBVIEW_METHOD_NAME;
154
+ }
155
+ opts.webview = Object.assign({ name }, opts.webview);
156
+ }
157
+ return opts;
158
+ }
159
+ var prodCachePkgName = `${PACKAGE_NAME}-inject`;
160
+ function genProdWebviewCode(cache, webview) {
161
+ webview = Object.assign({}, webview);
162
+ const prodCacheFolder = path2.join(cwd(), "node_modules", prodCachePkgName);
163
+ emptyDirSync(prodCacheFolder);
164
+ const destFile = path2.join(prodCacheFolder, "index.ts");
165
+ function handleHtmlCode(html) {
166
+ const root = htmlParser(html);
167
+ const head = root.querySelector("head");
168
+ if (!head) {
169
+ root == null ? void 0 : root.insertAdjacentHTML("beforeend", "<head></head>");
170
+ }
171
+ 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';">`;
172
+ head.insertAdjacentHTML("afterbegin", csp);
173
+ if (csp && csp.includes("{{nonce}}")) {
174
+ const tags = {
175
+ script: "src",
176
+ link: "href"
177
+ };
178
+ Object.keys(tags).forEach((tag) => {
179
+ const elements = root.querySelectorAll(tag);
180
+ elements.forEach((element) => {
181
+ const attr = element.getAttribute(tags[tag]);
182
+ if (attr) {
183
+ element.setAttribute(tags[tag], `{{baseUri}}${attr}`);
184
+ }
185
+ element.setAttribute("nonce", "{{nonce}}");
186
+ });
187
+ });
188
+ }
189
+ return root.removeWhitespace().toString();
190
+ }
191
+ const cacheCode = (
192
+ /* js */
193
+ `const htmlCode = {
194
+ ${Object.keys(cache).map((s) => `${s}: \`${handleHtmlCode(cache[s])}\`,`).join("\n")}
195
+ };`
196
+ );
197
+ const code = (
198
+ /* js */
199
+ `import { ExtensionContext, Uri, Webview } from 'vscode';
200
+
201
+ ${cacheCode}
202
+
203
+ function uuid() {
204
+ let text = '';
205
+ const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
206
+ for (let i = 0; i < 32; i++) {
207
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
208
+ }
209
+ return text;
210
+ }
211
+
212
+ export default function getWebviewHtml(webview: Webview, context: ExtensionContext, inputName?:string){
213
+ const nonce = uuid();
214
+ const baseUri = webview.asWebviewUri(Uri.joinPath(context.extensionUri, (process.env.VITE_WEBVIEW_DIST || 'dist')));
215
+ const html = htmlCode[inputName || 'index'] || '';
216
+ return html.replaceAll('{{cspSource}}', webview.cspSource).replaceAll('{{nonce}}', nonce).replaceAll('{{baseUri}}', baseUri);
217
+ }
218
+ `
219
+ );
220
+ fs.writeFileSync(destFile, code, { encoding: "utf8" });
221
+ return fixWindowsPath(destFile);
222
+ }
223
+ function fixWindowsPath(webviewPath) {
224
+ if (os.platform() === "win32") {
225
+ webviewPath = webviewPath.replaceAll("\\", "/");
226
+ }
227
+ return webviewPath;
228
+ }
229
+ function useVSCodePlugin(options) {
230
+ const opts = preMergeOptions(options);
231
+ const handleConfig = (config) => {
232
+ var _a, _b, _c, _d, _e;
233
+ let outDir = ((_a = config == null ? void 0 : config.build) == null ? void 0 : _a.outDir) || "dist";
234
+ opts.extension ??= {};
235
+ if (opts.recommended) {
236
+ opts.extension.outDir = path2.resolve(outDir, "extension");
237
+ outDir = path2.resolve(outDir, "webview");
238
+ }
239
+ const assetsDir = ((_b = config == null ? void 0 : config.build) == null ? void 0 : _b.assetsDir) || "assets";
240
+ const output = {
241
+ chunkFileNames: `${assetsDir}/[name].js`,
242
+ entryFileNames: `${assetsDir}/[name].js`,
243
+ assetFileNames: `${assetsDir}/[name].[ext]`
244
+ };
245
+ let rollupOutput = ((_d = (_c = config == null ? void 0 : config.build) == null ? void 0 : _c.rollupOptions) == null ? void 0 : _d.output) ?? {};
246
+ if (Array.isArray(rollupOutput)) {
247
+ rollupOutput.map((s) => Object.assign(s, output));
248
+ } else {
249
+ rollupOutput = Object.assign({}, rollupOutput, output);
250
+ }
251
+ return {
252
+ build: {
253
+ outDir,
254
+ sourcemap: isDev ? true : (_e = config == null ? void 0 : config.build) == null ? void 0 : _e.sourcemap,
255
+ rollupOptions: {
256
+ output: rollupOutput
257
+ }
258
+ }
259
+ };
260
+ };
261
+ let devWebviewClient;
262
+ if (opts.webview) {
263
+ devWebviewClient = readFileSync(path2.join(__dirname, "client.global.js"));
264
+ }
265
+ let buildConfig;
266
+ const prodHtmlCache = {};
267
+ return [
268
+ {
269
+ name: "@tomjs:vscode",
270
+ apply: "serve",
271
+ config(config) {
272
+ return handleConfig(config);
273
+ },
274
+ configureServer(server) {
275
+ var _a;
276
+ if (!server || !server.httpServer) {
277
+ return;
278
+ }
279
+ (_a = server.httpServer) == null ? void 0 : _a.once("listening", async () => {
280
+ const env = {
281
+ NODE_ENV: server.config.mode || "development",
282
+ VITE_DEV_SERVER_URL: resolveServerUrl(server)
283
+ };
284
+ logger.info("extension build start");
285
+ let buildCount = 0;
286
+ const webview = opts == null ? void 0 : opts.webview;
287
+ const { onSuccess: _onSuccess, ...tsupOptions } = opts.extension || {};
288
+ await tsupBuild(
289
+ merge(tsupOptions, {
290
+ watch: true,
291
+ env,
292
+ silent: true,
293
+ esbuildPlugins: !webview ? [] : [
294
+ {
295
+ name: "@tomjs:vscode:inject",
296
+ setup(build) {
297
+ build.onLoad({ filter: /\.ts$/ }, async (args) => {
298
+ const file = fs.readFileSync(args.path, "utf-8");
299
+ if (file.includes(`${webview.name}(`)) {
300
+ return {
301
+ contents: `import ${webview.name} from '${PACKAGE_NAME}/webview';
302
+ ` + file,
303
+ loader: "ts"
304
+ };
305
+ }
306
+ return {};
307
+ });
308
+ }
309
+ }
310
+ ],
311
+ async onSuccess() {
312
+ if (typeof _onSuccess === "function") {
313
+ await _onSuccess();
314
+ }
315
+ if (buildCount++ > 1) {
316
+ logger.info("extension rebuild success");
317
+ } else {
318
+ logger.info("extension build success");
319
+ }
320
+ }
321
+ })
322
+ );
323
+ });
324
+ },
325
+ transformIndexHtml(html) {
326
+ if (!opts.webview) {
327
+ return html;
328
+ }
329
+ return html.replace(/<\/title>/i, `</title><script>${devWebviewClient}</script>`);
330
+ }
331
+ },
332
+ {
333
+ name: "@tomjs:vscode",
334
+ apply: "build",
335
+ enforce: "post",
336
+ config(config) {
337
+ return handleConfig(config);
338
+ },
339
+ configResolved(config) {
340
+ buildConfig = config;
341
+ },
342
+ transformIndexHtml(html, ctx) {
343
+ var _a;
344
+ if (!opts.webview) {
345
+ return html;
346
+ }
347
+ prodHtmlCache[(_a = ctx.chunk) == null ? void 0 : _a.name] = html;
348
+ return html;
349
+ },
350
+ closeBundle() {
351
+ let webviewPath;
352
+ const webview = opts == null ? void 0 : opts.webview;
353
+ if (webview) {
354
+ webviewPath = genProdWebviewCode(prodHtmlCache, webview);
355
+ }
356
+ let outDir = buildConfig.build.outDir.replace(cwd(), "").replaceAll("\\", "/");
357
+ if (outDir.startsWith("/")) {
358
+ outDir = outDir.substring(1);
359
+ }
360
+ const env = {
361
+ NODE_ENV: buildConfig.mode || "production",
362
+ VITE_WEBVIEW_DIST: outDir
363
+ };
364
+ logger.info("extension build start");
365
+ const { onSuccess: _onSuccess, ...tsupOptions } = opts.extension || {};
366
+ tsupBuild(
367
+ merge(tsupOptions, {
368
+ env,
369
+ silent: true,
370
+ esbuildPlugins: !webview ? [] : [
371
+ {
372
+ name: "@tomjs:vscode:inject",
373
+ setup(build) {
374
+ build.onLoad({ filter: /\.ts$/ }, async (args) => {
375
+ const file = fs.readFileSync(args.path, "utf-8");
376
+ if (file.includes(`${webview.name}(`)) {
377
+ return {
378
+ contents: `import ${webview.name} from \`${webviewPath}\`;
379
+ ` + file,
380
+ loader: "ts"
381
+ };
382
+ }
383
+ return {};
384
+ });
385
+ }
386
+ }
387
+ ],
388
+ async onSuccess() {
389
+ if (typeof _onSuccess === "function") {
390
+ await _onSuccess();
391
+ }
392
+ logger.info("extension build success");
393
+ }
394
+ })
395
+ );
396
+ }
397
+ }
398
+ ];
399
+ }
400
+ var src_default = useVSCodePlugin;
401
+ export {
402
+ src_default as default,
403
+ useVSCodePlugin
404
+ };
@@ -0,0 +1,13 @@
1
+ interface WebviewHtmlDevOptions {
2
+ /**
3
+ * local server url
4
+ */
5
+ serverUrl: string;
6
+ }
7
+ /**
8
+ *
9
+ * @param options serverUrl string or object options
10
+ */
11
+ declare function getHtml(options: string | WebviewHtmlDevOptions): string;
12
+
13
+ export { WebviewHtmlDevOptions, getHtml as default, getHtml };
@@ -0,0 +1,13 @@
1
+ interface WebviewHtmlDevOptions {
2
+ /**
3
+ * local server url
4
+ */
5
+ serverUrl: string;
6
+ }
7
+ /**
8
+ *
9
+ * @param options serverUrl string or object options
10
+ */
11
+ declare function getHtml(options: string | WebviewHtmlDevOptions): string;
12
+
13
+ export { WebviewHtmlDevOptions, getHtml as default, getHtml };
@@ -0,0 +1,207 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/webview/template.html
2
+ var template_default = `<!doctype html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <style>
9
+ html,
10
+ body {
11
+ width: 100%;
12
+ height: 100%;
13
+ margin: 0;
14
+ padding: 0;
15
+ overflow: hidden;
16
+ }
17
+
18
+ #webview-patch-iframe {
19
+ width: 100%;
20
+ height: 100%;
21
+ border: none;
22
+ }
23
+
24
+ .outer {
25
+ width: 100%;
26
+ height: 100%;
27
+ overflow: hidden;
28
+ }
29
+ </style>
30
+
31
+ <script type="module" id="webview-patch">
32
+ const TAG = '[@tomjs:vscode:extension] ';
33
+
34
+ function onDomReady(callback, doc) {
35
+ const _doc = doc || document;
36
+ if (_doc.readyState === 'interactive' || _doc.readyState === 'complete') {
37
+ callback();
38
+ } else {
39
+ _doc.addEventListener('DOMContentLoaded', callback);
40
+ }
41
+ }
42
+
43
+ let vsCodeApi;
44
+
45
+ function getApi() {
46
+ if (vsCodeApi) return vsCodeApi;
47
+ return (vsCodeApi = acquireVsCodeApi());
48
+ }
49
+
50
+ function sendInitData(iframe) {
51
+ console.log(TAG + 'init data');
52
+ const dataset = {};
53
+ Object.keys(document.body.dataset).forEach(key => {
54
+ dataset[key] = document.body.dataset[key];
55
+ });
56
+
57
+ iframe.contentWindow.postMessage(
58
+ {
59
+ type: '[vscode:extension]:init',
60
+ data: {
61
+ state: getApi().getState(),
62
+ style: document.getElementById('_defaultStyles').innerHTML,
63
+ root: {
64
+ cssText: document.documentElement.style.cssText,
65
+ },
66
+ body: {
67
+ dataset: dataset,
68
+ className: document.body.className,
69
+ role: document.body.getAttribute('role'),
70
+ },
71
+ },
72
+ },
73
+ '*',
74
+ );
75
+ }
76
+
77
+ function observeAttributeChanges(element, attributeName, callback) {
78
+ const observer = new MutationObserver(function (mutationsList) {
79
+ for (let mutation of mutationsList) {
80
+ if (mutation.type === 'attributes' && mutation.attributeName === attributeName) {
81
+ callback(mutation.target.getAttribute(attributeName));
82
+ }
83
+ }
84
+ });
85
+ observer.observe(element, { attributes: true });
86
+ return observer;
87
+ }
88
+
89
+ // message handler
90
+ let iframeLoaded = false;
91
+ const cacheMessages = [];
92
+
93
+ function handleMessage(e) {
94
+ const iframe = document.getElementById('webview-patch-iframe');
95
+ if (!iframeLoaded || !iframe) {
96
+ return;
97
+ }
98
+ if (e.origin.startsWith('vscode-webview://')) {
99
+ iframe.contentWindow.postMessage(e.data, '*');
100
+ } else if ('{{serverUrl}}'.startsWith(e.origin)) {
101
+ const { type, data } = e.data;
102
+ console.log(TAG + ' received:', e.data);
103
+ if (type === '[vscode:client]:postMessage') {
104
+ getApi().postMessage(data);
105
+ } else if (type === '[vscode:client]:getState') {
106
+ iframe.contentWindow.postMessage(
107
+ {
108
+ type: '[vscode:client]:getState',
109
+ data: getApi().getState(),
110
+ },
111
+ '*',
112
+ );
113
+ } else if (type === '[vscode:client]:setState') {
114
+ getApi().setState(data);
115
+ }
116
+ }
117
+ }
118
+
119
+ window.addEventListener('message', function (event) {
120
+ if (event.origin.startsWith('vscode-webview://')) {
121
+ cacheMessages.push(event);
122
+ return;
123
+ }
124
+ handleMessage(event);
125
+ });
126
+
127
+ let isCacheWorking = false;
128
+ setInterval(() => {
129
+ if (isCacheWorking) {
130
+ return;
131
+ }
132
+
133
+ isCacheWorking = true;
134
+ if (iframeLoaded) {
135
+ let event = cacheMessages.shift();
136
+ while (event) {
137
+ handleMessage(event);
138
+ event = cacheMessages.shift();
139
+ }
140
+ }
141
+ isCacheWorking = false;
142
+ }, 50);
143
+
144
+ onDomReady(function () {
145
+ /** @type {HTMLIFrameElement} */
146
+ const iframe = document.getElementById('webview-patch-iframe');
147
+ observeAttributeChanges(document.body, 'class', function (className) {
148
+ sendInitData(iframe);
149
+ });
150
+
151
+ onDomReady(function () {
152
+ iframeLoaded = true;
153
+ sendInitData(iframe);
154
+ }, iframe.contentDocument);
155
+
156
+ iframe.addEventListener('load', function (e) {
157
+ iframeLoaded = true;
158
+
159
+ let interval = setInterval(() => {
160
+ try {
161
+ if (document.getElementById('_defaultStyles')) {
162
+ sendInitData(iframe);
163
+ // addListeners(iframe);
164
+ clearInterval(interval);
165
+ return;
166
+ }
167
+ } catch (e) {
168
+ clearInterval(interval);
169
+ console.error(e);
170
+ }
171
+ }, 10);
172
+ });
173
+ });
174
+ </script>
175
+ </head>
176
+
177
+ <body>
178
+ <div class="outer">
179
+ <iframe
180
+ id="webview-patch-iframe"
181
+ frameborder="0"
182
+ sandbox="allow-scripts allow-same-origin allow-forms allow-pointer-lock allow-downloads"
183
+ allow="cross-origin-isolated; autoplay; clipboard-read; clipboard-write"
184
+ src="{{serverUrl}}"
185
+ ></iframe>
186
+ </div>
187
+ </body>
188
+ </html>
189
+ `;
190
+
191
+ // src/webview/webview.ts
192
+ function getHtml(options) {
193
+ const opts = {
194
+ serverUrl: ""
195
+ };
196
+ if (typeof options === "string") {
197
+ opts.serverUrl = options;
198
+ } else {
199
+ Object.assign(opts, options);
200
+ }
201
+ return template_default.replace(new RegExp("{{serverUrl}}", "g"), opts.serverUrl);
202
+ }
203
+ var webview_default = getHtml;
204
+
205
+
206
+
207
+ exports.default = webview_default; exports.getHtml = getHtml;