@pubinfo-pr/vite 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 PUBINFO 腾龙框架
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,100 @@
1
+ import { UserConfig, UserConfigFnObject } from "rolldown-vite";
2
+ import * as vite_plugin_vue_devtools0 from "vite-plugin-vue-devtools";
3
+ import { VitePluginVueDevToolsOptions } from "vite-plugin-vue-devtools";
4
+ import * as _pubinfo_unplugin_openapi0 from "@pubinfo/unplugin-openapi";
5
+ import { Options } from "@pubinfo/unplugin-openapi";
6
+ export * from "rolldown-vite";
7
+ export * from "vite-plugin-fake-server/client";
8
+
9
+ //#region src/plugins/built-in/inject-auto.d.ts
10
+ interface InjectAutoOptions {
11
+ id: string;
12
+ }
13
+ /**
14
+ * 自动注入代码
15
+ */
16
+ //#endregion
17
+ //#region src/plugins/built-in/lib-resolver.d.ts
18
+ type GlobInput = string;
19
+ interface ModuleEntries {
20
+ /**
21
+ * 图标文件
22
+ * @default "src/assets/icons/**\/*"
23
+ */
24
+ icons?: GlobInput;
25
+ /**
26
+ * 布局文件
27
+ * @default "src/layouts/**\/*"
28
+ */
29
+ layouts?: GlobInput;
30
+ /**
31
+ * 页面文件
32
+ * @default "src/pages/**\/*"
33
+ */
34
+ pages?: GlobInput;
35
+ }
36
+ interface ResolverPluginOptions {
37
+ /** 入口配置 */
38
+ entries: ModuleEntries;
39
+ }
40
+ //#endregion
41
+ //#region src/interface.d.ts
42
+ interface CommitlintOptions {
43
+ /**
44
+ * Enable or disable commitlint for application repositories. Defaults to enabled.
45
+ */
46
+ enabled?: boolean;
47
+ /**
48
+ * Convenience flag mirroring `enabled: false`.
49
+ */
50
+ disable?: boolean;
51
+ }
52
+ interface PubinfoConfig {
53
+ /** `vite` */
54
+ vite?: UserConfig | UserConfigFnObject;
55
+ /** `@pubinfo/unplugin-openapi` */
56
+ openapi?: Options;
57
+ /** `resolver` */
58
+ resolver?: ResolverPluginOptions;
59
+ /** devtools */
60
+ devtools?: Omit<VitePluginVueDevToolsOptions, 'enabled'> & {
61
+ enabled?: boolean;
62
+ };
63
+ /** `commitlint` */
64
+ commitlint?: boolean | CommitlintOptions;
65
+ }
66
+ interface ModuleConfig extends PubinfoConfig {
67
+ /**
68
+ * `moduleId`
69
+ */
70
+ moduleId: InjectAutoOptions['id'];
71
+ }
72
+ //#endregion
73
+ //#region src/config/index.d.ts
74
+ /**
75
+ * 构建应用配置
76
+ */
77
+ declare function definePubinfoConfig(config: PubinfoConfig): {
78
+ vite: UserConfigFnObject;
79
+ openapi?: _pubinfo_unplugin_openapi0.Options;
80
+ resolver?: ResolverPluginOptions;
81
+ devtools?: Omit<vite_plugin_vue_devtools0.VitePluginVueDevToolsOptions, "enabled"> & {
82
+ enabled?: boolean;
83
+ };
84
+ commitlint?: boolean | CommitlintOptions;
85
+ };
86
+ /**
87
+ * 构建模块配置
88
+ */
89
+ declare function defineModuleConfig(config: ModuleConfig): {
90
+ vite: UserConfigFnObject;
91
+ moduleId: InjectAutoOptions["id"];
92
+ openapi?: _pubinfo_unplugin_openapi0.Options;
93
+ resolver?: ResolverPluginOptions;
94
+ devtools?: Omit<vite_plugin_vue_devtools0.VitePluginVueDevToolsOptions, "enabled"> & {
95
+ enabled?: boolean;
96
+ };
97
+ commitlint?: boolean | CommitlintOptions;
98
+ };
99
+ //#endregion
100
+ export { CommitlintOptions, ModuleConfig, PubinfoConfig, ResolverPluginOptions, defineModuleConfig, definePubinfoConfig };
package/dist/index.js ADDED
@@ -0,0 +1,747 @@
1
+ import { createRequire } from "node:module";
2
+ import { defineConfig, loadEnv, mergeConfig, normalizePath } from "rolldown-vite";
3
+ import process, { cwd } from "node:process";
4
+ import { logger } from "@pubinfo-pr/shared";
5
+ import chalk from "chalk";
6
+ import path, { dirname, join, posix, relative, resolve } from "node:path";
7
+ import vue from "@vitejs/plugin-vue";
8
+ import vueJsx from "@vitejs/plugin-vue-jsx";
9
+ import fs from "fs-extra";
10
+ import boxen from "boxen";
11
+ import MagicString from "magic-string";
12
+ import fg from "fast-glob";
13
+ import { merge } from "lodash-es";
14
+ import picomatch from "picomatch";
15
+ import "micromatch";
16
+ import { execSync } from "node:child_process";
17
+ import dayjs from "dayjs";
18
+ import { readPackageJSON } from "pkg-types";
19
+ import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
20
+ import { readFile } from "node:fs/promises";
21
+ import { fileURLToPath } from "node:url";
22
+ import { Buffer } from "node:buffer";
23
+ import fse from "fs-extra/esm";
24
+ import JSZip from "jszip";
25
+ import autoImport from "unplugin-auto-import/vite";
26
+ import IconsResolver from "unplugin-icons/resolver";
27
+ import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
28
+ import components from "unplugin-vue-components/vite";
29
+ import compression from "vite-plugin-compression";
30
+ import { pubinfoDevtools } from "@pubinfo-pr/devtools";
31
+ import dts from "vite-plugin-dts";
32
+ import Icons from "unplugin-icons/vite";
33
+ import { libInjectCss } from "vite-plugin-lib-inject-css";
34
+ import VueDevTools from "vite-plugin-vue-devtools";
35
+ import vueLegacy from "@vitejs/plugin-legacy";
36
+ import { vitePluginFakeServer } from "vite-plugin-fake-server";
37
+ import OpenAPI from "@pubinfo/unplugin-openapi/vite";
38
+ import Unocss from "unocss/vite";
39
+
40
+ export * from "rolldown-vite"
41
+
42
+ export * from "vite-plugin-fake-server/client"
43
+
44
+ //#region src/helper/alias.ts
45
+ function alias(root) {
46
+ const resolvePath = (name) => join(root, name);
47
+ const resolveDeps = (name, path$1) => join(createRequire(import.meta.url).resolve(name), path$1);
48
+ return {
49
+ "@": resolvePath("src"),
50
+ "#": resolvePath("types"),
51
+ "vue": resolveDeps("vue", "../"),
52
+ "vue-router": resolveDeps("vue-router", "../"),
53
+ "pinia": resolveDeps("pinia", "../"),
54
+ "unocss": resolveDeps("unocss", "../")
55
+ };
56
+ }
57
+
58
+ //#endregion
59
+ //#region src/helper/index.ts
60
+ function getServerProxy(env, isProxy) {
61
+ if (!isProxy) return {};
62
+ const targetPrefix = "VITE_APP_API_";
63
+ const proxyKey = Object.keys(env).filter((key) => key.startsWith(targetPrefix));
64
+ const serverProxy = {};
65
+ for (const envKey of proxyKey) {
66
+ const url = env[envKey];
67
+ const { pathname } = new URL(url);
68
+ const pk = `${pathname}/proxy`;
69
+ if (pk in serverProxy) logger.warn(`The env key ${chalk.bold.yellowBright(envKey)} ➜ ${chalk.bold.green(url)} already exists`);
70
+ else serverProxy[pk] = {
71
+ target: url,
72
+ changeOrigin: true,
73
+ rewrite: (path$1) => path$1.replace(pk, ""),
74
+ secure: false
75
+ };
76
+ }
77
+ return serverProxy;
78
+ }
79
+
80
+ //#endregion
81
+ //#region src/plugins/built-in/clean-build.ts
82
+ function createCleanBuild() {
83
+ let config;
84
+ return {
85
+ name: "vite-plugin-clean-build",
86
+ apply: "build",
87
+ enforce: "post",
88
+ configResolved(resolvedConfig) {
89
+ config = resolvedConfig;
90
+ },
91
+ buildStart() {
92
+ const outDir = config.build.outDir;
93
+ const root = config.root;
94
+ const outputPath = path.resolve(root, outDir);
95
+ if (fs.existsSync(outputPath)) try {
96
+ fs.rmSync(outputPath, {
97
+ recursive: true,
98
+ force: true
99
+ });
100
+ } catch (error) {
101
+ logger.error(`[vite-plugin-clean-build] Failed to clean build directory: ${error}`);
102
+ }
103
+ }
104
+ };
105
+ }
106
+
107
+ //#endregion
108
+ //#region src/plugins/built-in/info.ts
109
+ var Ctx$1 = class {
110
+ options;
111
+ setOptions(options) {
112
+ this.options = options;
113
+ }
114
+ async createInfo() {
115
+ console.log(boxen(`\
116
+ 欢迎使用${chalk.bold.greenBright(" 产数研发底座系统 ")}\n
117
+ ${chalk.green("使用文档地址")} ${chalk.green("➜")} https://134.108.39.195:9090/docs`, {
118
+ padding: 1,
119
+ margin: 1,
120
+ align: "center",
121
+ borderColor: "yellowBright",
122
+ borderStyle: "round"
123
+ }));
124
+ }
125
+ };
126
+ const ctx$1 = new Ctx$1();
127
+ function createAppInfo() {
128
+ return {
129
+ name: "createAppInfo",
130
+ apply: "serve",
131
+ enforce: "pre",
132
+ configResolved(configuration) {
133
+ const root = configuration.root;
134
+ ctx$1.setOptions({ root });
135
+ },
136
+ async buildStart() {
137
+ ctx$1.createInfo();
138
+ },
139
+ configureServer(server) {
140
+ const _printUrls = server.printUrls;
141
+ server.printUrls = () => {
142
+ console.log(` ${chalk.green("➜")} ${chalk.bold.bgBlueBright(` PUBINFO `)}${chalk.bold.bgYellowBright(` 前端基础框架 `)}`);
143
+ _printUrls();
144
+ };
145
+ }
146
+ };
147
+ }
148
+
149
+ //#endregion
150
+ //#region src/plugins/built-in/inject-auto.ts
151
+ /**
152
+ * 自动注入代码
153
+ */
154
+ function createInjectAuto(options) {
155
+ const { id } = options;
156
+ let entryFiles = [];
157
+ return {
158
+ name: "vite-plugin-inject-auto",
159
+ enforce: "pre",
160
+ configResolved(config) {
161
+ const lib = config.build?.lib;
162
+ if (!lib || !lib.entry) return;
163
+ const toAbs = (p) => resolve(config.root, p);
164
+ if (typeof lib.entry === "string") entryFiles = [toAbs(lib.entry)];
165
+ else if (Array.isArray(lib.entry)) entryFiles = lib.entry.map(toAbs);
166
+ else if (typeof lib.entry === "object") entryFiles = Object.values(lib.entry).map(toAbs);
167
+ },
168
+ transform(code, _id) {
169
+ if (entryFiles.includes(_id)) {
170
+ const s = new MagicString(code);
171
+ const injectCode = `
172
+ import { defineRouteModule, defineIconModule } from 'pubinfo-pr';
173
+ import modules from 'virtual:pubinfo-resolver';
174
+
175
+ defineRouteModule('${id}', modules.pages);
176
+ defineIconModule('${id}', modules.icons);
177
+
178
+ `;
179
+ s.prepend(injectCode);
180
+ return {
181
+ code: s.toString(),
182
+ map: s.generateMap({ hires: true })
183
+ };
184
+ }
185
+ }
186
+ };
187
+ }
188
+
189
+ //#endregion
190
+ //#region src/plugins/built-in/lib-resolver.ts
191
+ function getPatternBase(pattern) {
192
+ const parts = pattern.split("/");
193
+ const baseParts = [];
194
+ for (const part of parts) {
195
+ if (part.includes("*")) break;
196
+ baseParts.push(part);
197
+ }
198
+ return baseParts.join("/");
199
+ }
200
+ function normalizePath$1(path$1) {
201
+ return posix.normalize(path$1.replace(/\\/g, "/"));
202
+ }
203
+ function libResolverPlugin(options) {
204
+ const virtualModuleId = "virtual:pubinfo-resolver";
205
+ const resolvedId = `\0${virtualModuleId}`;
206
+ let serverRoot = "";
207
+ function sendUpdate(server, action, file) {
208
+ const payload = {
209
+ action,
210
+ file,
211
+ timestamp: Date.now()
212
+ };
213
+ server.ws.send({
214
+ type: "custom",
215
+ event: "pubinfo-resolver:update",
216
+ data: payload
217
+ });
218
+ }
219
+ function isMatchingFile(file) {
220
+ const normalizedFile = normalizePath$1(file);
221
+ const isVueOrTsFile = /\.(vue|tsx?|jsx?)$/.test(normalizedFile);
222
+ const relativePath = serverRoot ? normalizePath$1(relative(serverRoot, normalizedFile)) : normalizedFile;
223
+ return Object.values(options.entries).some((pattern, index) => {
224
+ return picomatch(pattern)(relativePath);
225
+ }) && isVueOrTsFile;
226
+ }
227
+ return {
228
+ name: "vite-plugin-lib-resolver",
229
+ enforce: "pre",
230
+ buildStart() {},
231
+ configureServer(server) {
232
+ serverRoot = server.config.root;
233
+ const encodedPath = "/@id/__x00__virtual:pubinfo-resolver";
234
+ server.middlewares.use((req, _res, next) => {
235
+ if (req.url && req.url.startsWith(encodedPath)) {
236
+ const mod = server.moduleGraph.getModuleById(resolvedId);
237
+ if (mod) server.moduleGraph.invalidateModule(mod);
238
+ }
239
+ next();
240
+ });
241
+ server.watcher.on("add", (file) => {
242
+ if (isMatchingFile(file)) sendUpdate(server, "add", file);
243
+ });
244
+ server.watcher.on("unlink", (file) => {
245
+ if (isMatchingFile(file)) sendUpdate(server, "unlink", file);
246
+ });
247
+ const patterns = Object.values(options.entries);
248
+ const bases = patterns.map((pattern) => {
249
+ const base = getPatternBase(pattern);
250
+ return resolve(server.config.root, base);
251
+ });
252
+ server.watcher.add([...patterns.map((p) => resolve(server.config.root, p)), ...bases]);
253
+ },
254
+ async resolveId(id) {
255
+ return id === virtualModuleId ? resolvedId : null;
256
+ },
257
+ async load(id) {
258
+ if (id !== resolvedId) return null;
259
+ return `export default {\n ${(await Promise.all(Object.entries(options.entries).map(async ([key, pattern]) => {
260
+ try {
261
+ const files = await fg(pattern, { absolute: true });
262
+ if (files.length === 0) return {
263
+ key,
264
+ content: `"${key}": {}`,
265
+ files: []
266
+ };
267
+ const base = getPatternBase(pattern);
268
+ return {
269
+ key,
270
+ content: `"${key}": {\n${files.map((file) => {
271
+ const absPath = normalizePath$1(file);
272
+ const relToBase = normalizePath$1(relative(resolve(base), file));
273
+ return `"${posix.join(base, relToBase)}": () => import("${absPath}")`;
274
+ }).join(",\n")}\n }`,
275
+ files
276
+ };
277
+ } catch (error) {
278
+ console.error(`[lib-resolver] Error processing pattern "${pattern}":`, error);
279
+ return {
280
+ key,
281
+ content: `"${key}": {}`,
282
+ files: []
283
+ };
284
+ }
285
+ }))).map((result) => result.content).join(",\n ")}\n}`;
286
+ }
287
+ };
288
+ }
289
+ function createLibResolver(options) {
290
+ return libResolverPlugin(merge({ entries: {
291
+ icons: "src/assets/icons/**/*",
292
+ layouts: "src/layouts/*.vue",
293
+ pages: "src/views/**/*.vue"
294
+ } }, options));
295
+ }
296
+
297
+ //#endregion
298
+ //#region src/plugins/built-in/system-info.ts
299
+ function hasGitRepository() {
300
+ try {
301
+ execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
302
+ return true;
303
+ } catch {
304
+ return false;
305
+ }
306
+ }
307
+ function hasGitCommit() {
308
+ try {
309
+ execSync("git rev-parse --verify HEAD", { stdio: "ignore" });
310
+ return true;
311
+ } catch {
312
+ return false;
313
+ }
314
+ }
315
+ function getGitInfo() {
316
+ if (!hasGitRepository() || !hasGitCommit()) return {
317
+ commit: "",
318
+ commitShort: "",
319
+ branch: ""
320
+ };
321
+ try {
322
+ const commit = execSync("git rev-parse HEAD", { encoding: "utf-8" }).trim();
323
+ const commitShort = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
324
+ let branch = process.env.GITHUB_REF_NAME || process.env.CI_COMMIT_REF_NAME || process.env.GIT_BRANCH || process.env.BRANCH_NAME;
325
+ if (!branch) {
326
+ branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
327
+ if (branch === "HEAD") try {
328
+ const branches = execSync(`git show-ref --heads | grep ${commit}`, { encoding: "utf-8" }).trim();
329
+ if (branches) {
330
+ const match = branches.split("\n")[0].match(/refs\/heads\/(.+)$/);
331
+ if (match) branch = match[1];
332
+ }
333
+ } catch {}
334
+ }
335
+ return {
336
+ commit,
337
+ commitShort,
338
+ branch
339
+ };
340
+ } catch {
341
+ return {
342
+ commit: "",
343
+ commitShort: "",
344
+ branch: ""
345
+ };
346
+ }
347
+ }
348
+ function createSystemInfo(options = {}) {
349
+ const defineKey = options.defineKey || "__SYSTEM_INFO__";
350
+ return {
351
+ name: "vite-plugin-system-info",
352
+ async config() {
353
+ const pkg = await readPackageJSON();
354
+ const systemInfo = {
355
+ buildTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
356
+ pkg,
357
+ git: getGitInfo()
358
+ };
359
+ return { define: { [defineKey]: JSON.stringify(systemInfo) } };
360
+ }
361
+ };
362
+ }
363
+
364
+ //#endregion
365
+ //#region src/plugins/built-in/virtual-inspector.ts
366
+ function getInspectorPath() {
367
+ return normalizePath(dirname(fileURLToPath(import.meta.url)));
368
+ }
369
+ function createVirtualInspectorPlugin(options = {}) {
370
+ const { enabled = true } = options;
371
+ const inspectorPath = getInspectorPath();
372
+ const virtualModuleId = "virtual:vite-pubinfo-inspector:load.js";
373
+ let config;
374
+ return {
375
+ name: "vite-plugin-virtual-inspector",
376
+ enforce: "pre",
377
+ configureServer(server) {
378
+ if (!enabled) return;
379
+ server.middlewares.use("/__pubinfo_inspector__", (req, res, next) => {
380
+ if (req.url === "/info") {
381
+ res.setHeader("Content-Type", "application/json");
382
+ res.end(JSON.stringify({
383
+ virtualModule: virtualModuleId,
384
+ enabled: true,
385
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
386
+ }));
387
+ } else next();
388
+ });
389
+ },
390
+ async resolveId(importee) {
391
+ if (config?.command !== "serve") return null;
392
+ if (importee === virtualModuleId) return resolve(inspectorPath, "load.js");
393
+ return null;
394
+ },
395
+ async load(id) {
396
+ if (config?.command !== "serve") return null;
397
+ if (id.includes("load.js") && id.includes(inspectorPath)) {
398
+ if (!enabled) return "export default {};";
399
+ const filePath = resolve(inspectorPath, "load.js");
400
+ if (existsSync(filePath)) return await readFile(filePath, "utf-8");
401
+ else {
402
+ console.error(`Failed to find file for pubinfo-inspector: ${filePath}`);
403
+ return "export default { error: \"Failed to load inspector content\" };";
404
+ }
405
+ }
406
+ return null;
407
+ },
408
+ transformIndexHtml(html) {
409
+ if (!enabled || config?.command !== "serve") return;
410
+ return {
411
+ html,
412
+ tags: [{
413
+ tag: "script",
414
+ injectTo: "head",
415
+ attrs: {
416
+ type: "module",
417
+ src: `${config?.base || "/"}@id/${virtualModuleId}`
418
+ }
419
+ }]
420
+ };
421
+ },
422
+ configResolved(resolvedConfig) {
423
+ config = resolvedConfig;
424
+ }
425
+ };
426
+ }
427
+ function createVirtualInspector(options) {
428
+ return createVirtualInspectorPlugin(options);
429
+ }
430
+
431
+ //#endregion
432
+ //#region src/plugins/built-in/zip.ts
433
+ var Ctx = class {
434
+ root;
435
+ outDirName;
436
+ dir;
437
+ outDir;
438
+ setOptions(options) {
439
+ this.root = options.root;
440
+ this.outDirName = options.outDirName;
441
+ this.getDirPath();
442
+ }
443
+ getDirPath() {
444
+ const dir = resolve(this.root, this.outDirName);
445
+ const outDir = `${dir}.zip`;
446
+ this.dir = dir;
447
+ this.outDir = outDir;
448
+ }
449
+ async clean() {
450
+ if (await fse.pathExists(this.outDir)) fse.remove(this.outDir);
451
+ }
452
+ async compress() {
453
+ const zip = new JSZip();
454
+ const files = this.getAllFiles(this.dir);
455
+ if (files && Array.isArray(files) && files.length) files.forEach((file) => {
456
+ const fileData = readFileSync(file, { encoding: "binary" });
457
+ zip.file(relative(this.dir, file), fileData, { binary: true });
458
+ });
459
+ const content = await zip.generateAsync({ type: "arraybuffer" });
460
+ writeFileSync(this.outDir, Buffer.from(content));
461
+ }
462
+ getAllFiles(dirPath) {
463
+ const files = readdirSync(dirPath);
464
+ const result = [];
465
+ for (const file of files) {
466
+ const filePath = join(dirPath, file);
467
+ if (statSync(filePath).isDirectory()) result.push(...this.getAllFiles(filePath));
468
+ else result.push(filePath);
469
+ }
470
+ return result;
471
+ }
472
+ };
473
+ const ctx = new Ctx();
474
+
475
+ //#endregion
476
+ //#region src/plugins/intergrations/auto-import.ts
477
+ function createAutoImport() {
478
+ return autoImport({
479
+ imports: [
480
+ "vue",
481
+ "vue-router",
482
+ "pinia",
483
+ { pubinfo: ["useAuth"] }
484
+ ],
485
+ ignore: ["h"],
486
+ dts: "./.pubinfo/auto-imports.d.ts",
487
+ resolvers: [AntDesignVueResolver(), IconsResolver({ prefix: "i" })]
488
+ });
489
+ }
490
+
491
+ //#endregion
492
+ //#region src/plugins/intergrations/components.ts
493
+ function createComponents() {
494
+ return components({
495
+ dirs: ["src/components"],
496
+ directives: true,
497
+ include: [
498
+ /\.vue$/,
499
+ /\.vue\?vue/,
500
+ /\.tsx$/
501
+ ],
502
+ resolvers: [
503
+ IconsResolver(),
504
+ AntDesignVueResolver({
505
+ resolveIcons: true,
506
+ importStyle: false
507
+ }),
508
+ {
509
+ type: "component",
510
+ resolve(name) {
511
+ if ([
512
+ "PubinfoApp",
513
+ "PubinfoProvider",
514
+ "PubinfoIcon"
515
+ ].includes(name)) return {
516
+ name,
517
+ from: "pubinfo-pr"
518
+ };
519
+ }
520
+ }
521
+ ],
522
+ dts: "./.pubinfo/components.d.ts"
523
+ });
524
+ }
525
+
526
+ //#endregion
527
+ //#region src/plugins/intergrations/compression.ts
528
+ function createCompression(env) {
529
+ const { VITE_BUILD_COMPRESS } = env;
530
+ const compressList = VITE_BUILD_COMPRESS?.split(",") ?? [];
531
+ const plugin = [];
532
+ if (compressList.includes("gzip")) plugin.push(compression({
533
+ ext: ".gz",
534
+ deleteOriginFile: false
535
+ }));
536
+ if (compressList.includes("brotli")) plugin.push(compression({
537
+ ext: ".br",
538
+ algorithm: "brotliCompress",
539
+ deleteOriginFile: false
540
+ }));
541
+ return plugin;
542
+ }
543
+
544
+ //#endregion
545
+ //#region src/plugins/intergrations/devtools.ts
546
+ function createPubinfoDevtoolsPlugin() {
547
+ return pubinfoDevtools();
548
+ }
549
+
550
+ //#endregion
551
+ //#region src/plugins/intergrations/dts.ts
552
+ function createDTS() {
553
+ return dts({
554
+ clearPureImport: false,
555
+ exclude: ["tests/**/*", ".pubinfo/**/*"]
556
+ });
557
+ }
558
+
559
+ //#endregion
560
+ //#region src/plugins/intergrations/icon.ts
561
+ function createIcons() {
562
+ return Icons({ autoInstall: false });
563
+ }
564
+
565
+ //#endregion
566
+ //#region src/plugins/intergrations/inject-css.ts
567
+ function createInjectCSS() {
568
+ return libInjectCss();
569
+ }
570
+
571
+ //#endregion
572
+ //#region src/plugins/intergrations/inspector.ts
573
+ function createInspector(devtoolsConfig) {
574
+ if (devtoolsConfig?.enabled) return VueDevTools({ ...devtoolsConfig });
575
+ else return null;
576
+ }
577
+
578
+ //#endregion
579
+ //#region src/plugins/intergrations/legacy.ts
580
+ function createLegacy(env) {
581
+ if (env.VITE_BUILD_LEGACY !== "true") return false;
582
+ return vueLegacy({
583
+ modernPolyfills: ["es.array.at", "es.array.find-last"],
584
+ additionalLegacyPolyfills: ["abort-controller/polyfill"]
585
+ });
586
+ }
587
+
588
+ //#endregion
589
+ //#region src/plugins/intergrations/mock.ts
590
+ function createMock(env, isBuild) {
591
+ const { VITE_BUILD_MOCK } = env;
592
+ if (!existsSync(resolve(cwd(), "src/mock"))) return;
593
+ return vitePluginFakeServer({
594
+ logger: !isBuild,
595
+ include: "src/mock",
596
+ infixName: false,
597
+ enableProd: isBuild && VITE_BUILD_MOCK === "true"
598
+ });
599
+ }
600
+
601
+ //#endregion
602
+ //#region src/plugins/intergrations/openapi.ts
603
+ function createOpenAPI(options) {
604
+ return OpenAPI(options || { enabled: false });
605
+ }
606
+
607
+ //#endregion
608
+ //#region src/plugins/intergrations/unocss.ts
609
+ function createUnocss() {
610
+ return Unocss();
611
+ }
612
+
613
+ //#endregion
614
+ //#region src/plugins/index.ts
615
+ function createVitePlugins(viteEnv, isBuild = false, config, type) {
616
+ return [
617
+ vue(),
618
+ vueJsx(),
619
+ createLegacy(viteEnv),
620
+ createAutoImport(),
621
+ createComponents(),
622
+ createUnocss(),
623
+ createIcons(),
624
+ createMock(viteEnv, isBuild),
625
+ createInspector(config.devtools),
626
+ createPubinfoDevtoolsPlugin(),
627
+ createOpenAPI(config.openapi),
628
+ createLibResolver(config.resolver),
629
+ createAppInfo(),
630
+ createVirtualInspector({ enabled: true }),
631
+ createSystemInfo(),
632
+ type === "module" ? [
633
+ createDTS(),
634
+ createInjectCSS(),
635
+ createInjectAuto({ id: config.moduleId })
636
+ ] : [createCleanBuild()],
637
+ isBuild ? createCompression(viteEnv) : null
638
+ ].filter(Boolean);
639
+ }
640
+
641
+ //#endregion
642
+ //#region src/config/application.ts
643
+ function createDefaultAppConfig(config) {
644
+ return ({ mode, command }) => {
645
+ const root = cwd();
646
+ const isBuild = command === "build";
647
+ const timestamp = (/* @__PURE__ */ new Date()).getTime();
648
+ const env = loadEnv(mode, root);
649
+ const { VITE_OPEN_PROXY, VITE_BUILD_SOURCEMAP } = env;
650
+ return {
651
+ base: "./",
652
+ server: {
653
+ open: true,
654
+ host: true,
655
+ proxy: getServerProxy(env, !isBuild && VITE_OPEN_PROXY === "true"),
656
+ warmup: { clientFiles: ["./index.html"] }
657
+ },
658
+ optimizeDeps: { exclude: [
659
+ "pubinfo-pr",
660
+ "@pubinfo-pr/core",
661
+ "alova"
662
+ ] },
663
+ resolve: { alias: alias(root) },
664
+ build: {
665
+ outDir: mode === "production" ? "dist" : `dist-${mode}`,
666
+ sourcemap: VITE_BUILD_SOURCEMAP === "true",
667
+ reportCompressedSize: false,
668
+ chunkSizeWarningLimit: 2e3,
669
+ rolldownOptions: { output: {
670
+ entryFileNames: `assets/entry/[name]-[hash]-${timestamp}.js`,
671
+ advancedChunks: { groups: [{
672
+ name: "pubinfo-pr",
673
+ test: "pubinfo-pr"
674
+ }] }
675
+ } }
676
+ },
677
+ plugins: createVitePlugins(env, isBuild, config, "app")
678
+ };
679
+ };
680
+ }
681
+
682
+ //#endregion
683
+ //#region src/config/module.ts
684
+ function createDefaultModuleConfig(config) {
685
+ return ({ mode, command }) => {
686
+ const root = cwd();
687
+ const isBuild = command === "build";
688
+ const env = loadEnv(mode, root);
689
+ return {
690
+ optimizeDeps: { exclude: [
691
+ "pubinfo-pr",
692
+ "@pubinfo-pr/core",
693
+ "alova"
694
+ ] },
695
+ resolve: { alias: alias(root) },
696
+ build: { rolldownOptions: {
697
+ preserveEntrySignatures: "allow-extension",
698
+ external: [
699
+ "vue",
700
+ "vue-router",
701
+ "pinia",
702
+ "unocss"
703
+ ]
704
+ } },
705
+ plugins: createVitePlugins(env, isBuild, config, "module")
706
+ };
707
+ };
708
+ }
709
+
710
+ //#endregion
711
+ //#region src/config/index.ts
712
+ /**
713
+ * 构建应用配置
714
+ */
715
+ function definePubinfoConfig(config) {
716
+ return {
717
+ ...config,
718
+ vite: mergeViteConfig(createDefaultAppConfig(config), config)
719
+ };
720
+ }
721
+ /**
722
+ * 构建模块配置
723
+ */
724
+ function defineModuleConfig(config) {
725
+ return {
726
+ ...config,
727
+ vite: mergeViteConfig(createDefaultModuleConfig(config), config)
728
+ };
729
+ }
730
+ /**
731
+ * 合并默认Vite配置
732
+ */
733
+ function mergeViteConfig(defaultOptions, config = {}) {
734
+ const { vite: viteOptions = {} } = config;
735
+ return defineConfig(({ mode, command }) => {
736
+ return mergeConfig(defaultOptions({
737
+ mode,
738
+ command
739
+ }), typeof viteOptions === "function" ? viteOptions({
740
+ mode,
741
+ command
742
+ }) : viteOptions);
743
+ });
744
+ }
745
+
746
+ //#endregion
747
+ export { defineModuleConfig, definePubinfoConfig };
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 ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@pubinfo-pr/vite",
3
+ "type": "module",
4
+ "version": "0.1.1",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./dist/index.d.ts",
8
+ "default": "./dist/index.js"
9
+ }
10
+ },
11
+ "main": "./dist/index.js",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "engines": {
18
+ "node": "^20.19.0 || >=22.12.0"
19
+ },
20
+ "peerDependencies": {
21
+ "vue": "^3.5.17"
22
+ },
23
+ "dependencies": {
24
+ "@pubinfo-pr/devtools": "0.1.1",
25
+ "@pubinfo-pr/shared": "0.1.1",
26
+ "@pubinfo/unplugin-openapi": "^0.9.1",
27
+ "@vitejs/plugin-legacy": "^7.2.1",
28
+ "@vitejs/plugin-vue": "^6.0.0",
29
+ "@vitejs/plugin-vue-jsx": "^5.0.1",
30
+ "abort-controller": "^3.0.0",
31
+ "boxen": "^8.0.1",
32
+ "chalk": "^5.4.1",
33
+ "dayjs": "^1.11.13",
34
+ "fast-glob": "^3.3.3",
35
+ "fs-extra": "^11.3.0",
36
+ "jszip": "^3.10.1",
37
+ "lodash-es": "^4.17.21",
38
+ "magic-string": "^0.30.19",
39
+ "micromatch": "^4.0.8",
40
+ "picomatch": "^4.0.3",
41
+ "pkg-types": "^2.3.0",
42
+ "rolldown-vite": "^7.1.2",
43
+ "terser": "^5.43.1",
44
+ "unocss": "^66.4.2",
45
+ "unplugin-auto-import": "^20.0.0",
46
+ "unplugin-icons": "^22.2.0",
47
+ "unplugin-vue-components": "^29.0.0",
48
+ "vite-plugin-compression": "^0.5.1",
49
+ "vite-plugin-dts": "^4.5.4",
50
+ "vite-plugin-env-runtime": "^0.3.6",
51
+ "vite-plugin-fake-server": "^2.2.0",
52
+ "vite-plugin-lib-inject-css": "^2.2.2",
53
+ "vite-plugin-vue-devtools": "^8.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/fs-extra": "^11.0.4",
57
+ "@types/lodash-es": "^4.17.12",
58
+ "@types/micromatch": "^4.0.9",
59
+ "@types/node": "^24.0.10",
60
+ "@types/picomatch": "^4.0.2",
61
+ "vue": "^3.5.17"
62
+ },
63
+ "scripts": {
64
+ "dev": "tsdown --watch",
65
+ "build": "tsdown"
66
+ }
67
+ }