@tomjs/vite-plugin-hbuilderx 1.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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/client.iife.js +42 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +336 -0
- package/dist/webview.d.ts +14 -0
- package/dist/webview.js +18 -0
- package/env-hbuilderx.d.ts +36 -0
- package/env.d.ts +24 -0
- package/eslint.config.mjs +6 -0
- package/package.json +64 -0
- package/src/constants.ts +4 -0
- package/src/index.ts +420 -0
- package/src/logger.ts +9 -0
- package/src/types.ts +81 -0
- package/src/utils.ts +36 -0
- package/src/webview/client.ts +47 -0
- package/src/webview/global.d.ts +4 -0
- package/src/webview/template.html +90 -0
- package/src/webview/webview.ts +25 -0
- package/src/webview/window.d.ts +9 -0
- package/tsconfig.json +15 -0
- package/tsconfig.web.json +9 -0
- package/tsdown.config.ts +38 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { cwd } from "node:process";
|
|
5
|
+
import { readFileSync, readJsonSync } from "@tomjs/node";
|
|
6
|
+
import { execa } from "execa";
|
|
7
|
+
import merge from "lodash.merge";
|
|
8
|
+
import { parse } from "node-html-parser";
|
|
9
|
+
import colors from "picocolors";
|
|
10
|
+
import { build } from "tsdown";
|
|
11
|
+
import Logger from "@tomjs/logger";
|
|
12
|
+
|
|
13
|
+
//#region ../../node_modules/.pnpm/tsdown@0.18.4_publint@0.3.16_synckit@0.11.11_typescript@5.9.3_vue-tsc@3.2.1_typescript@5.9.3_/node_modules/tsdown/esm-shims.js
|
|
14
|
+
const getFilename = () => fileURLToPath(import.meta.url);
|
|
15
|
+
const getDirname = () => path.dirname(getFilename());
|
|
16
|
+
const __dirname = /* @__PURE__ */ getDirname();
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/constants.ts
|
|
20
|
+
const PLUGIN_NAME = "tomjs:hbuilderx";
|
|
21
|
+
const ORG_NAME = "@tomjs";
|
|
22
|
+
const VIRTUAL_MODULE_ID = "virtual:hbuilderx";
|
|
23
|
+
const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/logger.ts
|
|
27
|
+
function createLogger() {
|
|
28
|
+
return new Logger({
|
|
29
|
+
prefix: `[${PLUGIN_NAME}]`,
|
|
30
|
+
time: true
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/utils.ts
|
|
36
|
+
/**
|
|
37
|
+
* @see https://github.com/vitejs/vite/blob/v4.0.1/packages/vite/src/node/constants.ts#L137-L147
|
|
38
|
+
*/
|
|
39
|
+
function resolveHostname(hostname) {
|
|
40
|
+
const loopbackHosts = new Set([
|
|
41
|
+
"localhost",
|
|
42
|
+
"127.0.0.1",
|
|
43
|
+
"::1",
|
|
44
|
+
"0000:0000:0000:0000:0000:0000:0000:0001"
|
|
45
|
+
]);
|
|
46
|
+
const wildcardHosts = new Set([
|
|
47
|
+
"0.0.0.0",
|
|
48
|
+
"::",
|
|
49
|
+
"0000:0000:0000:0000:0000:0000:0000:0000"
|
|
50
|
+
]);
|
|
51
|
+
return loopbackHosts.has(hostname) || wildcardHosts.has(hostname) ? "localhost" : hostname;
|
|
52
|
+
}
|
|
53
|
+
function resolveServerUrl(server) {
|
|
54
|
+
const addressInfo = server.httpServer.address();
|
|
55
|
+
const isAddressInfo = (x) => x?.address;
|
|
56
|
+
if (isAddressInfo(addressInfo)) {
|
|
57
|
+
const { address, port } = addressInfo;
|
|
58
|
+
const hostname = resolveHostname(address);
|
|
59
|
+
const options = server.config.server;
|
|
60
|
+
const protocol = options.https ? "https" : "http";
|
|
61
|
+
const devBase = server.config.base;
|
|
62
|
+
const path$1 = typeof options.open === "string" ? options.open : devBase;
|
|
63
|
+
return path$1.startsWith("http") ? path$1 : `${protocol}://${hostname}:${port}${path$1}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/index.ts
|
|
69
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
70
|
+
const logger = createLogger();
|
|
71
|
+
function getPkg() {
|
|
72
|
+
const pkgFile = path.resolve(process.cwd(), "package.json");
|
|
73
|
+
if (!fs.existsSync(pkgFile)) throw new Error("项目中未找到 package.json 文件");
|
|
74
|
+
const pkg = readJsonSync(pkgFile);
|
|
75
|
+
if (!pkg.main) throw new Error("package.json 文件未配置 main 入口文件");
|
|
76
|
+
return pkg;
|
|
77
|
+
}
|
|
78
|
+
function preMergeOptions(options) {
|
|
79
|
+
const pkg = getPkg();
|
|
80
|
+
const opts = merge({
|
|
81
|
+
webview: true,
|
|
82
|
+
recommended: true,
|
|
83
|
+
extension: {
|
|
84
|
+
entry: "extension/index.ts",
|
|
85
|
+
outDir: "dist-extension",
|
|
86
|
+
target: ["es2019", "node16"],
|
|
87
|
+
format: "cjs",
|
|
88
|
+
shims: true,
|
|
89
|
+
clean: true,
|
|
90
|
+
dts: false,
|
|
91
|
+
treeshake: !isDev,
|
|
92
|
+
publint: false,
|
|
93
|
+
config: false,
|
|
94
|
+
fixedExtension: false,
|
|
95
|
+
external: ["hbuilderx"]
|
|
96
|
+
}
|
|
97
|
+
}, options);
|
|
98
|
+
const opt = opts.extension || {};
|
|
99
|
+
if (isDev) opt.sourcemap = opt.sourcemap ?? true;
|
|
100
|
+
else {
|
|
101
|
+
opt.minify ??= true;
|
|
102
|
+
opt.clean ??= true;
|
|
103
|
+
}
|
|
104
|
+
if (typeof opt.external !== "function") {
|
|
105
|
+
opt.external = ["hbuilderx"].concat(opt.external ?? []);
|
|
106
|
+
opt.external = [...new Set(opt.external)];
|
|
107
|
+
} else {
|
|
108
|
+
const fn = opt.external;
|
|
109
|
+
opt.external = function(id, parentId, isResolved) {
|
|
110
|
+
if (id === "hbuilderx") return true;
|
|
111
|
+
return fn(id, parentId, isResolved);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (!isDev && !opt.skipNodeModulesBundle && !opt.noExternal) opt.noExternal = Object.keys(pkg.dependencies || {}).concat(Object.keys(pkg.peerDependencies || {}));
|
|
115
|
+
opts.extension = opt;
|
|
116
|
+
return opts;
|
|
117
|
+
}
|
|
118
|
+
function genProdWebviewCode(cache) {
|
|
119
|
+
function handleHtmlCode(html) {
|
|
120
|
+
const root = parse(html);
|
|
121
|
+
const head = root.querySelector("head");
|
|
122
|
+
if (!head) root?.insertAdjacentHTML("beforeend", "<head></head>");
|
|
123
|
+
head.insertAdjacentHTML("afterbegin", "<style>:root{--root-background-color:#fffae8;background-color:var(--root-background-color)}</style>");
|
|
124
|
+
const tags = {
|
|
125
|
+
script: "src",
|
|
126
|
+
link: "href"
|
|
127
|
+
};
|
|
128
|
+
Object.keys(tags).forEach((tag) => {
|
|
129
|
+
root.querySelectorAll(tag).forEach((element) => {
|
|
130
|
+
const attr = element.getAttribute(tags[tag]);
|
|
131
|
+
if (attr) element.setAttribute(tags[tag], `{{baseUri}}${attr}`);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
return root.removeWhitespace().toString();
|
|
135
|
+
}
|
|
136
|
+
return `import path from 'path';
|
|
137
|
+
import { workspace } from 'hbuilderx';
|
|
138
|
+
|
|
139
|
+
${`const htmlCode = {
|
|
140
|
+
${Object.keys(cache).map((s) => `'${s}': \`${handleHtmlCode(cache[s])}\`,`).join("\n")}
|
|
141
|
+
};`}
|
|
142
|
+
|
|
143
|
+
export function getWebviewHtml(options){
|
|
144
|
+
const { context, inputName, injectCode } = options || {};
|
|
145
|
+
const baseUri = path.join(context.extensionPath, process.env.VITE_WEBVIEW_DIST || 'dist');
|
|
146
|
+
let html = htmlCode[inputName || 'index'] || '';
|
|
147
|
+
if (injectCode) {
|
|
148
|
+
html = html.replace('<head>', '<head>'+ injectCode);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return html.replaceAll('{{baseUri}}', baseUri);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default getWebviewHtml;
|
|
155
|
+
`;
|
|
156
|
+
}
|
|
157
|
+
function useHBuilderxPlugin(options) {
|
|
158
|
+
const opts = preMergeOptions(options);
|
|
159
|
+
const handleConfig = (config) => {
|
|
160
|
+
let outDir = config?.build?.outDir || "dist";
|
|
161
|
+
opts.extension ??= {};
|
|
162
|
+
if (opts.recommended) {
|
|
163
|
+
opts.extension.outDir = path.resolve(outDir, "extension");
|
|
164
|
+
outDir = path.resolve(outDir, "webview");
|
|
165
|
+
}
|
|
166
|
+
const assetsDir = config?.build?.assetsDir || "assets";
|
|
167
|
+
const output = {
|
|
168
|
+
chunkFileNames: `${assetsDir}/[name].js`,
|
|
169
|
+
entryFileNames: `${assetsDir}/[name].js`,
|
|
170
|
+
assetFileNames: `${assetsDir}/[name].[ext]`
|
|
171
|
+
};
|
|
172
|
+
let rollupOutput = config?.build?.rollupOptions?.output ?? {};
|
|
173
|
+
if (Array.isArray(rollupOutput)) rollupOutput.map((s) => Object.assign(s, output));
|
|
174
|
+
else rollupOutput = Object.assign({}, rollupOutput, output);
|
|
175
|
+
return { build: {
|
|
176
|
+
outDir,
|
|
177
|
+
sourcemap: isDev ? true : config?.build?.sourcemap,
|
|
178
|
+
rollupOptions: { output: rollupOutput }
|
|
179
|
+
} };
|
|
180
|
+
};
|
|
181
|
+
let devWebviewClientCode;
|
|
182
|
+
let devWebviewVirtualCode;
|
|
183
|
+
let resolvedConfig;
|
|
184
|
+
const prodHtmlCache = {};
|
|
185
|
+
function isVue() {
|
|
186
|
+
return !!resolvedConfig.plugins.find((s) => ["vite:vue", "vite:vue2"].includes(s.name));
|
|
187
|
+
}
|
|
188
|
+
function isReact() {
|
|
189
|
+
return !!resolvedConfig.plugins.find((s) => ["vite:react-refresh", "vite:react-swc"].includes(s.name));
|
|
190
|
+
}
|
|
191
|
+
function getDevtoolsPort() {
|
|
192
|
+
const devtools = opts.devtools;
|
|
193
|
+
if (!devtools) return;
|
|
194
|
+
let port;
|
|
195
|
+
if (typeof devtools === "number") port = devtools;
|
|
196
|
+
else if (devtools === true) {
|
|
197
|
+
if (isVue()) port = 8098;
|
|
198
|
+
else if (isReact()) port = 8097;
|
|
199
|
+
}
|
|
200
|
+
return port;
|
|
201
|
+
}
|
|
202
|
+
return [{
|
|
203
|
+
name: "@tomjs:hbuilderx",
|
|
204
|
+
apply: "serve",
|
|
205
|
+
config(config) {
|
|
206
|
+
return handleConfig(config);
|
|
207
|
+
},
|
|
208
|
+
configResolved(config) {
|
|
209
|
+
resolvedConfig = config;
|
|
210
|
+
if (opts.webview) {
|
|
211
|
+
devWebviewClientCode = readFileSync(path.join(__dirname, "client.iife.js"));
|
|
212
|
+
let refreshKey = "";
|
|
213
|
+
if (opts.webview === true) refreshKey = "F6";
|
|
214
|
+
else if (typeof opts.webview === "object" && opts.webview.refreshKey) refreshKey = opts.webview.refreshKey;
|
|
215
|
+
if (refreshKey) devWebviewClientCode = `window.TOMJS_REFRESH_KEY="${refreshKey}";${devWebviewClientCode}`;
|
|
216
|
+
devWebviewVirtualCode = readFileSync(path.join(__dirname, "webview.js"));
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
configureServer(server) {
|
|
220
|
+
if (!server || !server.httpServer) return;
|
|
221
|
+
server.httpServer?.once("listening", async () => {
|
|
222
|
+
const env = {
|
|
223
|
+
NODE_ENV: server.config.mode || "development",
|
|
224
|
+
VITE_DEV_SERVER_URL: resolveServerUrl(server)
|
|
225
|
+
};
|
|
226
|
+
logger.info("extension build start");
|
|
227
|
+
let buildCount = 0;
|
|
228
|
+
const webview = opts?.webview;
|
|
229
|
+
const { onSuccess: _onSuccess, ignoreWatch, logLevel, watchFiles, ...tsdownOptions } = opts.extension || {};
|
|
230
|
+
await build(merge(tsdownOptions, {
|
|
231
|
+
watch: watchFiles ?? (opts.recommended ? ["extension"] : true),
|
|
232
|
+
ignoreWatch: [
|
|
233
|
+
".history",
|
|
234
|
+
".temp",
|
|
235
|
+
".tmp",
|
|
236
|
+
".cache",
|
|
237
|
+
"dist"
|
|
238
|
+
].concat(Array.isArray(ignoreWatch) ? ignoreWatch : []),
|
|
239
|
+
env,
|
|
240
|
+
logLevel: logLevel ?? "silent",
|
|
241
|
+
plugins: !webview ? [] : [{
|
|
242
|
+
name: `${ORG_NAME}:hbuilderx:inject`,
|
|
243
|
+
resolveId(id) {
|
|
244
|
+
if (id === VIRTUAL_MODULE_ID) return RESOLVED_VIRTUAL_MODULE_ID;
|
|
245
|
+
},
|
|
246
|
+
load(id) {
|
|
247
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID) return devWebviewVirtualCode;
|
|
248
|
+
}
|
|
249
|
+
}],
|
|
250
|
+
async onSuccess(config, signal) {
|
|
251
|
+
if (_onSuccess) {
|
|
252
|
+
if (typeof _onSuccess === "string") await execa(_onSuccess);
|
|
253
|
+
else if (typeof _onSuccess === "function") await _onSuccess(config, signal);
|
|
254
|
+
}
|
|
255
|
+
if (buildCount++ > 1) logger.info("extension rebuild success");
|
|
256
|
+
else logger.info("extension build success");
|
|
257
|
+
}
|
|
258
|
+
}));
|
|
259
|
+
});
|
|
260
|
+
if (opts.devtools) {
|
|
261
|
+
const _printUrls = server.printUrls;
|
|
262
|
+
server.printUrls = () => {
|
|
263
|
+
_printUrls();
|
|
264
|
+
const { green, bold, blue } = colors;
|
|
265
|
+
if (isVue() || isReact()) {
|
|
266
|
+
const port = getDevtoolsPort();
|
|
267
|
+
if (port) {
|
|
268
|
+
const devtoolsUrl = `http://localhost:${port}`;
|
|
269
|
+
console.log(` ${green("➜")} ${bold(isVue() ? "Vue DevTools" : "React DevTools")}: 已开启独立应用支持,地址 ${blue(`${devtoolsUrl}`)}`);
|
|
270
|
+
}
|
|
271
|
+
} else console.log(` ${green("➜")} 仅支持 ${green("react-devtools")} 和 ${green("vue-devtools")}`);
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
transformIndexHtml(html) {
|
|
276
|
+
if (!opts.webview) return html;
|
|
277
|
+
if (opts.devtools) {
|
|
278
|
+
const port = getDevtoolsPort();
|
|
279
|
+
if (port) html = html.replace(/<head>/i, `<head><script src="http://localhost:${port}"><\/script>`);
|
|
280
|
+
}
|
|
281
|
+
return html.replace(/<head>/i, `<head><script>${devWebviewClientCode}<\/script>`);
|
|
282
|
+
}
|
|
283
|
+
}, {
|
|
284
|
+
name: "@tomjs:hbuilderx",
|
|
285
|
+
apply: "build",
|
|
286
|
+
enforce: "post",
|
|
287
|
+
config(config) {
|
|
288
|
+
return handleConfig(config);
|
|
289
|
+
},
|
|
290
|
+
configResolved(config) {
|
|
291
|
+
resolvedConfig = config;
|
|
292
|
+
},
|
|
293
|
+
transformIndexHtml(html, ctx) {
|
|
294
|
+
if (!opts.webview) return html;
|
|
295
|
+
prodHtmlCache[ctx.chunk?.name] = html;
|
|
296
|
+
return html;
|
|
297
|
+
},
|
|
298
|
+
closeBundle() {
|
|
299
|
+
let webviewVirtualCode;
|
|
300
|
+
const webview = opts?.webview;
|
|
301
|
+
if (webview) webviewVirtualCode = genProdWebviewCode(prodHtmlCache);
|
|
302
|
+
let outDir = resolvedConfig.build.outDir.replace(cwd(), "").replaceAll("\\", "/");
|
|
303
|
+
if (outDir.startsWith("/")) outDir = outDir.substring(1);
|
|
304
|
+
const env = {
|
|
305
|
+
NODE_ENV: resolvedConfig.mode || "production",
|
|
306
|
+
VITE_WEBVIEW_DIST: outDir
|
|
307
|
+
};
|
|
308
|
+
logger.info("extension build start");
|
|
309
|
+
const { onSuccess: _onSuccess, logLevel, ...tsupOptions } = opts.extension || {};
|
|
310
|
+
build(merge(tsupOptions, {
|
|
311
|
+
env,
|
|
312
|
+
logLevel: logLevel ?? "silent",
|
|
313
|
+
plugins: !webview ? [] : [{
|
|
314
|
+
name: `${ORG_NAME}:hbuilderx:inject`,
|
|
315
|
+
resolveId(id) {
|
|
316
|
+
if (id === VIRTUAL_MODULE_ID) return RESOLVED_VIRTUAL_MODULE_ID;
|
|
317
|
+
},
|
|
318
|
+
load(id) {
|
|
319
|
+
if (id === RESOLVED_VIRTUAL_MODULE_ID) return webviewVirtualCode;
|
|
320
|
+
}
|
|
321
|
+
}],
|
|
322
|
+
async onSuccess(config, signal) {
|
|
323
|
+
if (_onSuccess) {
|
|
324
|
+
if (typeof _onSuccess === "string") await execa(_onSuccess);
|
|
325
|
+
else if (typeof _onSuccess === "function") await _onSuccess(config, signal);
|
|
326
|
+
}
|
|
327
|
+
logger.info("extension build success");
|
|
328
|
+
}
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
}];
|
|
332
|
+
}
|
|
333
|
+
var src_default = useHBuilderxPlugin;
|
|
334
|
+
|
|
335
|
+
//#endregion
|
|
336
|
+
export { src_default as default, useHBuilderxPlugin };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/webview/webview.d.ts
|
|
2
|
+
interface WebviewHtmlOptions {
|
|
3
|
+
/**
|
|
4
|
+
* local server url
|
|
5
|
+
*/
|
|
6
|
+
serverUrl: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param options serverUrl string or object options
|
|
11
|
+
*/
|
|
12
|
+
declare function getWebviewHtml(options: WebviewHtmlOptions): string;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { WebviewHtmlOptions, getWebviewHtml as default, getWebviewHtml };
|
package/dist/webview.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/webview/template.html
|
|
2
|
+
var template_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <style>\n html,\n body {\n width: 100%;\n height: 100%;\n padding: 0;\n margin: 0;\n overflow: hidden;\n }\n\n #webview-patch-iframe {\n width: 100%;\n height: 100%;\n border: none;\n }\n\n .outer {\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n </style>\n\n <script type=\"module\" id=\"webview-patch\">\n const TAG = '[@tomjs:hbuilderx:extension] ';\n\n function onDomReady(callback, doc) {\n const _doc = doc || document;\n if (_doc.readyState === 'interactive' || _doc.readyState === 'complete') {\n callback();\n } else {\n _doc.addEventListener('DOMContentLoaded', callback);\n }\n }\n\n // message handler\n let iframeLoaded = false;\n const cacheMessages = [];\n\n onDomReady(function () {\n /** @type {HTMLIFrameElement} */\n const iframe = document.getElementById('webview-patch-iframe');\n\n onDomReady(function () {\n iframeLoaded = true;\n }, iframe.contentDocument);\n\n iframe.addEventListener('load', function (e) {\n iframeLoaded = true;\n });\n });\n\n function handleMessage(e) {\n const iframe = document.getElementById('webview-patch-iframe');\n if (!iframeLoaded || !iframe) {\n return;\n }\n if ('{{serverUrl}}'.startsWith(e.origin)) {\n const { type, data } = e.data;\n console.log(TAG + ' received:', e.data);\n if (type === '[hbuilderx:client]:postMessage') {\n hbuilderx.postMessage(data);\n }\n }\n }\n\n window.addEventListener('message', function (event) {\n handleMessage(event);\n });\n <\/script>\n </head>\n\n <body>\n <div class=\"outer\">\n <iframe\n id=\"webview-patch-iframe\"\n frameborder=\"0\"\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-pointer-lock allow-downloads\"\n allow=\"cross-origin-isolated; autoplay; clipboard-read; clipboard-write\"\n src=\"{{serverUrl}}\"\n ></iframe>\n </div>\n </body>\n</html>\n";
|
|
3
|
+
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/webview/webview.ts
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param options serverUrl string or object options
|
|
9
|
+
*/
|
|
10
|
+
function getWebviewHtml(options) {
|
|
11
|
+
const opts = { serverUrl: "" };
|
|
12
|
+
Object.assign(opts, options);
|
|
13
|
+
return template_default.replace(/\{\{serverUrl\}\}/g, opts.serverUrl);
|
|
14
|
+
}
|
|
15
|
+
var webview_default = getWebviewHtml;
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { webview_default as default, getWebviewHtml };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/// <reference types="@tomjs/hbuilderx/types" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 提供 webview 代码注入的虚拟模块
|
|
5
|
+
*/
|
|
6
|
+
declare module 'virtual:hbuilderx' {
|
|
7
|
+
import type { ExtensionContext } from 'hbuilderx';
|
|
8
|
+
|
|
9
|
+
export interface WebviewHtmlOptions {
|
|
10
|
+
/**
|
|
11
|
+
* `[vite serve]` vite dev 服务地址. 请使用 `process.env.VITE_DEV_SERVER_URL`
|
|
12
|
+
*/
|
|
13
|
+
serverUrl?: string;
|
|
14
|
+
/**
|
|
15
|
+
* `[vite build]` 插件的上下文 `ExtensionContext`.
|
|
16
|
+
*/
|
|
17
|
+
context: ExtensionContext;
|
|
18
|
+
/**
|
|
19
|
+
* `[vite build]` vite build.rollupOptions.input 设置的 index 名. 默认 `index`.
|
|
20
|
+
*/
|
|
21
|
+
inputName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* `[vite build]` 在 `<head>` 后面注入 `script` 或 `style` 代码
|
|
24
|
+
*/
|
|
25
|
+
injectCode?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get the html of the webview.
|
|
30
|
+
*
|
|
31
|
+
* @param options
|
|
32
|
+
*/
|
|
33
|
+
export const getWebviewHtml: (options?: WebviewHtmlOptions) => string;
|
|
34
|
+
|
|
35
|
+
export default getWebviewHtml;
|
|
36
|
+
}
|
package/env.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference types="./env-hbuilderx.d.ts" />
|
|
2
|
+
|
|
3
|
+
export { };
|
|
4
|
+
declare global {
|
|
5
|
+
|
|
6
|
+
type UnionType<T> = T | (string & {});
|
|
7
|
+
|
|
8
|
+
namespace NodeJS {
|
|
9
|
+
interface ProcessEnv {
|
|
10
|
+
/**
|
|
11
|
+
* Node.js 环境变量
|
|
12
|
+
*/
|
|
13
|
+
NODE_ENV: UnionType<'development' | 'production'>;
|
|
14
|
+
/**
|
|
15
|
+
* `[vite serve]` vite dev 服务地址
|
|
16
|
+
*/
|
|
17
|
+
VITE_DEV_SERVER_URL?: string;
|
|
18
|
+
/**
|
|
19
|
+
* `[vite build]` web端静态资源输出目录
|
|
20
|
+
*/
|
|
21
|
+
VITE_WEBVIEW_DIST?: string;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tomjs/vite-plugin-hbuilderx",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "为 HBuilderX 开发插件提供 vite 插件,可以使用 vue/react 开发 webview 的视图等",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Tom Gao",
|
|
8
|
+
"email": "tom@tomgao.cc"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/tomjs/hbuilderx.git",
|
|
14
|
+
"directory": "packages/vite"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"vite",
|
|
18
|
+
"plugin",
|
|
19
|
+
"hbuilderx",
|
|
20
|
+
"html",
|
|
21
|
+
"hmr",
|
|
22
|
+
"extension",
|
|
23
|
+
"webview"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": "./dist/index.js",
|
|
27
|
+
"./webview": "./dist/webview.js",
|
|
28
|
+
"./client": "./dist/client.iife.js",
|
|
29
|
+
"./env": "./env.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"module": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public",
|
|
35
|
+
"registry": "https://registry.npmjs.org"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"vite": ">=5"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@tomjs/logger": "^1.4.0",
|
|
45
|
+
"@tomjs/node": "^2.2.3",
|
|
46
|
+
"execa": "^9.6.1",
|
|
47
|
+
"lodash.merge": "^4.6.2",
|
|
48
|
+
"node-html-parser": "^7.0.1",
|
|
49
|
+
"picocolors": "^1.1.1",
|
|
50
|
+
"tsdown": "~0.18.4"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/jsdom": "^27.0.0",
|
|
54
|
+
"@types/lodash.merge": "^4.6.9",
|
|
55
|
+
"@tomjs/hbuilderx": "1.0.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"dev": "tsdown --watch",
|
|
59
|
+
"build": "tsdown",
|
|
60
|
+
"lint": "run-s lint:stylelint lint:eslint",
|
|
61
|
+
"lint:stylelint": "stylelint \"examples/**/*.{css,scss,vue}\" --fix",
|
|
62
|
+
"lint:eslint": "eslint --fix"
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/constants.ts
ADDED