@cordy/electro-cli 1.2.19 → 1.2.20

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.
Files changed (2) hide show
  1. package/dist/index.mjs +102 -62
  2. package/package.json +8 -7
package/dist/index.mjs CHANGED
@@ -491,7 +491,36 @@ const cac = (name = "") => new CAC(name);
491
491
 
492
492
  //#endregion
493
493
  //#region package.json
494
- var version$1 = "1.2.19";
494
+ var version$1 = "1.2.20";
495
+
496
+ //#endregion
497
+ //#region src/dev/bridge-types.ts
498
+ const GENERATED_BRIDGE_DIRS = ["views", "windows"];
499
+ const VIEW_BRIDGE_MODULE_FILE = "bridge.gen.ts";
500
+ /**
501
+ * Resolve generated bridge declaration file for a view.
502
+ * Supports both historical `generated/windows/*` and current `generated/views/*`.
503
+ */
504
+ function findBridgeTypesForView(files, viewName) {
505
+ const byPath = files.find((f) => f.path === `generated/views/${viewName}.bridge.d.ts`) ?? files.find((f) => f.path === `generated/windows/${viewName}.bridge.d.ts`);
506
+ if (byPath) return byPath;
507
+ return files.find((f) => f.path.endsWith(`/${viewName}.bridge.d.ts`)) ?? null;
508
+ }
509
+ /** Target location for per-view bridge types next to the config file. */
510
+ function resolveViewBridgePath(view) {
511
+ if (!view.__source) return null;
512
+ return resolve(dirname(view.__source), VIEW_BRIDGE_MODULE_FILE);
513
+ }
514
+ /** Convert generated bridge declaration content into runtime-accessible bridge module. */
515
+ function createViewBridgeModuleContent(bridgeTypesContent) {
516
+ return `${bridgeTypesContent.trimEnd()}\n\nexport const electro = window.electro as ElectroBridge;\n`;
517
+ }
518
+ function isGeneratedBridgeTypesPath(path) {
519
+ return GENERATED_BRIDGE_DIRS.some((dir) => path.startsWith(`generated/${dir}/`) && path.endsWith(".bridge.d.ts"));
520
+ }
521
+ function generatedBridgeTypesPaths(viewName) {
522
+ return GENERATED_BRIDGE_DIRS.map((dir) => `generated/${dir}/${viewName}.bridge.d.ts`);
523
+ }
495
524
 
496
525
  //#endregion
497
526
  //#region src/dev/logger.ts
