@cordy/electro-cli 1.0.9 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +74 -70
  2. package/package.json +4 -4
package/dist/index.mjs CHANGED
@@ -490,7 +490,7 @@ const cac = (name = "") => new CAC(name);
490
490
 
491
491
  //#endregion
492
492
  //#region package.json
493
- var version$1 = "1.0.9";
493
+ var version$1 = "1.1.1";
494
494
 
495
495
  //#endregion
496
496
  //#region src/dev/logger.ts
@@ -714,23 +714,23 @@ function validateConfig(config) {
714
714
  error(`Main entry not found: ${mainEntry}`);
715
715
  process.exit(1);
716
716
  }
717
- const windows = config.windows ?? [];
717
+ const views = config.views ?? [];
718
718
  const names = /* @__PURE__ */ new Set();
719
- for (const win of windows) {
720
- if (names.has(win.name)) {
721
- error(`Duplicate window name "${win.name}". Window names must be unique.`);
719
+ for (const view of views) {
720
+ if (names.has(view.name)) {
721
+ error(`Duplicate view name "${view.name}". View names must be unique.`);
722
722
  process.exit(1);
723
723
  }
724
- names.add(win.name);
724
+ names.add(view.name);
725
725
  }
726
- for (const win of windows) {
727
- const winEntry = resolve(dirname(win.__source), win.entry);
728
- if (!existsSync(winEntry)) {
729
- error(`Window "${win.name}" entry not found: ${winEntry}`);
726
+ for (const view of views) {
727
+ const viewEntry = resolve(dirname(view.__source), view.entry);
728
+ if (!existsSync(viewEntry)) {
729
+ error(`View "${view.name}" entry not found: ${viewEntry}`);
730
730
  process.exit(1);
731
731
  }
732
732
  }
733
- for (const win of windows) if (win.features && win.features.length === 0) warn(`Window "${win.name}" has an empty features array — it won't have access to any services.`);
733
+ for (const view of views) if (view.features && view.features.length === 0) warn(`View "${view.name}" has an empty features array — it won't have access to any services.`);
734
734
  }
735
735
  /** Validate --sourcemap CLI value. Warns on unrecognized values. */
736
736
  function validateSourcemap(value) {
@@ -905,9 +905,9 @@ function resolveSourcemap(mode) {
905
905
  }
906
906
  function createRendererConfig(opts) {
907
907
  const input = {};
908
- for (const win of opts.windows) {
909
- const sourceDir = dirname(win.__source);
910
- input[win.name] = resolve(sourceDir, win.entry);
908
+ for (const view of opts.views) {
909
+ const sourceDir = dirname(view.__source);
910
+ input[view.name] = resolve(sourceDir, view.entry);
911
911
  }
912
912
  const isBuild = !!opts.outDir;
913
913
  const config = {
@@ -934,10 +934,32 @@ function createRendererConfig(opts) {
934
934
  if (opts.userViteConfigs?.length) {
935
935
  let merged = config;
936
936
  for (const userConfig of opts.userViteConfigs) merged = mergeConfig(merged, userConfig);
937
+ merged.plugins = deduplicatePlugins(merged.plugins);
937
938
  return merged;
938
939
  }
939
940
  return config;
940
941
  }
942
+ /**
943
+ * Deduplicate plugins by name — keeps the first occurrence of each named plugin.
944
+ * This allows multiple views to declare the same plugins (e.g. react()) without
945
+ * causing duplicate injection errors when configs are merged.
946
+ */
947
+ function deduplicatePlugins(plugins) {
948
+ if (!plugins) return [];
949
+ const seen = /* @__PURE__ */ new Set();
950
+ const result = [];
951
+ for (const plugin of plugins.flat(Infinity)) {
952
+ const name = plugin?.name;
953
+ if (!name) {
954
+ result.push(plugin);
955
+ continue;
956
+ }
957
+ if (seen.has(name)) continue;
958
+ seen.add(name);
959
+ result.push(plugin);
960
+ }
961
+ return result;
962
+ }
941
963
 
942
964
  //#endregion
943
965
  //#region ../../node_modules/.bun/@jridgewell+sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
@@ -2636,15 +2658,15 @@ async function build$1(options) {
2636
2658
  const root = loaded.root;
2637
2659
  const outDir = resolve(root, options.outDir);
2638
2660
  const codegenDir = resolve(root, ".electro");
2639
- const windows = config.windows ?? [];
2661
+ const views = config.views ?? [];
2640
2662
  const srcDir = resolve(root, "src");
2641
2663
  session({
2642
2664
  root,
2643
2665
  main: resolve(dirname(config.runtime.__source), config.runtime.entry),
2644
- preload: windows.length > 0 ? resolve(codegenDir, "generated/preload") : null,
2645
- renderer: windows.length > 0 ? resolve(root, dirname(relative(root, windows[0].__source))) : null,
2666
+ preload: views.length > 0 ? resolve(codegenDir, "generated/preload") : null,
2667
+ renderer: views.length > 0 ? resolve(root, dirname(relative(root, views[0].__source))) : null,
2646
2668
  mode: "build",
2647
- windows: windows.map((w) => ({
2669
+ windows: views.map((w) => ({
2648
2670
  name: w.name,
2649
2671
  entry: resolve(dirname(w.__source), w.entry)
2650
2672
  }))
@@ -2653,7 +2675,7 @@ async function build$1(options) {
2653
2675
  try {
2654
2676
  const { files, envTypes } = generate({
2655
2677
  scanResult: await scan(srcDir),
2656
- windows,
2678
+ views,
2657
2679
  outputDir: codegenDir,
2658
2680
  srcDir
2659
2681
  });
@@ -2688,7 +2710,7 @@ async function build$1(options) {
2688
2710
  stepFail("main", err instanceof Error ? err.message : String(err));
2689
2711
  process.exit(1);
2690
2712
  }
2691
- if (windows.length > 0) try {
2713
+ if (views.length > 0) try {
2692
2714
  buildScope("preload");
2693
2715
  await buildPreload({
2694
2716
  config,
@@ -2704,12 +2726,12 @@ async function build$1(options) {
2704
2726
  stepFail("preload", err instanceof Error ? err.message : String(err));
2705
2727
  process.exit(1);
2706
2728
  }
2707
- if (windows.length > 0) try {
2729
+ if (views.length > 0) try {
2708
2730
  buildScope("renderer");
2709
- const userViteConfigs = windows.filter((w) => w.vite).map((w) => w.vite);
2731
+ const userViteConfigs = views.filter((w) => w.vite).map((w) => w.vite);
2710
2732
  await build(createRendererConfig({
2711
2733
  root,
2712
- windows,
2734
+ views,
2713
2735
  userViteConfigs: userViteConfigs.length > 0 ? userViteConfigs : void 0,
2714
2736
  logLevel: "info",
2715
2737
  customLogger: logger,
@@ -2717,7 +2739,7 @@ async function build$1(options) {
2717
2739
  minify: options.minify,
2718
2740
  sourcemap: options.sourcemap
2719
2741
  }));
2720
- await flattenRendererOutput(resolve(outDir, "renderer"), windows, root);
2742
+ await flattenRendererOutput(resolve(outDir, "renderer"), views, root);
2721
2743
  } catch (err) {
2722
2744
  stepFail("renderer", err instanceof Error ? err.message : String(err));
2723
2745
  process.exit(1);
@@ -2727,14 +2749,6 @@ async function build$1(options) {
2727
2749
  async function buildMain(args) {
2728
2750
  const runtimeEntry = args.config.runtime.entry;
2729
2751
  const entry = resolve(dirname(args.config.runtime.__source), runtimeEntry);
2730
- const windowDefs = (args.config.windows ?? []).map((w) => ({
2731
- name: w.name,
2732
- type: w.type,
2733
- lifecycle: w.lifecycle,
2734
- autoShow: w.autoShow,
2735
- behavior: w.behavior,
2736
- window: w.window
2737
- }));
2738
2752
  await build(createNodeConfig({
2739
2753
  scope: "main",
2740
2754
  root: args.root,
@@ -2751,14 +2765,13 @@ async function buildMain(args) {
2751
2765
  userViteConfig: args.config.runtime.vite,
2752
2766
  sourcemap: args.sourcemap,
2753
2767
  customLogger: args.logger,
2754
- logLevel: "info",
2755
- define: { __ELECTRO_WINDOW_DEFINITIONS__: JSON.stringify(windowDefs) }
2768
+ logLevel: "info"
2756
2769
  }));
2757
2770
  }
2758
2771
  async function buildPreload(args) {
2759
- const windows = args.config.windows ?? [];
2772
+ const views = args.config.views ?? [];
2760
2773
  const input = {};
2761
- for (const win of windows) input[win.name] = resolve(args.codegenDir, `generated/preload/${win.name}.gen.ts`);
2774
+ for (const view of views) input[view.name] = resolve(args.codegenDir, `generated/preload/${view.name}.gen.ts`);
2762
2775
  const firstEntry = Object.values(input)[0];
2763
2776
  const preloadOutDir = resolve(args.outDir, "preload");
2764
2777
  const preloadPlugins = [
@@ -2809,12 +2822,12 @@ async function buildPreload(args) {
2809
2822
  * (e.g., `src/windows/main/index.html`) to `{name}/index.html`.
2810
2823
  * Adjusts relative asset references to match the new depth.
2811
2824
  */
2812
- async function flattenRendererOutput(rendererDir, windows, root) {
2825
+ async function flattenRendererOutput(rendererDir, views, root) {
2813
2826
  const dirsToClean = /* @__PURE__ */ new Set();
2814
- for (const win of windows) {
2815
- const relPath = relative(root, resolve(dirname(win.__source), win.entry));
2827
+ for (const view of views) {
2828
+ const relPath = relative(root, resolve(dirname(view.__source), view.entry));
2816
2829
  const oldHtmlPath = resolve(rendererDir, relPath);
2817
- const newHtmlPath = resolve(rendererDir, win.name, "index.html");
2830
+ const newHtmlPath = resolve(rendererDir, view.name, "index.html");
2818
2831
  if (oldHtmlPath === newHtmlPath) continue;
2819
2832
  let html = await readFile(oldHtmlPath, "utf-8");
2820
2833
  const depthDiff = relPath.split("/").length - 1 - 1;
@@ -2827,7 +2840,7 @@ async function flattenRendererOutput(rendererDir, windows, root) {
2827
2840
  await writeFile(newHtmlPath, html);
2828
2841
  await unlink(oldHtmlPath);
2829
2842
  const topDir = relPath.split("/")[0];
2830
- if (topDir !== win.name) dirsToClean.add(resolve(rendererDir, topDir));
2843
+ if (topDir !== view.name) dirsToClean.add(resolve(rendererDir, topDir));
2831
2844
  }
2832
2845
  for (const dir of dirsToClean) await rm(dir, {
2833
2846
  recursive: true,
@@ -2885,16 +2898,16 @@ var DevServer = class {
2885
2898
  this.root = loaded.root;
2886
2899
  this.outputDir = this.outDirOverride ? resolve(this.root, this.outDirOverride) : resolve(this.root, ".electro");
2887
2900
  this.configPaths.add(loaded.configPath);
2888
- for (const win of this.config.windows ?? []) this.configPaths.add(win.__source);
2889
- const windows = this.config.windows ?? [];
2901
+ for (const view of this.config.views ?? []) this.configPaths.add(view.__source);
2902
+ const views = this.config.views ?? [];
2890
2903
  const srcDir = resolve(this.root, "src");
2891
2904
  const mainEntry = resolve(dirname(this.config.runtime.__source), this.config.runtime.entry);
2892
2905
  session({
2893
2906
  root: this.root,
2894
2907
  main: mainEntry,
2895
- preload: windows.length > 0 ? resolve(this.outputDir, "generated/preload") : null,
2896
- renderer: windows.length > 0 ? resolve(this.root, dirname(relative(this.root, windows[0].__source))) : null,
2897
- windows: windows.map((w) => ({
2908
+ preload: views.length > 0 ? resolve(this.outputDir, "generated/preload") : null,
2909
+ renderer: views.length > 0 ? resolve(this.root, dirname(relative(this.root, views[0].__source))) : null,
2910
+ windows: views.map((w) => ({
2898
2911
  name: w.name,
2899
2912
  entry: resolve(dirname(w.__source), w.entry)
2900
2913
  }))
@@ -2907,7 +2920,7 @@ var DevServer = class {
2907
2920
  stepFail("codegen", err instanceof Error ? err.message : String(err));
2908
2921
  throw err;
2909
2922
  }
2910
- if (windows.length > 0) {
2923
+ if (views.length > 0) {
2911
2924
  const rendererTimer = startTimer();
2912
2925
  try {
2913
2926
  await this.startRenderer();
@@ -2924,7 +2937,7 @@ var DevServer = class {
2924
2937
  return;
2925
2938
  }
2926
2939
  const externals = await resolveExternals(this.root);
2927
- if (windows.length > 0) {
2940
+ if (views.length > 0) {
2928
2941
  const preloadTimer = startTimer();
2929
2942
  try {
2930
2943
  await this.buildPreload(externals);
@@ -2991,7 +3004,7 @@ var DevServer = class {
2991
3004
  this.lastScanResult = scanResult;
2992
3005
  const { files, envTypes } = generate({
2993
3006
  scanResult,
2994
- windows: this.config.windows ?? [],
3007
+ views: this.config.views ?? [],
2995
3008
  outputDir,
2996
3009
  srcDir
2997
3010
  });
@@ -3006,11 +3019,11 @@ var DevServer = class {
3006
3019
  await writeFile(envTypesPath, envTypes.content);
3007
3020
  }
3008
3021
  async startRenderer() {
3009
- const windows = this.config.windows ?? [];
3010
- const userViteConfigs = windows.filter((w) => w.vite).map((w) => w.vite);
3022
+ const views = this.config.views ?? [];
3023
+ const userViteConfigs = views.filter((w) => w.vite).map((w) => w.vite);
3011
3024
  this.rendererServer = await createServer(createRendererConfig({
3012
3025
  root: this.root,
3013
- windows,
3026
+ views,
3014
3027
  userViteConfigs: userViteConfigs.length > 0 ? userViteConfigs : void 0,
3015
3028
  logLevel: this.logLevel,
3016
3029
  clearScreen: this.clearScreen
@@ -3021,10 +3034,10 @@ var DevServer = class {
3021
3034
  this.rendererUrl = `http://localhost:${typeof addr === "object" && addr ? addr.port : 5173}`;
3022
3035
  }
3023
3036
  async buildPreload(externals) {
3024
- const windows = this.config.windows ?? [];
3037
+ const views = this.config.views ?? [];
3025
3038
  const preloadOutDir = resolve(this.outputDir, "preload");
3026
3039
  const input = {};
3027
- for (const win of windows) input[win.name] = resolve(this.outputDir, `generated/preload/${win.name}.gen.ts`);
3040
+ for (const view of views) input[view.name] = resolve(this.outputDir, `generated/preload/${view.name}.gen.ts`);
3028
3041
  const firstEntry = Object.values(input)[0];
3029
3042
  const baseConfig = createNodeConfig({
3030
3043
  scope: "preload",
@@ -3086,14 +3099,6 @@ var DevServer = class {
3086
3099
  async buildMain(externals) {
3087
3100
  const runtimeEntry = this.config.runtime.entry;
3088
3101
  const entry = resolve(dirname(this.config.runtime.__source), runtimeEntry);
3089
- const windowDefs = (this.config.windows ?? []).map((w) => ({
3090
- name: w.name,
3091
- type: w.type,
3092
- lifecycle: w.lifecycle,
3093
- autoShow: w.autoShow,
3094
- behavior: w.behavior,
3095
- window: w.window
3096
- }));
3097
3102
  const mainConfig = createNodeConfig({
3098
3103
  scope: "main",
3099
3104
  root: this.root,
@@ -3109,8 +3114,7 @@ var DevServer = class {
3109
3114
  logLevel: this.logLevel,
3110
3115
  clearScreen: this.clearScreen,
3111
3116
  userViteConfig: this.config.runtime.vite,
3112
- sourcemap: this.sourcemap,
3113
- define: { __ELECTRO_WINDOW_DEFINITIONS__: JSON.stringify(windowDefs) }
3117
+ sourcemap: this.sourcemap
3114
3118
  });
3115
3119
  const self = this;
3116
3120
  let firstBuild = true;
@@ -3147,10 +3151,10 @@ var DevServer = class {
3147
3151
  const addr = this.rendererServer.httpServer?.address();
3148
3152
  const port = typeof addr === "object" && addr ? addr.port : 5173;
3149
3153
  env.ELECTRO_RENDERER_BASE = `http://localhost:${port}`;
3150
- for (const win of this.config.windows ?? []) {
3151
- const entryPath = resolve(dirname(win.__source), win.entry);
3154
+ for (const view of this.config.views ?? []) {
3155
+ const entryPath = resolve(dirname(view.__source), view.entry);
3152
3156
  const relPath = relative(this.root, entryPath);
3153
- env[`ELECTRO_DEV_URL_${win.name}`] = `http://localhost:${port}/${relPath}`;
3157
+ env[`ELECTRO_DEV_URL_${view.name}`] = `http://localhost:${port}/${relPath}`;
3154
3158
  }
3155
3159
  }
3156
3160
  const proc = await launchElectron({
@@ -3287,15 +3291,15 @@ async function generate$1(options) {
3287
3291
  console.error("Error: electro.config.ts must have a default export");
3288
3292
  process.exit(1);
3289
3293
  }
3290
- const windows = config.windows ?? [];
3291
- console.log(`Loaded config with ${windows.length} window(s)`);
3294
+ const views = config.views ?? [];
3295
+ console.log(`Loaded config with ${views.length} view(s)`);
3292
3296
  const srcDir = resolve(process.cwd(), "src");
3293
3297
  console.log(`Scanning ${srcDir}...`);
3294
3298
  const scanResult = await scan(srcDir);
3295
3299
  console.log(`Found ${scanResult.features.length} feature(s)`);
3296
3300
  const { files, envTypes } = generate({
3297
3301
  scanResult,
3298
- windows,
3302
+ views,
3299
3303
  outputDir,
3300
3304
  srcDir
3301
3305
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cordy/electro-cli",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "CLI for @cordy/electro — dev server, build, and code generation commands",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -47,15 +47,15 @@
47
47
  "prepublishOnly": "bun run build"
48
48
  },
49
49
  "peerDependencies": {
50
- "@cordy/electro": "1.0.8",
50
+ "@cordy/electro": "1.1.1",
51
51
  "electron": ">=40.4.1",
52
52
  "vite": ">=8.0.0"
53
53
  },
54
54
  "dependencies": {
55
- "@cordy/electro-generator": "1.0.8"
55
+ "@cordy/electro-generator": "1.1.1"
56
56
  },
57
57
  "devDependencies": {
58
- "@cordy/electro": "1.0.9",
58
+ "@cordy/electro": "1.1.1",
59
59
  "@types/node": "^25.2.3",
60
60
  "cac": "^6.7.14",
61
61
  "electron": "^40.4.1",