@holix/cli 0.3.0 → 1.0.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/dist/index.cjs CHANGED
@@ -1,17 +1,93 @@
1
1
  #!/usr/bin/env node
2
2
  const require_config = require('./config-DiolnOet.cjs');
3
3
  let citty = require("citty");
4
+ let node_fs = require("node:fs");
5
+ let node_fs_promises = require("node:fs/promises");
6
+ let node_os = require("node:os");
7
+ let node_path = require("node:path");
4
8
  let node_process = require("node:process");
5
9
  node_process = require_config.__toESM(node_process);
6
10
  let __holix_builder = require("@holix/builder");
11
+ let electron_builder = require("electron-builder");
12
+ let pathe = require("pathe");
7
13
  let consola = require("consola");
8
14
  let node_module = require("node:module");
9
- let node_path = require("node:path");
10
15
  let node_url = require("node:url");
11
16
  require("vite");
12
17
  let __holix_electron = require("@holix/electron");
18
+ let __tanstack_pacer = require("@tanstack/pacer");
13
19
  let perfect_debounce = require("perfect-debounce");
14
20
 
21
+ //#region src/utils/electron-builder-config.ts
22
+ /**
23
+ * 根据 Holix 配置生成 electron-builder 配置
24
+ */
25
+ function generateElectronBuilderConfig(rootDir, config, packageJson) {
26
+ const builderConfig = config.electronBuilder || {};
27
+ const appName = packageJson.name || "holix-app";
28
+ const outDir = config.outDir || ".holix";
29
+ const appId = config.app?.id || `com.${appName.replace(/[^a-z0-9]/gi, "")}`;
30
+ let cleanProductName = builderConfig.productName || appName;
31
+ if (!/[\s-]/.test(cleanProductName)) cleanProductName = cleanProductName.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2").split(/[-_@/]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ").trim();
32
+ cleanProductName = cleanProductName.replace(/[@/\\:*?"<>|]/g, "").replace(/\s+/g, " ").replace(/^[\s-]+|[\s-]+$/g, "").trim();
33
+ if (!cleanProductName) cleanProductName = "Holix App";
34
+ const relativeOutDir = (0, pathe.normalize)(outDir).replace((0, pathe.normalize)(rootDir), "");
35
+ const relativePublicDir = config.publicDir ? (0, pathe.normalize)(config.publicDir).replace((0, pathe.normalize)(rootDir), "") : null;
36
+ const macIconPath = builderConfig.mac?.icon ? (0, node_path.resolve)(rootDir, builderConfig.mac.icon) : (0, node_path.resolve)(rootDir, "public/icon.icns");
37
+ const winIconPath = builderConfig.win?.icon ? (0, node_path.resolve)(rootDir, builderConfig.win.icon) : (0, node_path.resolve)(rootDir, "public/icon.ico");
38
+ const linuxIconPath = builderConfig.linux?.icon ? (0, node_path.resolve)(rootDir, builderConfig.linux.icon) : (0, node_path.resolve)(rootDir, "public/icon.png");
39
+ const hasMacIcon = (0, node_fs.existsSync)(macIconPath);
40
+ const hasWinIcon = (0, node_fs.existsSync)(winIconPath);
41
+ const hasLinuxIcon = (0, node_fs.existsSync)(linuxIconPath);
42
+ const devDependencies = Object.keys(packageJson.devDependencies || {}).map((dep) => {
43
+ return `!node_modules/${dep}/**`;
44
+ });
45
+ const files = Array.from(new Set([
46
+ `${relativeOutDir.substring(1)}/**/*`,
47
+ `!${relativeOutDir.substring(1)}/**/*.{ts,jsx,tsx,map,vue}`,
48
+ `${relativePublicDir ? `./${relativePublicDir}/**` : ""}`,
49
+ "./package.json",
50
+ "!tsconfig*.json",
51
+ "!vite.config.*",
52
+ "!holix.config.*",
53
+ ...devDependencies,
54
+ ...builderConfig?.extraConfig?.files || []
55
+ ]));
56
+ return {
57
+ appId,
58
+ productName: cleanProductName,
59
+ directories: {
60
+ output: builderConfig.outputDir || "app-dist",
61
+ app: rootDir
62
+ },
63
+ npmRebuild: false,
64
+ nodeGypRebuild: false,
65
+ buildDependenciesFromSource: false,
66
+ includeSubNodeModules: false,
67
+ mac: {
68
+ target: builderConfig.mac?.target || ["dmg", "zip"],
69
+ category: builderConfig.mac?.category || "public.app-category.utilities",
70
+ ...hasMacIcon ? { icon: macIconPath } : {}
71
+ },
72
+ win: {
73
+ target: builderConfig.win?.target || ["nsis", "zip"],
74
+ ...hasWinIcon ? { icon: winIconPath } : {}
75
+ },
76
+ linux: {
77
+ target: builderConfig.linux?.target || ["AppImage", "deb"],
78
+ category: builderConfig.linux?.category || "Utility",
79
+ ...hasLinuxIcon ? { icon: linuxIconPath } : {}
80
+ },
81
+ nsis: {
82
+ oneClick: builderConfig.nsis?.oneClick ?? false,
83
+ allowToChangeInstallationDirectory: builderConfig.nsis?.allowToChangeInstallationDirectory ?? true
84
+ },
85
+ ...builderConfig.extraConfig || {},
86
+ files
87
+ };
88
+ }
89
+
90
+ //#endregion
15
91
  //#region src/utils/logger.ts
16
92
  const logger = consola.consola.withTag("holix");
17
93
  function banner(msg) {
@@ -66,21 +142,46 @@ async function buildVite(cwd, holixConfig) {
66
142
 
67
143
  //#endregion
68
144
  //#region src/commands/build.ts
145
+ /**
146
+ * 获取当前平台对应的 electron-builder target
147
+ */
148
+ function getPlatformTarget() {
149
+ switch ((0, node_os.platform)()) {
150
+ case "darwin": return "mac";
151
+ case "win32": return "win";
152
+ default: return "linux";
153
+ }
154
+ }
69
155
  const runBuild = (0, citty.defineCommand)({
70
156
  meta: {
71
157
  name: "build",
72
158
  description: "Build Holix application for production"
73
159
  },
74
- args: { clear: {
75
- type: "boolean",
76
- description: "clear output directory before build",
77
- default: true
78
- } },
160
+ args: {
161
+ clear: {
162
+ type: "boolean",
163
+ description: "clear output directory before build",
164
+ default: true
165
+ },
166
+ package: {
167
+ type: "boolean",
168
+ description: "package application with electron-builder after build",
169
+ default: false
170
+ },
171
+ target: {
172
+ type: "string",
173
+ description: "build target platform for packaging: mac, win, linux (default: current platform)"
174
+ },
175
+ publish: {
176
+ type: "string",
177
+ description: "publish options: never, onTag, onTagOrDraft, always",
178
+ default: "never"
179
+ }
180
+ },
79
181
  async run({ args }) {
80
182
  const rootDir = node_process.default.cwd();
81
183
  banner("🏗️ 构建 Holix 应用程序");
82
184
  logger.info("Root directory:", rootDir);
83
- logger.info("Auto open:", args.open);
84
185
  if (args.clear) logger.info("Clear output:", "enabled");
85
186
  try {
86
187
  const { config, packageJson } = await require_config.loadHolixConfig({ cwd: rootDir });
@@ -88,6 +189,57 @@ const runBuild = (0, citty.defineCommand)({
88
189
  await buildVite(rootDir, config);
89
190
  await (0, __holix_builder.build)(config, packageJson, { clean: args.clear });
90
191
  logger.success("All builds completed successfully");
192
+ if (args.package) {
193
+ logger.info("\n📦 Packaging application with electron-builder...");
194
+ const builderConfig = generateElectronBuilderConfig(rootDir, config, packageJson);
195
+ const outputDir = (0, node_path.resolve)(rootDir, builderConfig.directories?.output || "app-dist");
196
+ if ((0, node_fs.existsSync)(outputDir)) {
197
+ logger.info("Cleaning previous build output...");
198
+ try {
199
+ await (0, node_fs_promises.rm)(outputDir, {
200
+ recursive: true,
201
+ force: true,
202
+ maxRetries: 3,
203
+ retryDelay: 1e3
204
+ });
205
+ logger.success("Previous build output cleaned");
206
+ } catch (cleanError) {
207
+ logger.warn("Failed to clean previous build output:", cleanError);
208
+ logger.warn("Continuing with build...");
209
+ }
210
+ }
211
+ const targetPlatform = args.target || getPlatformTarget();
212
+ let targets;
213
+ switch (targetPlatform) {
214
+ case "mac":
215
+ targets = electron_builder.Platform.MAC.createTarget();
216
+ break;
217
+ case "win":
218
+ targets = electron_builder.Platform.WINDOWS.createTarget();
219
+ break;
220
+ case "linux":
221
+ targets = electron_builder.Platform.LINUX.createTarget();
222
+ break;
223
+ default: {
224
+ logger.warn(`Unknown platform: ${targetPlatform}, using current platform`);
225
+ const currentPlatform = getPlatformTarget();
226
+ targets = currentPlatform === "mac" ? electron_builder.Platform.MAC.createTarget() : currentPlatform === "win" ? electron_builder.Platform.WINDOWS.createTarget() : electron_builder.Platform.LINUX.createTarget();
227
+ }
228
+ }
229
+ const result = await (0, electron_builder.build)({
230
+ targets,
231
+ config: builderConfig,
232
+ publish: args.publish
233
+ });
234
+ logger.success("✅ Packaging completed successfully!");
235
+ logger.info("Output directory:", outputDir);
236
+ if (result && result.length > 0) {
237
+ logger.success("\nGenerated files:");
238
+ result.forEach((file) => {
239
+ logger.info(` - ${file}`);
240
+ });
241
+ }
242
+ }
91
243
  } catch (error) {
92
244
  logger.error("Build failed:", error);
93
245
  throw error;
@@ -138,6 +290,11 @@ const runDev = (0, citty.defineCommand)({
138
290
  type: "boolean",
139
291
  description: "clear output directory before build",
140
292
  default: true
293
+ },
294
+ autoRestart: {
295
+ type: "boolean",
296
+ description: "automatically restart Electron on main process code changes",
297
+ default: false
141
298
  }
142
299
  },
143
300
  async run({ args }) {
@@ -151,13 +308,13 @@ const runDev = (0, citty.defineCommand)({
151
308
  const viteServer = await createViteDevServer(rootDir, config);
152
309
  const port = config.port ?? 5183;
153
310
  await viteServer.listen(port);
154
- viteServer.printUrls();
155
311
  logger.info("Building client and main processes...");
156
312
  const watcher = await (0, __holix_builder.dev)(config, packageJson, { clean: args.clear });
157
313
  logger.success("✓ Client built");
158
314
  logger.success("All builds completed successfully");
159
315
  if (!packageJson.main) {
160
316
  logger.warn("No main entry found in package.json, skipping Electron start.");
317
+ viteServer.printUrls();
161
318
  return;
162
319
  }
163
320
  if (args.open && packageJson.main) {
@@ -166,28 +323,57 @@ const runDev = (0, citty.defineCommand)({
166
323
  const electronProcess = await (0, __holix_electron.startElectron)({
167
324
  entry: mainEntry,
168
325
  cwd: rootDir,
169
- env: { NODE_ENV: "development" }
326
+ env: { NODE_ENV: "development" },
327
+ enableIpc: true
170
328
  });
171
329
  logger.success("Electron started");
330
+ viteServer.printUrls();
172
331
  let isRestarting = false;
173
332
  const onExit = (0, perfect_debounce.debounce)((code) => {
174
333
  logger.info("Electron process exited with code", code);
175
334
  watcher.close();
176
335
  node_process.default.exit(code ?? 0);
177
336
  }, 100);
178
- const restart = (0, perfect_debounce.debounce)(async () => {
179
- logger.info("Changes detected. Restarting Electron...");
180
- if (isRestarting) return;
337
+ electronProcess.handleIpc("process:restart", async () => {
338
+ logger.info("Electron process requested restart...");
339
+ if (isRestarting) return {
340
+ success: false,
341
+ reason: "already restarting"
342
+ };
181
343
  isRestarting = true;
182
344
  electronProcess.off("exit", onExit);
183
345
  await electronProcess.restart();
184
346
  electronProcess.on("exit", onExit);
185
347
  isRestarting = false;
348
+ return { success: true };
186
349
  });
187
- watcher.on("change", async (event, change) => {
350
+ const notifyFileChange = (0, perfect_debounce.debounce)(async (event, change) => {
188
351
  logger.info(`File ${change.event} detected: ${event}`);
189
- restart();
352
+ electronProcess.sendIpc("file:changed", {
353
+ path: event,
354
+ event: change.event,
355
+ timestamp: Date.now()
356
+ });
357
+ }, 100);
358
+ const batcher = new __tanstack_pacer.AsyncBatcher(async (items) => {
359
+ notifyFileChange(items, { event: "change" });
360
+ }, {
361
+ maxSize: 100,
362
+ wait: 100,
363
+ onError: (error, batch) => {
364
+ logger.error("Failed to send update batch:", error, batch);
365
+ },
366
+ asyncRetryerOptions: {
367
+ maxAttempts: 3,
368
+ backoff: "exponential",
369
+ baseWait: 1e3,
370
+ jitter: .3
371
+ }
372
+ });
373
+ if (args.autoRestart) watcher.on("change", async (event, _) => {
374
+ batcher.addItem(event);
190
375
  });
376
+ else watcher.close();
191
377
  electronProcess.on("exit", onExit);
192
378
  } else watcher.close();
193
379
  } catch (error) {
package/dist/index.mjs CHANGED
@@ -2,15 +2,91 @@
2
2
  import { n as loadHolixConfig } from "./config-BMXlLU4W.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { defineCommand, runMain } from "citty";
5
+ import { existsSync } from "node:fs";
6
+ import { rm } from "node:fs/promises";
7
+ import { platform } from "node:os";
8
+ import { join, resolve } from "node:path";
5
9
  import process from "node:process";
6
10
  import { build, dev } from "@holix/builder";
11
+ import { Platform, build as build$1 } from "electron-builder";
12
+ import { normalize } from "pathe";
7
13
  import { consola } from "consola";
8
- import { join, resolve } from "node:path";
9
14
  import { pathToFileURL } from "node:url";
10
15
  import "vite";
11
16
  import { startElectron } from "@holix/electron";
17
+ import { AsyncBatcher } from "@tanstack/pacer";
12
18
  import { debounce } from "perfect-debounce";
13
19
 
20
+ //#region src/utils/electron-builder-config.ts
21
+ /**
22
+ * 根据 Holix 配置生成 electron-builder 配置
23
+ */
24
+ function generateElectronBuilderConfig(rootDir, config, packageJson) {
25
+ const builderConfig = config.electronBuilder || {};
26
+ const appName = packageJson.name || "holix-app";
27
+ const outDir = config.outDir || ".holix";
28
+ const appId = config.app?.id || `com.${appName.replace(/[^a-z0-9]/gi, "")}`;
29
+ let cleanProductName = builderConfig.productName || appName;
30
+ if (!/[\s-]/.test(cleanProductName)) cleanProductName = cleanProductName.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2").split(/[-_@/]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ").trim();
31
+ cleanProductName = cleanProductName.replace(/[@/\\:*?"<>|]/g, "").replace(/\s+/g, " ").replace(/^[\s-]+|[\s-]+$/g, "").trim();
32
+ if (!cleanProductName) cleanProductName = "Holix App";
33
+ const relativeOutDir = normalize(outDir).replace(normalize(rootDir), "");
34
+ const relativePublicDir = config.publicDir ? normalize(config.publicDir).replace(normalize(rootDir), "") : null;
35
+ const macIconPath = builderConfig.mac?.icon ? resolve(rootDir, builderConfig.mac.icon) : resolve(rootDir, "public/icon.icns");
36
+ const winIconPath = builderConfig.win?.icon ? resolve(rootDir, builderConfig.win.icon) : resolve(rootDir, "public/icon.ico");
37
+ const linuxIconPath = builderConfig.linux?.icon ? resolve(rootDir, builderConfig.linux.icon) : resolve(rootDir, "public/icon.png");
38
+ const hasMacIcon = existsSync(macIconPath);
39
+ const hasWinIcon = existsSync(winIconPath);
40
+ const hasLinuxIcon = existsSync(linuxIconPath);
41
+ const devDependencies = Object.keys(packageJson.devDependencies || {}).map((dep) => {
42
+ return `!node_modules/${dep}/**`;
43
+ });
44
+ const files = Array.from(new Set([
45
+ `${relativeOutDir.substring(1)}/**/*`,
46
+ `!${relativeOutDir.substring(1)}/**/*.{ts,jsx,tsx,map,vue}`,
47
+ `${relativePublicDir ? `./${relativePublicDir}/**` : ""}`,
48
+ "./package.json",
49
+ "!tsconfig*.json",
50
+ "!vite.config.*",
51
+ "!holix.config.*",
52
+ ...devDependencies,
53
+ ...builderConfig?.extraConfig?.files || []
54
+ ]));
55
+ return {
56
+ appId,
57
+ productName: cleanProductName,
58
+ directories: {
59
+ output: builderConfig.outputDir || "app-dist",
60
+ app: rootDir
61
+ },
62
+ npmRebuild: false,
63
+ nodeGypRebuild: false,
64
+ buildDependenciesFromSource: false,
65
+ includeSubNodeModules: false,
66
+ mac: {
67
+ target: builderConfig.mac?.target || ["dmg", "zip"],
68
+ category: builderConfig.mac?.category || "public.app-category.utilities",
69
+ ...hasMacIcon ? { icon: macIconPath } : {}
70
+ },
71
+ win: {
72
+ target: builderConfig.win?.target || ["nsis", "zip"],
73
+ ...hasWinIcon ? { icon: winIconPath } : {}
74
+ },
75
+ linux: {
76
+ target: builderConfig.linux?.target || ["AppImage", "deb"],
77
+ category: builderConfig.linux?.category || "Utility",
78
+ ...hasLinuxIcon ? { icon: linuxIconPath } : {}
79
+ },
80
+ nsis: {
81
+ oneClick: builderConfig.nsis?.oneClick ?? false,
82
+ allowToChangeInstallationDirectory: builderConfig.nsis?.allowToChangeInstallationDirectory ?? true
83
+ },
84
+ ...builderConfig.extraConfig || {},
85
+ files
86
+ };
87
+ }
88
+
89
+ //#endregion
14
90
  //#region src/utils/logger.ts
15
91
  const logger = consola.withTag("holix");
16
92
  function banner(msg) {
@@ -65,21 +141,46 @@ async function buildVite(cwd, holixConfig) {
65
141
 
66
142
  //#endregion
67
143
  //#region src/commands/build.ts
144
+ /**
145
+ * 获取当前平台对应的 electron-builder target
146
+ */
147
+ function getPlatformTarget() {
148
+ switch (platform()) {
149
+ case "darwin": return "mac";
150
+ case "win32": return "win";
151
+ default: return "linux";
152
+ }
153
+ }
68
154
  const runBuild = defineCommand({
69
155
  meta: {
70
156
  name: "build",
71
157
  description: "Build Holix application for production"
72
158
  },
73
- args: { clear: {
74
- type: "boolean",
75
- description: "clear output directory before build",
76
- default: true
77
- } },
159
+ args: {
160
+ clear: {
161
+ type: "boolean",
162
+ description: "clear output directory before build",
163
+ default: true
164
+ },
165
+ package: {
166
+ type: "boolean",
167
+ description: "package application with electron-builder after build",
168
+ default: false
169
+ },
170
+ target: {
171
+ type: "string",
172
+ description: "build target platform for packaging: mac, win, linux (default: current platform)"
173
+ },
174
+ publish: {
175
+ type: "string",
176
+ description: "publish options: never, onTag, onTagOrDraft, always",
177
+ default: "never"
178
+ }
179
+ },
78
180
  async run({ args }) {
79
181
  const rootDir = process.cwd();
80
182
  banner("🏗️ 构建 Holix 应用程序");
81
183
  logger.info("Root directory:", rootDir);
82
- logger.info("Auto open:", args.open);
83
184
  if (args.clear) logger.info("Clear output:", "enabled");
84
185
  try {
85
186
  const { config, packageJson } = await loadHolixConfig({ cwd: rootDir });
@@ -87,6 +188,57 @@ const runBuild = defineCommand({
87
188
  await buildVite(rootDir, config);
88
189
  await build(config, packageJson, { clean: args.clear });
89
190
  logger.success("All builds completed successfully");
191
+ if (args.package) {
192
+ logger.info("\n📦 Packaging application with electron-builder...");
193
+ const builderConfig = generateElectronBuilderConfig(rootDir, config, packageJson);
194
+ const outputDir = resolve(rootDir, builderConfig.directories?.output || "app-dist");
195
+ if (existsSync(outputDir)) {
196
+ logger.info("Cleaning previous build output...");
197
+ try {
198
+ await rm(outputDir, {
199
+ recursive: true,
200
+ force: true,
201
+ maxRetries: 3,
202
+ retryDelay: 1e3
203
+ });
204
+ logger.success("Previous build output cleaned");
205
+ } catch (cleanError) {
206
+ logger.warn("Failed to clean previous build output:", cleanError);
207
+ logger.warn("Continuing with build...");
208
+ }
209
+ }
210
+ const targetPlatform = args.target || getPlatformTarget();
211
+ let targets;
212
+ switch (targetPlatform) {
213
+ case "mac":
214
+ targets = Platform.MAC.createTarget();
215
+ break;
216
+ case "win":
217
+ targets = Platform.WINDOWS.createTarget();
218
+ break;
219
+ case "linux":
220
+ targets = Platform.LINUX.createTarget();
221
+ break;
222
+ default: {
223
+ logger.warn(`Unknown platform: ${targetPlatform}, using current platform`);
224
+ const currentPlatform = getPlatformTarget();
225
+ targets = currentPlatform === "mac" ? Platform.MAC.createTarget() : currentPlatform === "win" ? Platform.WINDOWS.createTarget() : Platform.LINUX.createTarget();
226
+ }
227
+ }
228
+ const result = await build$1({
229
+ targets,
230
+ config: builderConfig,
231
+ publish: args.publish
232
+ });
233
+ logger.success("✅ Packaging completed successfully!");
234
+ logger.info("Output directory:", outputDir);
235
+ if (result && result.length > 0) {
236
+ logger.success("\nGenerated files:");
237
+ result.forEach((file) => {
238
+ logger.info(` - ${file}`);
239
+ });
240
+ }
241
+ }
90
242
  } catch (error) {
91
243
  logger.error("Build failed:", error);
92
244
  throw error;
@@ -137,6 +289,11 @@ const runDev = defineCommand({
137
289
  type: "boolean",
138
290
  description: "clear output directory before build",
139
291
  default: true
292
+ },
293
+ autoRestart: {
294
+ type: "boolean",
295
+ description: "automatically restart Electron on main process code changes",
296
+ default: false
140
297
  }
141
298
  },
142
299
  async run({ args }) {
@@ -150,13 +307,13 @@ const runDev = defineCommand({
150
307
  const viteServer = await createViteDevServer(rootDir, config);
151
308
  const port = config.port ?? 5183;
152
309
  await viteServer.listen(port);
153
- viteServer.printUrls();
154
310
  logger.info("Building client and main processes...");
155
311
  const watcher = await dev(config, packageJson, { clean: args.clear });
156
312
  logger.success("✓ Client built");
157
313
  logger.success("All builds completed successfully");
158
314
  if (!packageJson.main) {
159
315
  logger.warn("No main entry found in package.json, skipping Electron start.");
316
+ viteServer.printUrls();
160
317
  return;
161
318
  }
162
319
  if (args.open && packageJson.main) {
@@ -165,28 +322,57 @@ const runDev = defineCommand({
165
322
  const electronProcess = await startElectron({
166
323
  entry: mainEntry,
167
324
  cwd: rootDir,
168
- env: { NODE_ENV: "development" }
325
+ env: { NODE_ENV: "development" },
326
+ enableIpc: true
169
327
  });
170
328
  logger.success("Electron started");
329
+ viteServer.printUrls();
171
330
  let isRestarting = false;
172
331
  const onExit = debounce((code) => {
173
332
  logger.info("Electron process exited with code", code);
174
333
  watcher.close();
175
334
  process.exit(code ?? 0);
176
335
  }, 100);
177
- const restart = debounce(async () => {
178
- logger.info("Changes detected. Restarting Electron...");
179
- if (isRestarting) return;
336
+ electronProcess.handleIpc("process:restart", async () => {
337
+ logger.info("Electron process requested restart...");
338
+ if (isRestarting) return {
339
+ success: false,
340
+ reason: "already restarting"
341
+ };
180
342
  isRestarting = true;
181
343
  electronProcess.off("exit", onExit);
182
344
  await electronProcess.restart();
183
345
  electronProcess.on("exit", onExit);
184
346
  isRestarting = false;
347
+ return { success: true };
185
348
  });
186
- watcher.on("change", async (event, change) => {
349
+ const notifyFileChange = debounce(async (event, change) => {
187
350
  logger.info(`File ${change.event} detected: ${event}`);
188
- restart();
351
+ electronProcess.sendIpc("file:changed", {
352
+ path: event,
353
+ event: change.event,
354
+ timestamp: Date.now()
355
+ });
356
+ }, 100);
357
+ const batcher = new AsyncBatcher(async (items) => {
358
+ notifyFileChange(items, { event: "change" });
359
+ }, {
360
+ maxSize: 100,
361
+ wait: 100,
362
+ onError: (error, batch) => {
363
+ logger.error("Failed to send update batch:", error, batch);
364
+ },
365
+ asyncRetryerOptions: {
366
+ maxAttempts: 3,
367
+ backoff: "exponential",
368
+ baseWait: 1e3,
369
+ jitter: .3
370
+ }
371
+ });
372
+ if (args.autoRestart) watcher.on("change", async (event, _) => {
373
+ batcher.addItem(event);
189
374
  });
375
+ else watcher.close();
190
376
  electronProcess.on("exit", onExit);
191
377
  } else watcher.close();
192
378
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["viteEntry: string","err: any"],"sources":["../src/utils/logger.ts","../src/vite/resolve.ts","../src/vite/build.ts","../src/commands/build.ts","../src/vite/server.ts","../src/commands/dev.ts","../src/index.ts"],"sourcesContent":["import { consola } from 'consola'\r\n\r\nexport const logger = consola.withTag('holix')\r\n\r\nexport function banner(msg: string) {\r\n logger.box(msg)\r\n}\r\n","import type { HolixConfig } from '@holix/config'\r\nimport type { UserConfig as ViteConfig } from 'vite'\r\nimport { createRequire } from 'node:module'\r\nimport { join } from 'node:path'\r\nimport { pathToFileURL } from 'node:url'\r\n\r\nexport { mergeConfig } from 'vite'\r\n\r\nexport async function resolveViteFromCwd(\r\n cwd: string,\r\n): Promise<typeof import('vite')> {\r\n const _require = createRequire(import.meta.url)\r\n let viteEntry: string\r\n\r\n try {\r\n viteEntry = _require.resolve('vite', {\r\n paths: [cwd],\r\n })\r\n }\r\n catch {\r\n throw new Error(\r\n `[holix] Cannot find \"vite\" in project: ${cwd}\\n`\r\n + `Please install it first: pnpm add -D vite`,\r\n )\r\n }\r\n\r\n try {\r\n // 优先走 ESM\r\n return await import(pathToFileURL(viteEntry).href)\r\n }\r\n catch (err: any) {\r\n // 仅在明确是 CJS 不兼容时 fallback\r\n if (\r\n err?.code === 'ERR_REQUIRE_ESM'\r\n || err?.message?.includes('Cannot use import statement')\r\n ) {\r\n return _require(viteEntry)\r\n }\r\n\r\n throw err\r\n }\r\n}\r\n\r\nexport async function resolveViteConfigFromHolixConfig(cwd: string, holixConfig: HolixConfig): Promise<ViteConfig> {\r\n const outdir = join(holixConfig.outDir || '.holix', 'client')\r\n\r\n const viteConfig: ViteConfig = {\r\n root: cwd,\r\n base: './',\r\n plugins: [\r\n ...(holixConfig.vitePlugins || []),\r\n ],\r\n resolve: {\r\n alias: holixConfig.alias || {},\r\n },\r\n build: {\r\n outDir: outdir,\r\n rollupOptions: {\r\n external: ['electron'],\r\n output: {\r\n // 可选:控制输出文件名\r\n entryFileNames: '[name].js',\r\n chunkFileNames: 'chunks/[name]-[hash].js',\r\n assetFileNames: 'assets/[name]-[hash][extname]',\r\n },\r\n },\r\n },\r\n }\r\n return viteConfig\r\n}\r\n","import type { HolixConfig } from '@holix/config'\r\nimport { resolveViteConfigFromHolixConfig, resolveViteFromCwd } from './resolve'\r\n\r\nexport async function buildVite(cwd: string, holixConfig: HolixConfig) {\r\n // 从用户项目的 node_modules 中解析 Vite\r\n const vite = await resolveViteFromCwd(cwd)\r\n\r\n // 创建 Vite 服务器配置\r\n const serverConfig = await resolveViteConfigFromHolixConfig(cwd, holixConfig)\r\n\r\n return vite.build(serverConfig)\r\n}\r\n","import process from 'node:process'\r\nimport { build } from '@holix/builder'\r\nimport { defineCommand } from 'citty'\r\nimport { loadHolixConfig } from '../config'\r\nimport { banner, logger } from '../utils/logger'\r\nimport { buildVite } from '../vite/build'\r\n\r\nexport const runBuild = defineCommand({\r\n meta: {\r\n name: 'build',\r\n description: 'Build Holix application for production',\r\n },\r\n args: {\r\n clear: {\r\n type: 'boolean',\r\n description: 'clear output directory before build',\r\n default: true,\r\n },\r\n },\r\n async run({ args }) {\r\n const rootDir = process.cwd()\r\n banner('🏗️ 构建 Holix 应用程序')\r\n\r\n logger.info('Root directory:', rootDir)\r\n logger.info('Auto open:', args.open)\r\n if (args.clear) {\r\n logger.info('Clear output:', 'enabled')\r\n }\r\n\r\n try {\r\n const { config, packageJson } = await loadHolixConfig({\r\n cwd: rootDir,\r\n })\r\n\r\n logger.info('Building client and main processes...')\r\n\r\n await buildVite(rootDir, config)\r\n\r\n await build(config, packageJson, { clean: args.clear })\r\n\r\n logger.success('All builds completed successfully')\r\n }\r\n catch (error) {\r\n logger.error('Build failed:', error)\r\n throw error\r\n }\r\n },\r\n})\r\n","import type { HolixConfig } from '@holix/config/dist/index.mjs'\r\nimport { resolveViteConfigFromHolixConfig, resolveViteFromCwd } from './resolve'\r\n\r\n/**\r\n * 创建 Vite 开发服务器(不立即启动)\r\n *\r\n * @param options - Vite 开发服务器选项\r\n * @returns ViteDevServer 实例\r\n *\r\n * @example\r\n * ```ts\r\n * const server = await createViteDevServer({\r\n * cwd: '/path/to/project',\r\n * config: { root: './src' }\r\n * })\r\n *\r\n * // 手动启动\r\n * await server.listen()\r\n * server.printUrls()\r\n * ```\r\n */\r\nexport async function createViteDevServer(cwd: string, holixConfig: HolixConfig) {\r\n // 从用户项目的 node_modules 中解析 Vite\r\n const vite = await resolveViteFromCwd(cwd)\r\n\r\n // 创建 Vite 服务器配置\r\n const serverConfig = await resolveViteConfigFromHolixConfig(cwd, holixConfig)\r\n\r\n // 创建开发服务器(不启动)\r\n return vite.createServer(serverConfig)\r\n}\r\n","import { resolve } from 'node:path'\r\nimport process from 'node:process'\r\nimport { dev } from '@holix/builder'\r\nimport { startElectron } from '@holix/electron'\r\nimport { defineCommand } from 'citty'\r\nimport { debounce } from 'perfect-debounce'\r\nimport { loadHolixConfig } from '../config'\r\nimport { banner, logger } from '../utils/logger'\r\nimport { createViteDevServer } from '../vite/server'\r\n\r\nexport const runDev = defineCommand({\r\n meta: {\r\n name: 'dev',\r\n description: 'Start Holix development mode (with SSR + Electron hot reload)',\r\n },\r\n args: {\r\n open: {\r\n type: 'boolean',\r\n description: 'auto open Electron window',\r\n default: true,\r\n },\r\n clear: {\r\n type: 'boolean',\r\n description: 'clear output directory before build',\r\n default: true,\r\n },\r\n },\r\n async run({ args }) {\r\n const rootDir = process.cwd()\r\n banner('🚀 启动 Holix 开发模式')\r\n\r\n logger.info('Root directory:', rootDir)\r\n logger.info('Auto open:', args.open)\r\n\r\n if (args.clear) {\r\n logger.info('Clear output:', 'enabled')\r\n }\r\n\r\n try {\r\n const { config, packageJson } = await loadHolixConfig({\r\n cwd: rootDir,\r\n })\r\n\r\n const viteServer = await createViteDevServer(rootDir, config)\r\n\r\n const port = config.port ?? 5183\r\n\r\n await viteServer.listen(port)\r\n\r\n viteServer.printUrls()\r\n\r\n logger.info('Building client and main processes...')\r\n\r\n const watcher = await dev(config, packageJson, { clean: args.clear })\r\n\r\n logger.success('✓ Client built')\r\n\r\n logger.success('All builds completed successfully')\r\n\r\n if (!packageJson.main) {\r\n logger.warn('No main entry found in package.json, skipping Electron start.')\r\n return\r\n }\r\n\r\n // 如果启用 open,启动 Electron 进程\r\n if (args.open && packageJson.main) {\r\n const mainEntry = resolve(rootDir, packageJson.main!)\r\n logger.info('Starting Electron...')\r\n\r\n const electronProcess = await startElectron({\r\n entry: mainEntry,\r\n cwd: rootDir,\r\n env: {\r\n NODE_ENV: 'development',\r\n },\r\n })\r\n\r\n logger.success('Electron started')\r\n\r\n let isRestarting = false\r\n\r\n const onExit = debounce((code: number | null) => {\r\n logger.info('Electron process exited with code', code)\r\n watcher.close()\r\n process.exit(code ?? 0)\r\n }, 100)\r\n\r\n const restart = debounce(async () => {\r\n logger.info('Changes detected. Restarting Electron...')\r\n if (isRestarting) {\r\n return\r\n }\r\n isRestarting = true\r\n electronProcess.off('exit', onExit)\r\n await electronProcess.restart()\r\n electronProcess.on('exit', onExit)\r\n isRestarting = false\r\n })\r\n\r\n watcher.on('change', async (event, change) => {\r\n logger.info(`File ${change.event} detected: ${event}`)\r\n restart()\r\n })\r\n\r\n electronProcess.on('exit', onExit)\r\n }\r\n else {\r\n watcher.close()\r\n }\r\n }\r\n catch (error) {\r\n logger.error('Build failed:', error)\r\n throw error\r\n }\r\n },\r\n})\r\n","#!/usr/bin/env node\r\nimport { defineCommand, runMain } from 'citty'\r\nimport { runBuild } from './commands/build'\r\nimport { runDev } from './commands/dev'\r\n\r\nconst main = defineCommand({\r\n meta: {\r\n name: 'holix',\r\n version: '0.1.0',\r\n description: 'Holix Application Framework CLI - Build desktop apps with Vue SSR + Electron',\r\n },\r\n args: {\r\n clear: {\r\n type: 'boolean',\r\n description: 'clear output directory before build',\r\n default: true,\r\n },\r\n },\r\n subCommands: {\r\n dev: runDev,\r\n build: runBuild,\r\n },\r\n})\r\n\r\nrunMain(main)\r\n"],"mappings":";;;;;;;;;;;;;;AAEA,MAAa,SAAS,QAAQ,QAAQ,QAAQ;AAE9C,SAAgB,OAAO,KAAa;AAClC,QAAO,IAAI,IAAI;;;;;ACGjB,eAAsB,mBACpB,KACgC;CAChC,MAAM,WAAW,cAAc,OAAO,KAAK,IAAI;CAC/C,IAAIA;AAEJ,KAAI;AACF,cAAY,SAAS,QAAQ,QAAQ,EACnC,OAAO,CAAC,IAAI,EACb,CAAC;SAEE;AACJ,QAAM,IAAI,MACR,0CAA0C,IAAI,6CAE/C;;AAGH,KAAI;AAEF,SAAO,MAAM,OAAO,cAAc,UAAU,CAAC;UAExCC,KAAU;AAEf,MACE,KAAK,SAAS,qBACX,KAAK,SAAS,SAAS,8BAA8B,CAExD,QAAO,SAAS,UAAU;AAG5B,QAAM;;;AAIV,eAAsB,iCAAiC,KAAa,aAA+C;CACjH,MAAM,SAAS,KAAK,YAAY,UAAU,UAAU,SAAS;AAwB7D,QAtB+B;EAC7B,MAAM;EACN,MAAM;EACN,SAAS,CACP,GAAI,YAAY,eAAe,EAAE,CAClC;EACD,SAAS,EACP,OAAO,YAAY,SAAS,EAAE,EAC/B;EACD,OAAO;GACL,QAAQ;GACR,eAAe;IACb,UAAU,CAAC,WAAW;IACtB,QAAQ;KAEN,gBAAgB;KAChB,gBAAgB;KAChB,gBAAgB;KACjB;IACF;GACF;EACF;;;;;AChEH,eAAsB,UAAU,KAAa,aAA0B;CAErE,MAAM,OAAO,MAAM,mBAAmB,IAAI;CAG1C,MAAM,eAAe,MAAM,iCAAiC,KAAK,YAAY;AAE7E,QAAO,KAAK,MAAM,aAAa;;;;;ACHjC,MAAa,WAAW,cAAc;CACpC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,EACJ,OAAO;EACL,MAAM;EACN,aAAa;EACb,SAAS;EACV,EACF;CACD,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,UAAU,QAAQ,KAAK;AAC7B,SAAO,qBAAqB;AAE5B,SAAO,KAAK,mBAAmB,QAAQ;AACvC,SAAO,KAAK,cAAc,KAAK,KAAK;AACpC,MAAI,KAAK,MACP,QAAO,KAAK,iBAAiB,UAAU;AAGzC,MAAI;GACF,MAAM,EAAE,QAAQ,gBAAgB,MAAM,gBAAgB,EACpD,KAAK,SACN,CAAC;AAEF,UAAO,KAAK,wCAAwC;AAEpD,SAAM,UAAU,SAAS,OAAO;AAEhC,SAAM,MAAM,QAAQ,aAAa,EAAE,OAAO,KAAK,OAAO,CAAC;AAEvD,UAAO,QAAQ,oCAAoC;WAE9C,OAAO;AACZ,UAAO,MAAM,iBAAiB,MAAM;AACpC,SAAM;;;CAGX,CAAC;;;;;;;;;;;;;;;;;;;;;;AC1BF,eAAsB,oBAAoB,KAAa,aAA0B;CAE/E,MAAM,OAAO,MAAM,mBAAmB,IAAI;CAG1C,MAAM,eAAe,MAAM,iCAAiC,KAAK,YAAY;AAG7E,QAAO,KAAK,aAAa,aAAa;;;;;ACnBxC,MAAa,SAAS,cAAc;CAClC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,MAAM;GACJ,MAAM;GACN,aAAa;GACb,SAAS;GACV;EACD,OAAO;GACL,MAAM;GACN,aAAa;GACb,SAAS;GACV;EACF;CACD,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,UAAU,QAAQ,KAAK;AAC7B,SAAO,mBAAmB;AAE1B,SAAO,KAAK,mBAAmB,QAAQ;AACvC,SAAO,KAAK,cAAc,KAAK,KAAK;AAEpC,MAAI,KAAK,MACP,QAAO,KAAK,iBAAiB,UAAU;AAGzC,MAAI;GACF,MAAM,EAAE,QAAQ,gBAAgB,MAAM,gBAAgB,EACpD,KAAK,SACN,CAAC;GAEF,MAAM,aAAa,MAAM,oBAAoB,SAAS,OAAO;GAE7D,MAAM,OAAO,OAAO,QAAQ;AAE5B,SAAM,WAAW,OAAO,KAAK;AAE7B,cAAW,WAAW;AAEtB,UAAO,KAAK,wCAAwC;GAEpD,MAAM,UAAU,MAAM,IAAI,QAAQ,aAAa,EAAE,OAAO,KAAK,OAAO,CAAC;AAErE,UAAO,QAAQ,iBAAiB;AAEhC,UAAO,QAAQ,oCAAoC;AAEnD,OAAI,CAAC,YAAY,MAAM;AACrB,WAAO,KAAK,gEAAgE;AAC5E;;AAIF,OAAI,KAAK,QAAQ,YAAY,MAAM;IACjC,MAAM,YAAY,QAAQ,SAAS,YAAY,KAAM;AACrD,WAAO,KAAK,uBAAuB;IAEnC,MAAM,kBAAkB,MAAM,cAAc;KAC1C,OAAO;KACP,KAAK;KACL,KAAK,EACH,UAAU,eACX;KACF,CAAC;AAEF,WAAO,QAAQ,mBAAmB;IAElC,IAAI,eAAe;IAEnB,MAAM,SAAS,UAAU,SAAwB;AAC/C,YAAO,KAAK,qCAAqC,KAAK;AACtD,aAAQ,OAAO;AACf,aAAQ,KAAK,QAAQ,EAAE;OACtB,IAAI;IAEP,MAAM,UAAU,SAAS,YAAY;AACnC,YAAO,KAAK,2CAA2C;AACvD,SAAI,aACF;AAEF,oBAAe;AACf,qBAAgB,IAAI,QAAQ,OAAO;AACnC,WAAM,gBAAgB,SAAS;AAC/B,qBAAgB,GAAG,QAAQ,OAAO;AAClC,oBAAe;MACf;AAEF,YAAQ,GAAG,UAAU,OAAO,OAAO,WAAW;AAC5C,YAAO,KAAK,QAAQ,OAAO,MAAM,aAAa,QAAQ;AACtD,cAAS;MACT;AAEF,oBAAgB,GAAG,QAAQ,OAAO;SAGlC,SAAQ,OAAO;WAGZ,OAAO;AACZ,UAAO,MAAM,iBAAiB,MAAM;AACpC,SAAM;;;CAGX,CAAC;;;;AC3FF,QAnBa,cAAc;CACzB,MAAM;EACJ,MAAM;EACN,SAAS;EACT,aAAa;EACd;CACD,MAAM,EACJ,OAAO;EACL,MAAM;EACN,aAAa;EACb,SAAS;EACV,EACF;CACD,aAAa;EACX,KAAK;EACL,OAAO;EACR;CACF,CAAC,CAEW"}
1
+ {"version":3,"file":"index.mjs","names":["viteEntry: string","err: any","electronBuild"],"sources":["../src/utils/electron-builder-config.ts","../src/utils/logger.ts","../src/vite/resolve.ts","../src/vite/build.ts","../src/commands/build.ts","../src/vite/server.ts","../src/commands/dev.ts","../src/index.ts"],"sourcesContent":["import type { HolixConfig } from '@holix/config'\r\nimport type { Configuration as ElectronBuilderConfig } from 'electron-builder'\r\nimport type { PackageJson } from 'pkg-types'\r\nimport { existsSync } from 'node:fs'\r\nimport { resolve } from 'node:path'\r\nimport { normalize } from 'pathe'\r\n/**\r\n * 根据 Holix 配置生成 electron-builder 配置\r\n */\r\nexport function generateElectronBuilderConfig(\r\n rootDir: string,\r\n config: HolixConfig,\r\n packageJson: PackageJson,\r\n): ElectronBuilderConfig {\r\n const builderConfig = config.electronBuilder || {}\r\n const appName = packageJson.name || 'holix-app'\r\n const outDir = config.outDir || '.holix'\r\n const appId = config.app?.id || `com.${appName.replace(/[^a-z0-9]/gi, '')}`\r\n\r\n // 清理 productName,移除不安全字符,但保留空格和连字符\r\n let cleanProductName = builderConfig.productName || appName\r\n\r\n // 如果没有空格和连字符,尝试将驼峰或其他格式转换为可读格式\r\n if (!/[\\s-]/.test(cleanProductName)) {\r\n // 处理驼峰命名: holixPlayground -> Holix Playground\r\n cleanProductName = cleanProductName\r\n .replace(/([a-z])([A-Z])/g, '$1 $2') // 小写后跟大写,添加空格\r\n .replace(/([A-Z])([A-Z][a-z])/g, '$1 $2') // 连续大写后跟小写,添加空格\r\n .split(/[-_@/]/) // 按分隔符拆分\r\n .map((word: string) => word.charAt(0).toUpperCase() + word.slice(1)) // 首字母大写\r\n .join(' ')\r\n .trim()\r\n }\r\n\r\n // 移除文件系统不安全字符,但保留空格和连字符\r\n cleanProductName = cleanProductName\r\n .replace(/[@/\\\\:*?\"<>|]/g, '') // 移除不安全字符\r\n .replace(/\\s+/g, ' ') // 多个空格替换为单个空格\r\n .replace(/^[\\s-]+|[\\s-]+$/g, '') // 移除首尾空格和连字符\r\n .trim()\r\n\r\n // 如果清理后为空,使用默认值\r\n if (!cleanProductName) {\r\n cleanProductName = 'Holix App'\r\n }\r\n\r\n const relativeOutDir = normalize(outDir).replace(normalize(rootDir), '')\r\n const relativePublicDir = config.publicDir\r\n ? normalize(config.publicDir).replace(normalize(rootDir), '')\r\n : null\r\n\r\n // 检查 icon 文件是否存在\r\n const macIconPath = builderConfig.mac?.icon\r\n ? resolve(rootDir, builderConfig.mac.icon)\r\n : resolve(rootDir, 'public/icon.icns')\r\n const winIconPath = builderConfig.win?.icon\r\n ? resolve(rootDir, builderConfig.win.icon)\r\n : resolve(rootDir, 'public/icon.ico')\r\n const linuxIconPath = builderConfig.linux?.icon\r\n ? resolve(rootDir, builderConfig.linux.icon)\r\n : resolve(rootDir, 'public/icon.png')\r\n\r\n const hasMacIcon = existsSync(macIconPath)\r\n const hasWinIcon = existsSync(winIconPath)\r\n const hasLinuxIcon = existsSync(linuxIconPath)\r\n\r\n const devDependencies = Object.keys(packageJson.devDependencies || {}).map((dep) => {\r\n return `!node_modules/${dep}/**`\r\n })\r\n\r\n const files = Array.from(new Set([\r\n `${relativeOutDir.substring(1)}/**/*`,\r\n `!${relativeOutDir.substring(1)}/**/*.{ts,jsx,tsx,map,vue}`, // 排除源代码和映射文件\r\n `${relativePublicDir ? `./${relativePublicDir}/**` : ''}`,\r\n './package.json',\r\n '!tsconfig*.json',\r\n '!vite.config.*',\r\n '!holix.config.*',\r\n ...devDependencies,\r\n ...((builderConfig?.extraConfig?.files as string[]) || []),\r\n ]))\r\n\r\n return {\r\n appId,\r\n productName: cleanProductName,\r\n directories: {\r\n output: builderConfig.outputDir || 'app-dist',\r\n app: rootDir,\r\n },\r\n npmRebuild: false,\r\n nodeGypRebuild: false,\r\n buildDependenciesFromSource: false,\r\n includeSubNodeModules: false,\r\n mac: {\r\n target: (builderConfig.mac?.target || ['dmg', 'zip']) as any,\r\n category: builderConfig.mac?.category || 'public.app-category.utilities',\r\n ...(hasMacIcon ? { icon: macIconPath } : {}),\r\n },\r\n win: {\r\n target: (builderConfig.win?.target || ['nsis', 'zip']) as any,\r\n ...(hasWinIcon ? { icon: winIconPath } : {}),\r\n },\r\n linux: {\r\n target: (builderConfig.linux?.target || ['AppImage', 'deb']) as any,\r\n category: builderConfig.linux?.category || 'Utility',\r\n ...(hasLinuxIcon ? { icon: linuxIconPath } : {}),\r\n },\r\n nsis: {\r\n oneClick: builderConfig.nsis?.oneClick ?? false,\r\n allowToChangeInstallationDirectory: builderConfig.nsis?.allowToChangeInstallationDirectory ?? true,\r\n },\r\n // 允许用户通过 extraConfig 覆盖配置\r\n ...(builderConfig.extraConfig || {}),\r\n files,\r\n }\r\n}\r\n","import { consola } from 'consola'\r\n\r\nexport const logger = consola.withTag('holix')\r\n\r\nexport function banner(msg: string) {\r\n logger.box(msg)\r\n}\r\n","import type { HolixConfig } from '@holix/config'\r\nimport type { UserConfig as ViteConfig } from 'vite'\r\nimport { createRequire } from 'node:module'\r\nimport { join } from 'node:path'\r\nimport { pathToFileURL } from 'node:url'\r\n\r\nexport { mergeConfig } from 'vite'\r\n\r\nexport async function resolveViteFromCwd(\r\n cwd: string,\r\n): Promise<typeof import('vite')> {\r\n const _require = createRequire(import.meta.url)\r\n let viteEntry: string\r\n\r\n try {\r\n viteEntry = _require.resolve('vite', {\r\n paths: [cwd],\r\n })\r\n }\r\n catch {\r\n throw new Error(\r\n `[holix] Cannot find \"vite\" in project: ${cwd}\\n`\r\n + `Please install it first: pnpm add -D vite`,\r\n )\r\n }\r\n\r\n try {\r\n // 优先走 ESM\r\n return await import(pathToFileURL(viteEntry).href)\r\n }\r\n catch (err: any) {\r\n // 仅在明确是 CJS 不兼容时 fallback\r\n if (\r\n err?.code === 'ERR_REQUIRE_ESM'\r\n || err?.message?.includes('Cannot use import statement')\r\n ) {\r\n return _require(viteEntry)\r\n }\r\n\r\n throw err\r\n }\r\n}\r\n\r\nexport async function resolveViteConfigFromHolixConfig(cwd: string, holixConfig: HolixConfig): Promise<ViteConfig> {\r\n const outdir = join(holixConfig.outDir || '.holix', 'client')\r\n\r\n const viteConfig: ViteConfig = {\r\n root: cwd,\r\n base: './',\r\n plugins: [\r\n ...(holixConfig.vitePlugins || []),\r\n ],\r\n resolve: {\r\n alias: holixConfig.alias || {},\r\n },\r\n build: {\r\n outDir: outdir,\r\n rollupOptions: {\r\n external: ['electron'],\r\n output: {\r\n // 可选:控制输出文件名\r\n entryFileNames: '[name].js',\r\n chunkFileNames: 'chunks/[name]-[hash].js',\r\n assetFileNames: 'assets/[name]-[hash][extname]',\r\n },\r\n },\r\n },\r\n }\r\n return viteConfig\r\n}\r\n","import type { HolixConfig } from '@holix/config'\r\nimport { resolveViteConfigFromHolixConfig, resolveViteFromCwd } from './resolve'\r\n\r\nexport async function buildVite(cwd: string, holixConfig: HolixConfig) {\r\n // 从用户项目的 node_modules 中解析 Vite\r\n const vite = await resolveViteFromCwd(cwd)\r\n\r\n // 创建 Vite 服务器配置\r\n const serverConfig = await resolveViteConfigFromHolixConfig(cwd, holixConfig)\r\n\r\n return vite.build(serverConfig)\r\n}\r\n","import { existsSync } from 'node:fs'\r\nimport { rm } from 'node:fs/promises'\r\nimport { platform } from 'node:os'\r\nimport { resolve } from 'node:path'\r\nimport process from 'node:process'\r\nimport { build } from '@holix/builder'\r\nimport { defineCommand } from 'citty'\r\nimport { build as electronBuild, Platform } from 'electron-builder'\r\nimport { loadHolixConfig } from '../config'\r\nimport { generateElectronBuilderConfig } from '../utils/electron-builder-config'\r\nimport { banner, logger } from '../utils/logger'\r\nimport { buildVite } from '../vite/build'\r\n\r\n/**\r\n * 获取当前平台对应的 electron-builder target\r\n */\r\nfunction getPlatformTarget(): 'mac' | 'win' | 'linux' {\r\n const currentPlatform = platform()\r\n switch (currentPlatform) {\r\n case 'darwin':\r\n return 'mac'\r\n case 'win32':\r\n return 'win'\r\n default:\r\n return 'linux'\r\n }\r\n}\r\n\r\nexport const runBuild = defineCommand({\r\n meta: {\r\n name: 'build',\r\n description: 'Build Holix application for production',\r\n },\r\n args: {\r\n clear: {\r\n type: 'boolean',\r\n description: 'clear output directory before build',\r\n default: true,\r\n },\r\n package: {\r\n type: 'boolean',\r\n description: 'package application with electron-builder after build',\r\n default: false,\r\n },\r\n target: {\r\n type: 'string',\r\n description: 'build target platform for packaging: mac, win, linux (default: current platform)',\r\n },\r\n publish: {\r\n type: 'string',\r\n description: 'publish options: never, onTag, onTagOrDraft, always',\r\n default: 'never',\r\n },\r\n },\r\n async run({ args }) {\r\n const rootDir = process.cwd()\r\n banner('🏗️ 构建 Holix 应用程序')\r\n\r\n logger.info('Root directory:', rootDir)\r\n if (args.clear) {\r\n logger.info('Clear output:', 'enabled')\r\n }\r\n\r\n try {\r\n const { config, packageJson } = await loadHolixConfig({\r\n cwd: rootDir,\r\n })\r\n\r\n logger.info('Building client and main processes...')\r\n\r\n await buildVite(rootDir, config)\r\n\r\n await build(config, packageJson, { clean: args.clear })\r\n\r\n logger.success('All builds completed successfully')\r\n\r\n // 如果启用了打包,使用 electron-builder 打包\r\n if (args.package) {\r\n logger.info('\\n📦 Packaging application with electron-builder...')\r\n\r\n const builderConfig = generateElectronBuilderConfig(rootDir, config, packageJson)\r\n const outputDir = resolve(rootDir, builderConfig.directories?.output || 'app-dist')\r\n\r\n // 清理之前的打包输出目录,避免文件占用问题\r\n if (existsSync(outputDir)) {\r\n logger.info('Cleaning previous build output...')\r\n try {\r\n await rm(outputDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 1000 })\r\n logger.success('Previous build output cleaned')\r\n }\r\n catch (cleanError) {\r\n logger.warn('Failed to clean previous build output:', cleanError)\r\n logger.warn('Continuing with build...')\r\n }\r\n }\r\n\r\n // logger.info('Electron builder config:', JSON.stringify(builderConfig, null, 2))\r\n\r\n // 确定打包目标\r\n const targetPlatform = args.target || getPlatformTarget()\r\n\r\n let targets\r\n switch (targetPlatform) {\r\n case 'mac':\r\n targets = Platform.MAC.createTarget()\r\n break\r\n case 'win':\r\n targets = Platform.WINDOWS.createTarget()\r\n break\r\n case 'linux':\r\n targets = Platform.LINUX.createTarget()\r\n break\r\n default:\r\n {\r\n logger.warn(`Unknown platform: ${targetPlatform}, using current platform`)\r\n const currentPlatform = getPlatformTarget()\r\n targets = currentPlatform === 'mac'\r\n ? Platform.MAC.createTarget()\r\n : currentPlatform === 'win'\r\n ? Platform.WINDOWS.createTarget()\r\n : Platform.LINUX.createTarget()\r\n }\r\n }\r\n\r\n // 执行打包\r\n const result = await electronBuild({\r\n targets,\r\n config: builderConfig,\r\n publish: args.publish as any,\r\n })\r\n\r\n logger.success('✅ Packaging completed successfully!')\r\n logger.info('Output directory:', outputDir)\r\n\r\n if (result && result.length > 0) {\r\n logger.success('\\nGenerated files:')\r\n result.forEach((file) => {\r\n logger.info(` - ${file}`)\r\n })\r\n }\r\n }\r\n }\r\n catch (error) {\r\n logger.error('Build failed:', error)\r\n throw error\r\n }\r\n },\r\n})\r\n","import type { HolixConfig } from '@holix/config/dist/index.mjs'\r\nimport { resolveViteConfigFromHolixConfig, resolveViteFromCwd } from './resolve'\r\n\r\n/**\r\n * 创建 Vite 开发服务器(不立即启动)\r\n *\r\n * @param options - Vite 开发服务器选项\r\n * @returns ViteDevServer 实例\r\n *\r\n * @example\r\n * ```ts\r\n * const server = await createViteDevServer({\r\n * cwd: '/path/to/project',\r\n * config: { root: './src' }\r\n * })\r\n *\r\n * // 手动启动\r\n * await server.listen()\r\n * server.printUrls()\r\n * ```\r\n */\r\nexport async function createViteDevServer(cwd: string, holixConfig: HolixConfig) {\r\n // 从用户项目的 node_modules 中解析 Vite\r\n const vite = await resolveViteFromCwd(cwd)\r\n\r\n // 创建 Vite 服务器配置\r\n const serverConfig = await resolveViteConfigFromHolixConfig(cwd, holixConfig)\r\n\r\n // 创建开发服务器(不启动)\r\n return vite.createServer(serverConfig)\r\n}\r\n","import { resolve } from 'node:path'\r\nimport process from 'node:process'\r\nimport { dev } from '@holix/builder'\r\nimport { startElectron } from '@holix/electron'\r\nimport { AsyncBatcher } from '@tanstack/pacer'\r\nimport { defineCommand } from 'citty'\r\nimport { debounce } from 'perfect-debounce'\r\nimport { loadHolixConfig } from '../config'\r\nimport { banner, logger } from '../utils/logger'\r\nimport { getElectronVersion } from '../utils/rebuild'\r\nimport { createViteDevServer } from '../vite/server'\r\n\r\nexport const runDev = defineCommand({\r\n meta: {\r\n name: 'dev',\r\n description: 'Start Holix development mode (with SSR + Electron hot reload)',\r\n },\r\n args: {\r\n open: {\r\n type: 'boolean',\r\n description: 'auto open Electron window',\r\n default: true,\r\n },\r\n clear: {\r\n type: 'boolean',\r\n description: 'clear output directory before build',\r\n default: true,\r\n },\r\n autoRestart: {\r\n type: 'boolean',\r\n description: 'automatically restart Electron on main process code changes',\r\n default: false,\r\n },\r\n // rebuild: {\r\n // type: 'boolean',\r\n // description: 'rebuild native modules for Electron',\r\n // default: true,\r\n // },\r\n },\r\n async run({ args }) {\r\n const rootDir = process.cwd()\r\n banner('🚀 启动 Holix 开发模式')\r\n\r\n logger.info('Root directory:', rootDir)\r\n logger.info('Auto open:', args.open)\r\n\r\n if (args.clear) {\r\n logger.info('Clear output:', 'enabled')\r\n }\r\n\r\n try {\r\n const { config, packageJson } = await loadHolixConfig({\r\n cwd: rootDir,\r\n })\r\n\r\n const viteServer = await createViteDevServer(rootDir, config)\r\n\r\n const port = config.port ?? 5183\r\n\r\n await viteServer.listen(port)\r\n\r\n logger.info('Building client and main processes...')\r\n\r\n // TODO: 重建 native 模块\r\n // if (args.rebuild) {\r\n // await import('../utils/rebuild').then(({ rebuildNativeModules }) =>\r\n // rebuildNativeModules(rootDir, packageJson),\r\n // )\r\n // logger.success('Native modules rebuilt successfully')\r\n // }\r\n // else {\r\n // logger.warn('Electron version not found in package.json, skipping native module rebuild.')\r\n // }\r\n\r\n const watcher = await dev(config, packageJson, { clean: args.clear })\r\n\r\n logger.success('✓ Client built')\r\n\r\n logger.success('All builds completed successfully')\r\n\r\n if (!packageJson.main) {\r\n logger.warn('No main entry found in package.json, skipping Electron start.')\r\n viteServer.printUrls()\r\n return\r\n }\r\n\r\n // 如果启用 open,启动 Electron 进程\r\n if (args.open && packageJson.main) {\r\n const mainEntry = resolve(rootDir, packageJson.main!)\r\n logger.info('Starting Electron...')\r\n\r\n const electronProcess = await startElectron({\r\n entry: mainEntry,\r\n cwd: rootDir,\r\n env: {\r\n NODE_ENV: 'development',\r\n },\r\n enableIpc: true, // 启用 IPC 通信\r\n })\r\n\r\n logger.success('Electron started')\r\n\r\n viteServer.printUrls()\r\n\r\n let isRestarting = false\r\n\r\n const onExit = debounce((code: number | null) => {\r\n logger.info('Electron process exited with code', code)\r\n watcher.close()\r\n process.exit(code ?? 0)\r\n }, 100)\r\n\r\n // 注册 IPC 处理器:子进程请求重启\r\n electronProcess.handleIpc('process:restart', async () => {\r\n logger.info('Electron process requested restart...')\r\n if (isRestarting) {\r\n return { success: false, reason: 'already restarting' }\r\n }\r\n isRestarting = true\r\n electronProcess.off('exit', onExit)\r\n await electronProcess.restart()\r\n electronProcess.on('exit', onExit)\r\n isRestarting = false\r\n return { success: true }\r\n })\r\n\r\n const notifyFileChange = debounce(async (event: string[], change: any) => {\r\n logger.info(`File ${change.event} detected: ${event}`)\r\n // 发送文件变更通知到子进程,而不是重启\r\n electronProcess.sendIpc('file:changed', {\r\n path: event,\r\n event: change.event,\r\n timestamp: Date.now(),\r\n })\r\n }, 100)\r\n\r\n const batcher = new AsyncBatcher<string>(\r\n async (items) => {\r\n notifyFileChange(items, { event: 'change' })\r\n },\r\n {\r\n maxSize: 100,\r\n wait: 100,\r\n onError: (error, batch) => {\r\n logger.error('Failed to send update batch:', error, batch)\r\n },\r\n asyncRetryerOptions: {\r\n maxAttempts: 3,\r\n backoff: 'exponential',\r\n baseWait: 1000,\r\n jitter: 0.3,\r\n },\r\n },\r\n )\r\n\r\n if (args.autoRestart) {\r\n watcher.on('change', async (event, _) => {\r\n batcher.addItem(event)\r\n })\r\n }\r\n else {\r\n watcher.close()\r\n }\r\n\r\n electronProcess.on('exit', onExit)\r\n }\r\n else {\r\n watcher.close()\r\n }\r\n }\r\n catch (error) {\r\n logger.error('Build failed:', error)\r\n throw error\r\n }\r\n },\r\n})\r\n","#!/usr/bin/env node\r\nimport { defineCommand, runMain } from 'citty'\r\nimport { runBuild } from './commands/build'\r\nimport { runDev } from './commands/dev'\r\n\r\nconst main = defineCommand({\r\n meta: {\r\n name: 'holix',\r\n version: '0.1.0',\r\n description: 'Holix Application Framework CLI - Build desktop apps with Vue SSR + Electron',\r\n },\r\n args: {\r\n clear: {\r\n type: 'boolean',\r\n description: 'clear output directory before build',\r\n default: true,\r\n },\r\n },\r\n subCommands: {\r\n dev: runDev,\r\n build: runBuild,\r\n },\r\n})\r\n\r\nrunMain(main)\r\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@holix/cli",
3
3
  "type": "module",
4
- "version": "0.3.0",
4
+ "version": "1.0.1",
5
5
  "private": false,
6
6
  "description": "Holix Application Framework CLI",
7
7
  "author": "zhaogongchengsi <zzhanya648@gmail.com>",
@@ -46,19 +46,24 @@
46
46
  "dist"
47
47
  ],
48
48
  "dependencies": {
49
+ "@tanstack/pacer": "^0.17.0",
49
50
  "c12": "^3.3.1",
50
51
  "chokidar": "^4.0.3",
51
52
  "citty": "^0.1.6",
52
53
  "consola": "^3.4.2",
54
+ "electron-builder": "^25.1.8",
55
+ "electron-rebuild": "^3.2.9",
53
56
  "pathe": "^2.0.3",
54
57
  "perfect-debounce": "^2.0.0",
55
58
  "pkg-types": "^1.3.1",
56
- "@holix/builder": "0.3.0",
57
- "@holix/electron": "0.4.0",
58
- "@holix/config": "0.2.0"
59
+ "semver": "^7.7.3",
60
+ "@holix/builder": "1.0.1",
61
+ "@holix/electron": "1.0.0",
62
+ "@holix/config": "1.0.0"
59
63
  },
60
64
  "devDependencies": {
61
65
  "@types/node": "^24.9.1",
66
+ "@types/semver": "^7.7.1",
62
67
  "typescript": "^5.9.3"
63
68
  },
64
69
  "scripts": {