@pubinfo/vite 2.0.0-rc.1 → 2.0.0-rc.3
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.d.ts +14 -2
- package/dist/index.js +162 -80
- package/dist/load.js +267 -0
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -7,13 +7,25 @@ export * from "vite-plugin-fake-server/client";
|
|
|
7
7
|
//#region src/plugins/lib-resolver.d.ts
|
|
8
8
|
type GlobInput = string;
|
|
9
9
|
interface ModuleEntries {
|
|
10
|
+
/**
|
|
11
|
+
* 图标文件
|
|
12
|
+
* @default "src/assets/icons/**\/*"
|
|
13
|
+
*/
|
|
14
|
+
icons?: GlobInput;
|
|
15
|
+
/**
|
|
16
|
+
* 布局文件
|
|
17
|
+
* @default "src/layouts/**\/*"
|
|
18
|
+
*/
|
|
10
19
|
layouts?: GlobInput;
|
|
20
|
+
/**
|
|
21
|
+
* 页面文件
|
|
22
|
+
* @default "src/pages/**\/*"
|
|
23
|
+
*/
|
|
11
24
|
pages?: GlobInput;
|
|
12
25
|
}
|
|
13
26
|
interface ResolverPluginOptions {
|
|
27
|
+
/** 入口配置 */
|
|
14
28
|
entries: ModuleEntries;
|
|
15
|
-
cache?: boolean;
|
|
16
|
-
maxCacheSize?: number;
|
|
17
29
|
}
|
|
18
30
|
//#endregion
|
|
19
31
|
//#region src/interface.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { defineConfig, loadEnv, mergeConfig } from "rolldown-vite";
|
|
2
|
+
import { defineConfig, loadEnv, mergeConfig, normalizePath } from "rolldown-vite";
|
|
3
3
|
import { cwd } from "node:process";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import consola from "consola";
|
|
6
|
-
import { join, posix, relative, resolve } from "node:path";
|
|
6
|
+
import { dirname, join, posix, relative, resolve } from "node:path";
|
|
7
7
|
import vue from "@vitejs/plugin-vue";
|
|
8
8
|
import vueJsx from "@vitejs/plugin-vue-jsx";
|
|
9
9
|
import autoImport from "unplugin-auto-import/vite";
|
|
@@ -14,15 +14,18 @@ import compression from "vite-plugin-compression";
|
|
|
14
14
|
import dts from "vite-plugin-dts";
|
|
15
15
|
import Icons from "unplugin-icons/vite";
|
|
16
16
|
import boxen from "boxen";
|
|
17
|
+
import { libInjectCss } from "vite-plugin-lib-inject-css";
|
|
17
18
|
import VueDevTools from "vite-plugin-vue-devtools";
|
|
18
19
|
import vueLegacy from "@vitejs/plugin-legacy";
|
|
19
|
-
import { createHash } from "node:crypto";
|
|
20
|
-
import { existsSync, statSync } from "node:fs";
|
|
21
20
|
import fg from "fast-glob";
|
|
22
21
|
import { merge } from "lodash-es";
|
|
22
|
+
import picomatch from "picomatch";
|
|
23
|
+
import { existsSync } from "node:fs";
|
|
23
24
|
import { vitePluginFakeServer } from "vite-plugin-fake-server";
|
|
24
25
|
import OpenAPI from "@pubinfo/unplugin-openapi/vite";
|
|
25
26
|
import Unocss from "unocss/vite";
|
|
27
|
+
import { readFile } from "node:fs/promises";
|
|
28
|
+
import { fileURLToPath } from "node:url";
|
|
26
29
|
|
|
27
30
|
export * from "rolldown-vite"
|
|
28
31
|
|
|
@@ -67,17 +70,20 @@ function getServerProxy(env, isProxy) {
|
|
|
67
70
|
//#endregion
|
|
68
71
|
//#region src/plugins/auto-import.ts
|
|
69
72
|
function createAutoImport() {
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
return {
|
|
74
|
+
...autoImport({
|
|
75
|
+
imports: [
|
|
76
|
+
"vue",
|
|
77
|
+
"vue-router",
|
|
78
|
+
"pinia",
|
|
79
|
+
{ pubinfo: ["useAuth"] }
|
|
80
|
+
],
|
|
81
|
+
ignore: ["h"],
|
|
82
|
+
dts: "./.pubinfo/auto-imports.d.ts",
|
|
83
|
+
resolvers: [AntDesignVueResolver(), IconsResolver({ prefix: "i" })]
|
|
84
|
+
}),
|
|
85
|
+
enforce: "pre"
|
|
86
|
+
};
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
//#endregion
|
|
@@ -137,10 +143,13 @@ function createCompression(env) {
|
|
|
137
143
|
//#endregion
|
|
138
144
|
//#region src/plugins/dts.ts
|
|
139
145
|
function createDTS() {
|
|
140
|
-
return
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
return {
|
|
147
|
+
...dts({
|
|
148
|
+
clearPureImport: false,
|
|
149
|
+
exclude: ["tests/**/*"]
|
|
150
|
+
}),
|
|
151
|
+
enforce: "post"
|
|
152
|
+
};
|
|
144
153
|
}
|
|
145
154
|
|
|
146
155
|
//#endregion
|
|
@@ -191,6 +200,12 @@ function appInfo() {
|
|
|
191
200
|
};
|
|
192
201
|
}
|
|
193
202
|
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/plugins/inject-css.ts
|
|
205
|
+
function createInjectCSS() {
|
|
206
|
+
return libInjectCss();
|
|
207
|
+
}
|
|
208
|
+
|
|
194
209
|
//#endregion
|
|
195
210
|
//#region src/plugins/inspector.ts
|
|
196
211
|
function createInspector(env) {
|
|
@@ -220,32 +235,70 @@ function getPatternBase(pattern) {
|
|
|
220
235
|
}
|
|
221
236
|
return baseParts.join("/");
|
|
222
237
|
}
|
|
223
|
-
function normalizePath(path) {
|
|
238
|
+
function normalizePath$1(path) {
|
|
224
239
|
return posix.normalize(path.replace(/\\/g, "/"));
|
|
225
240
|
}
|
|
226
241
|
function libResolverPlugin(options) {
|
|
227
242
|
const virtualModuleId = "virtual:pubinfo-resolver";
|
|
228
243
|
const resolvedId = `\0${virtualModuleId}`;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
244
|
+
let serverRoot = "";
|
|
245
|
+
function sendUpdate(server, action, file) {
|
|
246
|
+
const payload = {
|
|
247
|
+
action,
|
|
248
|
+
file,
|
|
249
|
+
timestamp: Date.now()
|
|
250
|
+
};
|
|
251
|
+
server.ws.send({
|
|
252
|
+
type: "custom",
|
|
253
|
+
event: "pubinfo-resolver:update",
|
|
254
|
+
data: payload
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function isMatchingFile(file) {
|
|
258
|
+
const normalizedFile = normalizePath$1(file);
|
|
259
|
+
const isVueOrTsFile = /\.(vue|tsx?|jsx?)$/.test(normalizedFile);
|
|
260
|
+
const relativePath = serverRoot ? normalizePath$1(relative(serverRoot, normalizedFile)) : normalizedFile;
|
|
261
|
+
const patterns = Object.values(options.entries);
|
|
262
|
+
const matchesPattern = patterns.some((pattern, index) => {
|
|
263
|
+
const matcher = picomatch(pattern);
|
|
264
|
+
const matches = matcher(relativePath);
|
|
265
|
+
return matches;
|
|
266
|
+
});
|
|
267
|
+
const result = matchesPattern && isVueOrTsFile;
|
|
268
|
+
return result;
|
|
269
|
+
}
|
|
232
270
|
return {
|
|
233
271
|
name: "vite-plugin-lib-resolver",
|
|
234
272
|
enforce: "pre",
|
|
235
|
-
buildStart() {
|
|
236
|
-
|
|
273
|
+
buildStart() {},
|
|
274
|
+
configureServer(server) {
|
|
275
|
+
serverRoot = server.config.root;
|
|
276
|
+
const encodedPath = "/@id/__x00__virtual:pubinfo-resolver";
|
|
277
|
+
server.middlewares.use((req, _res, next) => {
|
|
278
|
+
if (req.url && req.url.startsWith(encodedPath)) {
|
|
279
|
+
const mod = server.moduleGraph.getModuleById(resolvedId);
|
|
280
|
+
if (mod) server.moduleGraph.invalidateModule(mod);
|
|
281
|
+
}
|
|
282
|
+
next();
|
|
283
|
+
});
|
|
284
|
+
server.watcher.on("add", (file) => {
|
|
285
|
+
if (isMatchingFile(file)) sendUpdate(server, "add", file);
|
|
286
|
+
});
|
|
287
|
+
server.watcher.on("unlink", (file) => {
|
|
288
|
+
if (isMatchingFile(file)) sendUpdate(server, "unlink", file);
|
|
289
|
+
});
|
|
290
|
+
const patterns = Object.values(options.entries);
|
|
291
|
+
const bases = patterns.map((pattern) => {
|
|
292
|
+
const base = getPatternBase(pattern);
|
|
293
|
+
return resolve(server.config.root, base);
|
|
294
|
+
});
|
|
295
|
+
server.watcher.add([...patterns.map((p) => resolve(server.config.root, p)), ...bases]);
|
|
237
296
|
},
|
|
238
297
|
async resolveId(id) {
|
|
239
298
|
return id === virtualModuleId ? resolvedId : null;
|
|
240
299
|
},
|
|
241
300
|
async load(id) {
|
|
242
301
|
if (id !== resolvedId) return null;
|
|
243
|
-
const configHash = createHash("md5").update(JSON.stringify(options.entries)).digest("hex");
|
|
244
|
-
if (enableCache && cache.has(configHash)) {
|
|
245
|
-
const cached = cache.get(configHash);
|
|
246
|
-
const hasChanges = await checkForFileChanges(options.entries, cached.fileHashes);
|
|
247
|
-
if (!hasChanges) return cached.content;
|
|
248
|
-
}
|
|
249
302
|
const moduleResults = await Promise.all(Object.entries(options.entries).map(async ([key, pattern]) => {
|
|
250
303
|
try {
|
|
251
304
|
const files = await fg(pattern, { absolute: true });
|
|
@@ -256,8 +309,8 @@ function libResolverPlugin(options) {
|
|
|
256
309
|
};
|
|
257
310
|
const base = getPatternBase(pattern);
|
|
258
311
|
const imports = files.map((file) => {
|
|
259
|
-
const absPath = normalizePath(file);
|
|
260
|
-
const relToBase = normalizePath(relative(resolve(base), file));
|
|
312
|
+
const absPath = normalizePath$1(file);
|
|
313
|
+
const relToBase = normalizePath$1(relative(resolve(base), file));
|
|
261
314
|
const relPath = posix.join(base, relToBase);
|
|
262
315
|
return `"${relPath}": () => import("${absPath}")`;
|
|
263
316
|
}).join(",\n");
|
|
@@ -277,57 +330,16 @@ function libResolverPlugin(options) {
|
|
|
277
330
|
}));
|
|
278
331
|
const moduleDefs = moduleResults.map((result) => result.content);
|
|
279
332
|
const content = `export default {\n ${moduleDefs.join(",\n ")}\n}`;
|
|
280
|
-
const fileHashes = /* @__PURE__ */ new Map();
|
|
281
|
-
const allFiles = moduleResults.flatMap((result) => result.files);
|
|
282
|
-
for (const file of allFiles) if (existsSync(file)) {
|
|
283
|
-
const stats = statSync(file);
|
|
284
|
-
const fileHash = createHash("md5").update(`${file}-${stats.mtimeMs}-${stats.size}`).digest("hex");
|
|
285
|
-
fileHashes.set(file, fileHash);
|
|
286
|
-
}
|
|
287
|
-
if (enableCache) {
|
|
288
|
-
if (cache.size >= maxCacheSize) {
|
|
289
|
-
const oldestKey = cache.keys().next().value;
|
|
290
|
-
if (oldestKey) cache.delete(oldestKey);
|
|
291
|
-
}
|
|
292
|
-
cache.set(configHash, {
|
|
293
|
-
content,
|
|
294
|
-
fileHashes,
|
|
295
|
-
timestamp: Date.now()
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
333
|
return content;
|
|
299
334
|
}
|
|
300
335
|
};
|
|
301
|
-
async function checkForFileChanges(entries, cachedFileHashes) {
|
|
302
|
-
try {
|
|
303
|
-
for (const pattern of Object.values(entries)) {
|
|
304
|
-
const files = await fg(pattern, { absolute: true });
|
|
305
|
-
for (const file of files) {
|
|
306
|
-
if (!existsSync(file)) return true;
|
|
307
|
-
const stats = statSync(file);
|
|
308
|
-
const currentFileHash = createHash("md5").update(`${file}-${stats.mtimeMs}-${stats.size}`).digest("hex");
|
|
309
|
-
const cachedHash = cachedFileHashes.get(file);
|
|
310
|
-
if (!cachedHash || cachedHash !== currentFileHash) return true;
|
|
311
|
-
}
|
|
312
|
-
for (const cachedFile of cachedFileHashes.keys()) if (!files.includes(cachedFile) && existsSync(cachedFile)) return true;
|
|
313
|
-
}
|
|
314
|
-
return false;
|
|
315
|
-
} catch (error) {
|
|
316
|
-
console.warn("[lib-resolver] Error checking file changes:", error);
|
|
317
|
-
return true;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
336
|
}
|
|
321
337
|
function createLibResolver(options) {
|
|
322
|
-
return libResolverPlugin(merge({
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
},
|
|
328
|
-
cache: true,
|
|
329
|
-
maxCacheSize: 50
|
|
330
|
-
}, options));
|
|
338
|
+
return libResolverPlugin(merge({ entries: {
|
|
339
|
+
icons: "src/assets/icons/**/*",
|
|
340
|
+
layouts: "src/layouts/*.vue",
|
|
341
|
+
pages: "src/views/**/*.vue"
|
|
342
|
+
} }, options));
|
|
331
343
|
}
|
|
332
344
|
|
|
333
345
|
//#endregion
|
|
@@ -355,6 +367,75 @@ function createUnocss() {
|
|
|
355
367
|
return Unocss();
|
|
356
368
|
}
|
|
357
369
|
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/plugins/virtual-inspector.ts
|
|
372
|
+
function getInspectorPath() {
|
|
373
|
+
const pluginPath = normalizePath(dirname(fileURLToPath(import.meta.url)));
|
|
374
|
+
return pluginPath;
|
|
375
|
+
}
|
|
376
|
+
function createVirtualInspectorPlugin(options = {}) {
|
|
377
|
+
const { enabled = true } = options;
|
|
378
|
+
const inspectorPath = getInspectorPath();
|
|
379
|
+
const virtualModuleId = "virtual:vite-pubinfo-inspector:load.js";
|
|
380
|
+
let config;
|
|
381
|
+
return {
|
|
382
|
+
name: "vite-plugin-virtual-inspector",
|
|
383
|
+
enforce: "pre",
|
|
384
|
+
configureServer(server) {
|
|
385
|
+
if (!enabled) return;
|
|
386
|
+
server.middlewares.use("/__pubinfo_inspector__", (req, res, next) => {
|
|
387
|
+
if (req.url === "/info") {
|
|
388
|
+
res.setHeader("Content-Type", "application/json");
|
|
389
|
+
res.end(JSON.stringify({
|
|
390
|
+
virtualModule: virtualModuleId,
|
|
391
|
+
enabled: true,
|
|
392
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
393
|
+
}));
|
|
394
|
+
} else next();
|
|
395
|
+
});
|
|
396
|
+
},
|
|
397
|
+
async resolveId(importee) {
|
|
398
|
+
if (importee === virtualModuleId) {
|
|
399
|
+
const resolved = resolve(inspectorPath, "load.js");
|
|
400
|
+
return resolved;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
},
|
|
404
|
+
async load(id) {
|
|
405
|
+
if (id.includes("load.js") && id.includes(inspectorPath)) {
|
|
406
|
+
if (!enabled) return "export default {};";
|
|
407
|
+
const filePath = resolve(inspectorPath, "load.js");
|
|
408
|
+
if (existsSync(filePath)) return await readFile(filePath, "utf-8");
|
|
409
|
+
else {
|
|
410
|
+
console.error(`Failed to find file for pubinfo-inspector: ${filePath}`);
|
|
411
|
+
return "export default { error: \"Failed to load inspector content\" };";
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return null;
|
|
415
|
+
},
|
|
416
|
+
transformIndexHtml(html) {
|
|
417
|
+
if (!enabled) return;
|
|
418
|
+
return {
|
|
419
|
+
html,
|
|
420
|
+
tags: [{
|
|
421
|
+
tag: "script",
|
|
422
|
+
injectTo: "head",
|
|
423
|
+
attrs: {
|
|
424
|
+
type: "module",
|
|
425
|
+
src: `${config?.base || "/"}@id/${virtualModuleId}`
|
|
426
|
+
}
|
|
427
|
+
}]
|
|
428
|
+
};
|
|
429
|
+
},
|
|
430
|
+
configResolved(resolvedConfig) {
|
|
431
|
+
config = resolvedConfig;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function createVirtualInspector(options) {
|
|
436
|
+
return createVirtualInspectorPlugin(options);
|
|
437
|
+
}
|
|
438
|
+
|
|
358
439
|
//#endregion
|
|
359
440
|
//#region src/plugins/index.ts
|
|
360
441
|
function createVitePlugins(viteEnv, isBuild = false, config, type) {
|
|
@@ -371,7 +452,8 @@ function createVitePlugins(viteEnv, isBuild = false, config, type) {
|
|
|
371
452
|
createOpenAPI(config.openapi),
|
|
372
453
|
createLibResolver(config.resolver),
|
|
373
454
|
appInfo(),
|
|
374
|
-
|
|
455
|
+
createVirtualInspector({ enabled: true }),
|
|
456
|
+
type === "module" ? [createDTS(), createInjectCSS()] : null,
|
|
375
457
|
isBuild ? createCompression(viteEnv) : null
|
|
376
458
|
];
|
|
377
459
|
return vitePlugins.filter(Boolean);
|
package/dist/load.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// Vite Pubinfo Inspector Virtual Module
|
|
2
|
+
|
|
3
|
+
// 检查器工具函数
|
|
4
|
+
export const inspectorUtils = {
|
|
5
|
+
// 获取当前环境信息
|
|
6
|
+
getEnvInfo() {
|
|
7
|
+
return {
|
|
8
|
+
nodeEnv: 'development', // 简化处理,直接设置为开发模式
|
|
9
|
+
mode: import.meta.env.MODE,
|
|
10
|
+
dev: import.meta.env.DEV,
|
|
11
|
+
prod: import.meta.env.PROD,
|
|
12
|
+
ssr: import.meta.env.SSR,
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
// 获取Vite信息
|
|
17
|
+
getViteInfo() {
|
|
18
|
+
return {
|
|
19
|
+
hmr: import.meta.hot ? 'enabled' : 'disabled',
|
|
20
|
+
base: import.meta.env.BASE_URL,
|
|
21
|
+
url: import.meta.url,
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// WebSocket 连接工具
|
|
26
|
+
websocket: {
|
|
27
|
+
// 获取 HMR WebSocket 连接信息
|
|
28
|
+
getHMRConnection() {
|
|
29
|
+
if (!import.meta.hot) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 通过 import.meta.hot 获取内部的 transport 和连接信息
|
|
34
|
+
// 注意:这些是内部 API,可能会在 Vite 版本更新时发生变化
|
|
35
|
+
const hotContext = import.meta.hot;
|
|
36
|
+
|
|
37
|
+
// 尝试访问内部的 HMR 客户端
|
|
38
|
+
const hmrClient = hotContext?.__viteHmrClient || hotContext?._hmrClient;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
isAvailable: !!hotContext,
|
|
42
|
+
client: hmrClient,
|
|
43
|
+
// 提供一些基本的连接信息
|
|
44
|
+
connectionState: hmrClient?.transport ? 'connected' : 'disconnected',
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// 发送自定义 WebSocket 消息
|
|
49
|
+
send(event, data) {
|
|
50
|
+
if (!import.meta.hot) {
|
|
51
|
+
console.warn('[Pubinfo Inspector] HMR not available');
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
import.meta.hot.send(event, data);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error('[Pubinfo Inspector] Failed to send WebSocket message:', error);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// 监听自定义 WebSocket 事件
|
|
66
|
+
on(event, callback) {
|
|
67
|
+
if (!import.meta.hot) {
|
|
68
|
+
console.warn('[Pubinfo Inspector] HMR not available');
|
|
69
|
+
return () => {};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
import.meta.hot.on(event, callback);
|
|
74
|
+
|
|
75
|
+
// 返回取消监听的函数
|
|
76
|
+
return () => {
|
|
77
|
+
try {
|
|
78
|
+
import.meta.hot.off(event, callback);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error('[Pubinfo Inspector] Failed to remove WebSocket listener:', error);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error('[Pubinfo Inspector] Failed to add WebSocket listener:', error);
|
|
87
|
+
return () => {};
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
// 监听 WebSocket 连接状态变化
|
|
92
|
+
onConnectionChange(callback) {
|
|
93
|
+
if (!import.meta.hot) {
|
|
94
|
+
console.warn('[Pubinfo Inspector] HMR not available');
|
|
95
|
+
return () => {};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const listeners = [];
|
|
99
|
+
|
|
100
|
+
// 监听连接建立
|
|
101
|
+
const offConnect = this.on('vite:ws:connect', () => {
|
|
102
|
+
callback('connected');
|
|
103
|
+
});
|
|
104
|
+
listeners.push(offConnect);
|
|
105
|
+
|
|
106
|
+
// 监听连接断开
|
|
107
|
+
const offDisconnect = this.on('vite:ws:disconnect', () => {
|
|
108
|
+
callback('disconnected');
|
|
109
|
+
});
|
|
110
|
+
listeners.push(offDisconnect);
|
|
111
|
+
|
|
112
|
+
// 返回取消所有监听的函数
|
|
113
|
+
return () => {
|
|
114
|
+
listeners.forEach(off => off());
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// 获取 WebSocket 连接的详细信息
|
|
119
|
+
getConnectionDetails() {
|
|
120
|
+
const connection = this.getHMRConnection();
|
|
121
|
+
|
|
122
|
+
if (!connection || !connection.isAvailable) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 尝试获取更多连接详细信息
|
|
127
|
+
const details = {
|
|
128
|
+
state: connection.connectionState,
|
|
129
|
+
url: null,
|
|
130
|
+
protocol: null,
|
|
131
|
+
readyState: null,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
// 尝试从内部访问 WebSocket 实例
|
|
136
|
+
const transport = connection.client?.transport;
|
|
137
|
+
if (transport?.socket) {
|
|
138
|
+
details.url = transport.socket.url;
|
|
139
|
+
details.protocol = transport.socket.protocol;
|
|
140
|
+
details.readyState = transport.socket.readyState;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
// 静默处理错误,因为这些是内部 API
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return details;
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// 测试 WebSocket 连接
|
|
151
|
+
async testConnection() {
|
|
152
|
+
if (!import.meta.hot) {
|
|
153
|
+
return { success: false, error: 'HMR not available' };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
// 发送一个测试事件
|
|
158
|
+
const testEventName = `pubinfo:test:${Date.now()}`;
|
|
159
|
+
let received = false;
|
|
160
|
+
|
|
161
|
+
// 监听响应
|
|
162
|
+
const off = this.on(`${testEventName}:response`, () => {
|
|
163
|
+
received = true;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// 发送测试消息
|
|
167
|
+
this.send(testEventName, { timestamp: Date.now() });
|
|
168
|
+
|
|
169
|
+
// 等待响应(超时 5 秒)
|
|
170
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
171
|
+
|
|
172
|
+
off();
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
success: true,
|
|
176
|
+
connectionWorking: received,
|
|
177
|
+
details: this.getConnectionDetails(),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
return {
|
|
182
|
+
success: false,
|
|
183
|
+
error: error.message,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
// 性能监控
|
|
190
|
+
performance: {
|
|
191
|
+
mark: (name) => {
|
|
192
|
+
if (typeof performance !== 'undefined' && performance.mark) {
|
|
193
|
+
performance.mark(name);
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
measure: (name, startMark, endMark) => {
|
|
197
|
+
if (typeof performance !== 'undefined' && performance.measure) {
|
|
198
|
+
try {
|
|
199
|
+
performance.measure(name, startMark, endMark);
|
|
200
|
+
const entries = performance.getEntriesByName(name);
|
|
201
|
+
return entries[entries.length - 1];
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
console.warn('Performance measurement failed:', e);
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// 导出默认对象
|
|
214
|
+
export default inspectorUtils;
|
|
215
|
+
|
|
216
|
+
// 全局访问接口 - 让其他模块可以访问 WebSocket 功能
|
|
217
|
+
if (typeof globalThis !== 'undefined') {
|
|
218
|
+
// 在全局对象上暴露 WebSocket 工具
|
|
219
|
+
globalThis.__PUBINFO_WEBSOCKET__ = {
|
|
220
|
+
// 发送消息
|
|
221
|
+
send: (event, data) => inspectorUtils.websocket.send(event, data),
|
|
222
|
+
|
|
223
|
+
// 监听事件
|
|
224
|
+
on: (event, callback) => inspectorUtils.websocket.on(event, callback),
|
|
225
|
+
|
|
226
|
+
// 获取连接信息
|
|
227
|
+
getConnection: () => inspectorUtils.websocket.getHMRConnection(),
|
|
228
|
+
|
|
229
|
+
// 获取连接详情
|
|
230
|
+
getDetails: () => inspectorUtils.websocket.getConnectionDetails(),
|
|
231
|
+
|
|
232
|
+
// 测试连接
|
|
233
|
+
test: () => inspectorUtils.websocket.testConnection(),
|
|
234
|
+
|
|
235
|
+
// 监听连接状态
|
|
236
|
+
onStateChange: callback => inspectorUtils.websocket.onConnectionChange(callback),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// HMR 支持 - 静默接受热更新,避免页面重新加载
|
|
241
|
+
if (import.meta.hot) {
|
|
242
|
+
// 静默接受热更新,不输出日志,避免噪音
|
|
243
|
+
import.meta.hot.accept(() => {
|
|
244
|
+
// 静默重新初始化全局接口,不输出任何日志
|
|
245
|
+
if (typeof globalThis !== 'undefined') {
|
|
246
|
+
globalThis.__PUBINFO_WEBSOCKET__ = {
|
|
247
|
+
send: (event, data) => inspectorUtils.websocket.send(event, data),
|
|
248
|
+
on: (event, callback) => inspectorUtils.websocket.on(event, callback),
|
|
249
|
+
getConnection: () => inspectorUtils.websocket.getHMRConnection(),
|
|
250
|
+
getDetails: () => inspectorUtils.websocket.getConnectionDetails(),
|
|
251
|
+
test: () => inspectorUtils.websocket.testConnection(),
|
|
252
|
+
onStateChange: callback => inspectorUtils.websocket.onConnectionChange(callback),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// HMR 数据持久化
|
|
258
|
+
import.meta.hot.dispose((data) => {
|
|
259
|
+
// 静默保存当前状态
|
|
260
|
+
data.connectionInfo = inspectorUtils.websocket.getConnectionDetails();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// 静默从之前的状态恢复
|
|
264
|
+
if (import.meta.hot.data?.connectionInfo) {
|
|
265
|
+
// 静默恢复,不输出日志
|
|
266
|
+
}
|
|
267
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubinfo/vite",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-rc.
|
|
4
|
+
"version": "2.0.0-rc.3",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -19,18 +19,20 @@
|
|
|
19
19
|
"vue-i18n": "^10.0.7"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@pubinfo/unplugin-openapi": "^0.
|
|
22
|
+
"@pubinfo/unplugin-openapi": "^0.9.0",
|
|
23
23
|
"@vitejs/plugin-legacy": "^7.2.1",
|
|
24
24
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
25
25
|
"@vitejs/plugin-vue-jsx": "^5.0.1",
|
|
26
26
|
"abort-controller": "^3.0.0",
|
|
27
27
|
"boxen": "^8.0.1",
|
|
28
28
|
"chalk": "^5.4.1",
|
|
29
|
+
"chokidar": "^4.0.1",
|
|
29
30
|
"consola": "^3.4.2",
|
|
30
31
|
"fast-glob": "^3.3.3",
|
|
31
32
|
"fs-extra": "^11.3.0",
|
|
32
33
|
"jszip": "^3.10.1",
|
|
33
34
|
"lodash-es": "^4.17.21",
|
|
35
|
+
"picomatch": "^4.0.3",
|
|
34
36
|
"rolldown-vite": "^7.1.2",
|
|
35
37
|
"terser": "^5.43.1",
|
|
36
38
|
"unocss": "^66.4.2",
|
|
@@ -41,12 +43,14 @@
|
|
|
41
43
|
"vite-plugin-dts": "^4.5.4",
|
|
42
44
|
"vite-plugin-env-runtime": "^0.3.6",
|
|
43
45
|
"vite-plugin-fake-server": "^2.2.0",
|
|
46
|
+
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
44
47
|
"vite-plugin-vue-devtools": "^8.0.0"
|
|
45
48
|
},
|
|
46
49
|
"devDependencies": {
|
|
47
50
|
"@types/fs-extra": "^11.0.4",
|
|
48
51
|
"@types/lodash-es": "^4.17.12",
|
|
49
52
|
"@types/node": "^24.0.10",
|
|
53
|
+
"@types/picomatch": "^4.0.2",
|
|
50
54
|
"vue": "^3.5.17",
|
|
51
55
|
"vue-i18n": "^10.0.7"
|
|
52
56
|
},
|