@@ -587,29 +616,47 @@ function footer(message, url) {
587
616
  function toProjectRelative(root, absolutePath) {
588
617
  return relative(root, absolutePath) || ".";
589
618
  }
590
- function session(meta) {
619
+ function logSession(meta) {
591
620
  if (levels[currentLevel] > levels.info) return;
592
621
  const isBuild = meta.mode === "build";
593
622
  const projectName = basename(meta.root);
594
- const mainEntry = toProjectRelative(meta.root, meta.main);
623
+ const runtimeEntry = toProjectRelative(meta.root, meta.runtime);
595
624
  const preloadEntry = meta.preload ? toProjectRelative(meta.root, meta.preload) : `${dim$1}(none)${reset$1}`;
596
- const rendererEntry = meta.renderer ? toProjectRelative(meta.root, meta.renderer) : `${dim$1}(none)${reset$1}`;
625
+ const firstView = meta.views?.[0] ?? null;
626
+ const viewEntry = firstView ? toProjectRelative(meta.root, firstView.entry) : `${dim$1}(none)${reset$1}`;
597
627
  const command = isBuild ? "build" : "dev";
598
628
  console.log(`\n${bold}${yellow$1}⚡ electro ${command}${reset$1} → ${cyan}${projectName}${reset$1}\n`);
599
- const mainMode = isBuild ? "build" : "watch";
629
+ const runtimeMode = isBuild ? "build" : "watch";
600
630
  const preloadMode = isBuild ? "build" : "watch";
601
- const rendererMode = isBuild ? "build" : "dev server";
602
- const entryWidth = Math.max(14, mainEntry.length, preloadEntry.length, rendererEntry.length) + 2;
603
- console.log(` ${dim$1}Scope ${"Entry".padEnd(entryWidth)}Mode${reset$1}`);
604
- console.log(` ${cyan}main${reset$1} ${mainEntry.padEnd(entryWidth)}${dim$1}${mainMode}${reset$1}`);
605
- console.log(` ${yellow$1}preload${reset$1} ${preloadEntry.padEnd(entryWidth)}${dim$1}${preloadMode}${reset$1}`);
606
- console.log(` ${green}renderer${reset$1} ${rendererEntry.padEnd(entryWidth)}${dim$1}${rendererMode}${reset$1}`);
607
- if (meta.windows && meta.windows.length > 0) {
631
+ const viewsMode = isBuild ? "build" : "dev server";
632
+ const rows = [
633
+ {
634
+ scope: `${cyan}runtime${reset$1}`,
635
+ entry: runtimeEntry,
636
+ mode: `${dim$1}${runtimeMode}${reset$1}`
637
+ },
638
+ {
639
+ scope: `${yellow$1}preload${reset$1}`,
640
+ entry: preloadEntry,
641
+ mode: `${dim$1}${preloadMode}${reset$1}`
642
+ },
643
+ {
644
+ scope: `${green}view${reset$1}`,
645
+ entry: viewEntry,
646
+ mode: `${dim$1}${viewsMode}${reset$1}`
647
+ }
648
+ ];
649
+ const scopeWidth = Math.max(5, ...rows.map((r) => visibleLength(r.scope))) + 2;
650
+ const entryWidth = Math.max(5, ...rows.map((r) => visibleLength(r.entry))) + 2;
651
+ console.log(` ${dim$1}${padVisible("Scope", scopeWidth)}${padVisible("Entry", entryWidth)}Mode${reset$1}`);
652
+ for (const row of rows) console.log(` ${padVisible(row.scope, scopeWidth)}${padVisible(row.entry, entryWidth)}${row.mode}`);
653
+ if (meta.views && meta.views.length > 0) {
608
654
  console.log("");
609
- console.log(` ${dim$1}Windows${reset$1} ${meta.windows.length} configured`);
610
- for (const win of meta.windows) {
611
- const winEntry = toProjectRelative(meta.root, win.entry);
612
- console.log(` ${win.name.padEnd(10)} ${dim$1}${winEntry}${reset$1}`);
655
+ console.log(` ${dim$1}Views${reset$1} ${meta.views.length} configured`);
656
+ const viewNameWidth = Math.max(4, ...meta.views.map((v) => v.name.length)) + 2;
657
+ for (const view of meta.views) {
658
+ const entry = toProjectRelative(meta.root, view.entry);
659
+ console.log(` ${padVisible(view.name, viewNameWidth)}${dim$1}${entry}${reset$1}`);
613
660
  }
614
661
  }
615
662
  console.log("");
@@ -619,6 +666,13 @@ const VITE_TAG_RE = new RegExp(String.raw`(?:\x1b\[[0-9;]*m)*\[(vite(?:-plugin-[
619
666
  function retagMessage(msg) {
620
667
  return msg.replace(VITE_TAG_RE, `[${bold}${yellow$1}electro${reset$1}]`);
621
668
  }
669
+ function visibleLength(value) {
670
+ return value.replace(ANSI_RE, "").length;
671
+ }
672
+ function padVisible(value, width) {
673
+ const len = visibleLength(value);
674
+ return value + " ".repeat(Math.max(0, width - len));
675
+ }
622
676
  /**
623
677
  * Patch a Vite logger to rebrand `[vite]` → `[electro]`,
624
678
  * suppress startup noise ("ready in", "➜"), and extract
@@ -788,6 +842,10 @@ async function loadConfig(configPath) {
788
842
  const config = (await import(absolutePath)).default;
789
843
  if (!config) throw new Error(`${configPath} must have a default export`);
790
844
  if (!config.runtime) throw new Error(`${configPath} must define a runtime via defineRuntime()`);
845
+ if (!config.codegen || !config.codegen?.scanDir) config.codegen = { scanDir: resolve(root, "src") };
846
+ if (config.views && config.views?.length > 0) {
847
+ for (const view of config.views) if (!view.entry) view.entry = "./index.html";
848
+ }
791
849
  validateConfig(config);
792
850
  return {
793
851
  config,
@@ -2145,10 +2203,7 @@ function resolveSourcemap(mode) {
2145
2203
  }
2146
2204
  function createRendererConfig(opts) {
2147
2205
  const input = {};
2148
- for (const view of opts.views) {
2149
- const sourceDir = dirname(view.__source);
2150
- input[view.name] = resolve(sourceDir, view.entry);
2151
- }
2206
+ for (const view of opts.views) input[view.name] = resolve(view.root, view.entry);
2152
2207
  const isBuild = !!opts.outDir;
2153
2208
  const config = {
2154
2209
  configFile: false,
@@ -2201,35 +2256,6 @@ function deduplicatePlugins(plugins) {
2201
2256
  return result;
2202
2257
  }
2203
2258
 
2204
- //#endregion
2205
- //#region src/dev/bridge-types.ts
2206
- const GENERATED_BRIDGE_DIRS = ["views", "windows"];
2207
- const VIEW_BRIDGE_MODULE_FILE = "bridge.gen.ts";
2208
- /**
2209
- * Resolve generated bridge declaration file for a view.
2210
- * Supports both historical `generated/windows/*` and current `generated/views/*`.
2211
- */
2212
- function findBridgeTypesForView(files, viewName) {
2213
- const byPath = files.find((f) => f.path === `generated/views/${viewName}.bridge.d.ts`) ?? files.find((f) => f.path === `generated/windows/${viewName}.bridge.d.ts`);
2214
- if (byPath) return byPath;
2215
- return files.find((f) => f.path.endsWith(`/${viewName}.bridge.d.ts`)) ?? null;
2216
- }
2217
- /** Target location for per-view bridge types next to the config file. */
2218
- function resolveViewBridgePath(view) {
2219
- if (!view.__source) return null;
2220
- return resolve(dirname(view.__source), VIEW_BRIDGE_MODULE_FILE);
2221
- }
2222
- /** Convert generated bridge declaration content into runtime-accessible bridge module. */
2223
- function createViewBridgeModuleContent(bridgeTypesContent) {
2224
- return `${bridgeTypesContent.trimEnd()}\n\nexport const electro = window.electro as ElectroBridge;\n`;
2225
- }
2226
- function isGeneratedBridgeTypesPath(path) {
2227
- return GENERATED_BRIDGE_DIRS.some((dir) => path.startsWith(`generated/${dir}/`) && path.endsWith(".bridge.d.ts"));
2228
- }
2229
- function generatedBridgeTypesPaths(viewName) {
2230
- return GENERATED_BRIDGE_DIRS.map((dir) => `generated/${dir}/${viewName}.bridge.d.ts`);
2231
- }
2232
-
2233
2259
  //#endregion
2234
2260
  //#region src/plugins/utils.ts
2235
2261
  /** Strip query and hash from a URL/path. */
@@ -2312,7 +2338,7 @@ async function findElectronBin(root) {
2312
2338
  const electronDir = resolve(root, "node_modules/electron");
2313
2339
  const pathTxtPath = resolve(electronDir, "path.txt");
2314
2340
  if (await fileExists(pathTxtPath)) {
2315
- const resolved = resolve(electronDir, (await readFile(pathTxtPath, "utf-8")).trim());
2341
+ const resolved = resolve(electronDir, "dist", (await readFile(pathTxtPath, "utf-8")).trim());
2316
2342
  if (await fileExists(resolved)) return resolved;
2317
2343
  }
2318
2344
  } catch {}
@@ -2919,9 +2945,9 @@ async function build$1(options) {
2919
2945
  const views = config.views ?? [];
2920
2946
  const rendererViews = views.filter((v) => v.entry);
2921
2947
  const srcDir = resolve(root, "src");
2922
- session({
2948
+ logSession({
2923
2949
  root,
2924
- main: resolve(dirname(config.runtime.__source), config.runtime.entry),
2950
+ runtime: resolve(dirname(config.runtime.__source), config.runtime.entry),
2925
2951
  preload: rendererViews.length > 0 ? resolve(codegenDir, "generated/preload") : null,
2926
2952
  renderer: rendererViews.length > 0 ? resolve(root, dirname(relative(root, rendererViews[0].__source))) : null,
2927
2953
  mode: "build",
@@ -3210,24 +3236,26 @@ var DevServer = class {
3210
3236
  this.outputDir = this.outDirOverride ? resolve(this.root, this.outDirOverride) : resolve(this.root, ".electro");
3211
3237
  this.nodeFormat = await resolveNodeOutputFormat(this.root);
3212
3238
  this.configPaths.add(loaded.configPath);
3213
- for (const view of this.config.views ?? []) this.configPaths.add(view.__source);
3239
+ for (const view of this.config.views ?? []) {
3240
+ view.root = dirname(view.__source);
3241
+ this.configPaths.add(view.__source);
3242
+ }
3214
3243
  const views = this.config.views ?? [];
3215
3244
  const rendererViews = views.filter((v) => v.entry);
3216
- const srcDir = resolve(this.root, "src");
3217
- const mainEntry = resolve(dirname(this.config.runtime.__source), this.config.runtime.entry);
3218
- session({
3245
+ const runtimeEntry = resolve(dirname(this.config.runtime.__source), this.config.runtime.entry);
3246
+ logSession({
3219
3247
  root: this.root,
3220
- main: mainEntry,
3248
+ runtime: runtimeEntry,
3221
3249
  preload: rendererViews.length > 0 ? resolve(this.outputDir, "generated/preload") : null,
3222
- renderer: rendererViews.length > 0 ? resolve(this.root, dirname(relative(this.root, rendererViews[0].__source))) : null,
3223
- windows: rendererViews.map((w) => ({
3250
+ views: rendererViews.map((w) => ({
3224
3251
  name: w.name,
3225
- entry: resolve(dirname(w.__source), w.entry)
3252
+ root: w.root,
3253
+ entry: resolve(w.root, w.entry)
3226
3254
  }))
3227
3255
  });
3228
3256
  const codegenTimer = startTimer();
3229
3257
  try {
3230
- await this.runCodegen(this.outputDir, srcDir);
3258
+ await this.runCodegen(this.outputDir, this.config.codegen.scanDir);
3231
3259
  step("codegen", codegenTimer());
3232
3260
  } catch (err) {
3233
3261
  stepFail("codegen", err instanceof Error ? err.message : String(err));
@@ -3667,7 +3695,19 @@ function sanitizeRuntimeWebPreferences(webPreferences) {
3667
3695
  //#endregion
3668
3696
  //#region src/commands/dev.ts
3669
3697
  async function dev(options) {
3698
+ if (options.remoteDebuggingPort) process.env.REMOTE_DEBUGGING_PORT = options.remoteDebuggingPort;
3699
+ if (options.inspect) {
3700
+ const port = typeof options.inspect === "number" ? options.inspect : 9229;
3701
+ process.env.NODE_OPTIONS = `--inspect=${port}`;
3702
+ }
3703
+ if (options.inspectBrk) {
3704
+ const port = typeof options.inspectBrk === "number" ? options.inspectBrk : 9229;
3705
+ process.env.NODE_OPTIONS = `--inspect-brk=${port}`;
3706
+ }
3707
+ if (options.noSandbox) process.env.NO_SANDBOX = "1";
3708
+ if (options["--"]) process.env.ELECTRON_CLI_ARGS = JSON.stringify(options["--"]);
3670
3709
  if (options.sourcemap) validateSourcemap(options.sourcemap);
3710
+ process.env.ELECTRO_MODE = "development";
3671
3711
  const createServer = () => new DevServer(options.config, {
3672
3712
  logLevel: options.logLevel,
3673
3713
  clearScreen: options.clearScreen,
@@ -3798,7 +3838,7 @@ const cli = cac("electro");
3798
3838
  cli.command("generate", "Generate preload scripts, bridge types, and context types").option("-c, --config <path>", "Path to electro.config.ts", { default: "electro.config.ts" }).option("-o, --output <dir>", "Output directory", { default: ".electro" }).action(generate$1);
3799
3839
  cli.command("build", "Build for production").option("-c, --config <path>", "Path to electro.config.ts", { default: "electro.config.ts" }).option("-o, --outDir <dir>", "Output directory", { default: "dist" }).option("--sourcemap <mode>", "Sourcemap mode (linked | inline | external | none)").option("--minify", "Minify output (default: true)", { default: true }).option("--no-minify", "Disable minification").option("--bytecode", "Compile main/preload to V8 bytecode for source protection").option("-l, --logLevel <level>", "Log level (info | warn | error | silent)").action(build$1);
3800
3840
  cli.command("preview", "Build and preview in Electron").option("-c, --config <path>", "Path to electro.config.ts", { default: "electro.config.ts" }).option("-o, --outDir <dir>", "Output directory", { default: "dist" }).option("--sourcemap <mode>", "Sourcemap mode (linked | inline | external | none)").option("--minify", "Minify output (default: true)", { default: true }).option("--no-minify", "Disable minification").option("--bytecode", "Compile main/preload to V8 bytecode for source protection").option("--skip-build", "Skip build step and launch from existing output").option("-l, --logLevel <level>", "Log level (info | warn | error | silent)").action(preview);
3801
- cli.command("dev", "Start development server with Electron").option("-c, --config <path>", "Path to electro.config.ts", { default: "electro.config.ts" }).option("--clearScreen", "Clear screen on rebuild", { default: true }).option("-l, --logLevel <level>", "Log level (info | warn | error | silent)").option("--renderer-only", "Start only the renderer dev server (no Electron)").option("--sourcemap <mode>", "Sourcemap mode (linked | inline | external | none)").option("--outDir <dir>", "Output directory override (default: .electro)").action(dev);
3841
+ cli.command("dev", "Start development server with Electron").option("--config <path>", "Path to electro.config.ts", { default: "electro.config.ts" }).option("--clearScreen", "Clear screen on rebuild", { default: true }).option("--logLevel <level>", "Log level (info | warn | error | silent)").option("--sourcemap <mode>", "Sourcemap mode (linked | inline | external | none)").option("--outDir <dir>", "Output directory override (default: .electro)").option("--inspect [port]", `[boolean | number] enable V8 inspector on the specified port`).option("--inspectBrk [port]", `[boolean | number] enable V8 inspector on the specified port`).option("--remoteDebuggingPort <port>", `[string] port for remote debugging`).option("--noSandbox", `[boolean] forces renderer process to run un-sandboxed`).option("--rendererOnly", `[boolean] only dev server for the renderer`).action(dev);
3802
3842
  cli.help();
3803
3843
  cli.version(version$1);
3804
3844
  cli.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cordy/electro-cli",
3
- "version": "1.2.19",
3
+ "version": "1.2.20",
4
4
  "description": "CLI for @cordy/electro — dev server, build, and code generation commands",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,10 +30,11 @@
30
30
  "main": "./dist/index.mjs",
31
31
  "types": "./dist/index.d.mts",
32
32
  "files": [
33
+ "bin",
33
34
  "dist"
34
35
  ],
35
36
  "bin": {
36
- "electro": "./dist/index.mjs"
37
+ "electro": "bin/cli.js"
37
38
  },
38
39
  "exports": {
39
40
  ".": {
@@ -48,19 +49,19 @@
48
49
  },
49
50
  "peerDependencies": {
50
51
  "@cordy/electro": "1.2.19",
51
- "electron": ">=40.4.1",
52
+ "electron": ">=40.6.0",
52
53
  "vite": ">=8.0.0"
53
54
  },
54
55
  "dependencies": {
55
56
  "@cordy/electro-generator": "1.2.19"
56
57
  },
57
58
  "devDependencies": {
58
- "@cordy/electro": "1.2.19",
59
- "@types/node": "^25.2.3",
59
+ "@cordy/electro": "1.2.20",
60
+ "@types/node": "^25.3.0",
60
61
  "cac": "^6.7.14",
61
- "electron": "^40.4.1",
62
+ "electron": "^40.6.0",
62
63
  "magic-string": "^0.30.21",
63
64
  "tsdown": "^0.20.3",
64
- "vite": "^8.0.0-beta.14"
65
+ "vite": "^8.0.0-beta.15"
65
66
  }
66
67
  }