@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 +200 -14
- package/dist/index.mjs +200 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -4
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: {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
179
|
-
logger.info("
|
|
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
|
-
|
|
350
|
+
const notifyFileChange = (0, perfect_debounce.debounce)(async (event, change) => {
|
|
188
351
|
logger.info(`File ${change.event} detected: ${event}`);
|
|
189
|
-
|
|
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: {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
178
|
-
logger.info("
|
|
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
|
-
|
|
349
|
+
const notifyFileChange = debounce(async (event, change) => {
|
|
187
350
|
logger.info(`File ${change.event} detected: ${event}`);
|
|
188
|
-
|
|
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) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":"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"}
|
|
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.
|
|
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
|
-
"
|
|
57
|
-
"@holix/
|
|
58
|
-
"@holix/
|
|
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": {
|