@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 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 autoImport({
71
- imports: [
72
- "vue",
73
- "vue-router",
74
- "pinia",
75
- { pubinfo: ["useAuth"] }
76
- ],
77
- ignore: ["h"],
78
- dts: "./.pubinfo/auto-imports.d.ts",
79
- resolvers: [AntDesignVueResolver(), IconsResolver({ prefix: "i" })]
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 dts({
141
- clearPureImport: false,
142
- exclude: ["tests/**/*"]
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
- const enableCache = options.cache ?? true;
230
- const maxCacheSize = options.maxCacheSize ?? 50;
231
- const cache = /* @__PURE__ */ new Map();
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
- if (!enableCache) cache.clear();
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
- entries: {
324
- icons: "src/assets/icons/**/*",
325
- layouts: "src/layouts/*.vue",
326
- pages: "src/views/**/*.vue"
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
- type === "module" ? [createDTS()] : null,
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.1",
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.8.4",
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
  },