@cordy/electro-cli 1.2.8 → 1.2.10

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 +153 -18
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -491,7 +491,7 @@ const cac = (name = "") => new CAC(name);
491
491
 
492
492
  //#endregion
493
493
  //#region package.json
494
- var version$1 = "1.2.8";
494
+ var version$1 = "1.2.10";
495
495
 
496
496
  //#endregion
497
497
  //#region src/dev/logger.ts
@@ -815,16 +815,48 @@ async function resolveExternals(root) {
815
815
  deps.delete("@cordy/electro");
816
816
  const builtins = builtinModules.flatMap((m) => [m, `node:${m}`]);
817
817
  const depsArray = [...deps];
818
+ const cjsInteropDeps = (await Promise.all(depsArray.map(async (dep) => ({
819
+ dep,
820
+ isCommonJs: await isLikelyCommonJsDependency(root, dep)
821
+ })))).filter((entry) => entry.isCommonJs).map((entry) => entry.dep);
818
822
  const deepPattern = depsArray.length > 0 ? new RegExp(`^(${depsArray.map(escapeRegExp).join("|")})/.+`) : null;
819
- return deepPattern ? [
820
- ...depsArray,
821
- ...builtins,
822
- deepPattern
823
- ] : [...depsArray, ...builtins];
823
+ return {
824
+ externals: deepPattern ? [
825
+ ...depsArray,
826
+ ...builtins,
827
+ deepPattern
828
+ ] : [...depsArray, ...builtins],
829
+ cjsInteropDeps
830
+ };
824
831
  }
825
832
  function escapeRegExp(str) {
826
833
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
827
834
  }
835
+ async function isLikelyCommonJsDependency(root, dep) {
836
+ if (dep === "electron" || dep.startsWith("node:")) return false;
837
+ const depPkgPath = resolve(root, "node_modules", dep, "package.json");
838
+ try {
839
+ return !isLikelyEsmPackage(JSON.parse(await readFile(depPkgPath, "utf-8")));
840
+ } catch {
841
+ return false;
842
+ }
843
+ }
844
+ function isLikelyEsmPackage(pkg) {
845
+ if (pkg.type === "module") return true;
846
+ if (typeof pkg.module === "string") return true;
847
+ if (typeof pkg.main === "string" && pkg.main.endsWith(".mjs")) return true;
848
+ if (typeof pkg.exports === "string" && pkg.exports.endsWith(".mjs")) return true;
849
+ if (hasImportCondition(pkg.exports)) return true;
850
+ return false;
851
+ }
852
+ function hasImportCondition(value) {
853
+ if (!value || typeof value !== "object") return false;
854
+ if (Array.isArray(value)) return value.some(hasImportCondition);
855
+ const record = value;
856
+ if ("import" in record) return true;
857
+ for (const nested of Object.values(record)) if (hasImportCondition(nested)) return true;
858
+ return false;
859
+ }
828
860
 
829
861
  //#endregion
830
862
  //#region src/dev/node-format.ts
@@ -1878,6 +1910,96 @@ var MagicString = class MagicString {
1878
1910
  }
1879
1911
  };
1880
1912
 
1913
+ //#endregion
1914
+ //#region src/plugins/cjs-external-interop.ts
1915
+ const STATIC_IMPORT_RE = /(?<=\s|^|;)import\s*([\s"']*(?<imports>[\p{L}\p{M}\w\t\n\r $*,/{}@.]+)from\s*)?["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][\s;]*/gmu;
1916
+ const IDENT_RE = /^[A-Za-z_$][\w$]*$/;
1917
+ /**
1918
+ * Rewrites named imports from external CommonJS deps to runtime-safe accessors.
1919
+ *
1920
+ * Example:
1921
+ * import { autoUpdater } from "electron-updater"
1922
+ * becomes
1923
+ * import * as __cjs_ext_0__ from "electron-updater"
1924
+ * const autoUpdater = __cjs_ext_0__.autoUpdater ?? __cjs_ext_0__.default?.autoUpdater
1925
+ */
1926
+ function cjsExternalInteropPlugin(cjsDeps) {
1927
+ if (cjsDeps.length === 0) return {
1928
+ name: "electro:cjs-external-interop",
1929
+ apply: "build"
1930
+ };
1931
+ const cjsDepSet = new Set(cjsDeps);
1932
+ return {
1933
+ name: "electro:cjs-external-interop",
1934
+ apply: "build",
1935
+ enforce: "post",
1936
+ renderChunk(code, _chunk, { format, sourcemap }) {
1937
+ if (format !== "es") return null;
1938
+ let s = null;
1939
+ let counter = 0;
1940
+ for (const match of code.matchAll(STATIC_IMPORT_RE)) {
1941
+ const statement = match[0];
1942
+ const start = match.index ?? 0;
1943
+ const specifier = match.groups?.specifier?.trim();
1944
+ const importsClause = match.groups?.imports?.trim();
1945
+ if (!specifier || !importsClause) continue;
1946
+ if (!isCjsExternalSpecifier(specifier, cjsDepSet)) continue;
1947
+ const parsed = parseImportClause(importsClause);
1948
+ if (!parsed) continue;
1949
+ const ns = `__cjs_ext_${counter++}__`;
1950
+ const lines = [`import * as ${ns} from ${JSON.stringify(specifier)};`];
1951
+ if (parsed.defaultImport) lines.push(`const ${parsed.defaultImport} = ${ns}.default ?? ${ns};`);
1952
+ for (const { imported, local } of parsed.named) lines.push(`const ${local} = ${ns}.${imported} ?? ${ns}.default?.${imported};`);
1953
+ s ??= new MagicString(code);
1954
+ s.overwrite(start, start + statement.length, lines.join("\n"));
1955
+ }
1956
+ if (!s) return null;
1957
+ return {
1958
+ code: s.toString(),
1959
+ map: sourcemap ? s.generateMap({ hires: "boundary" }) : null
1960
+ };
1961
+ }
1962
+ };
1963
+ }
1964
+ function isCjsExternalSpecifier(specifier, cjsDepSet) {
1965
+ if (specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\0") || specifier.startsWith("node:")) return false;
1966
+ if (cjsDepSet.has(specifier)) return true;
1967
+ for (const dep of cjsDepSet) if (specifier.startsWith(`${dep}/`)) return true;
1968
+ return false;
1969
+ }
1970
+ function parseImportClause(clause) {
1971
+ const braceStart = clause.indexOf("{");
1972
+ const braceEnd = clause.lastIndexOf("}");
1973
+ if (braceStart < 0 || braceEnd < braceStart) return null;
1974
+ const defaultPart = clause.slice(0, braceStart).trim().replace(/,$/, "").trim();
1975
+ if (defaultPart.startsWith("*")) return null;
1976
+ let defaultImport;
1977
+ if (defaultPart.length > 0) {
1978
+ const normalized = defaultPart.replace(/^type\s+/, "").trim();
1979
+ if (!IDENT_RE.test(normalized)) return null;
1980
+ defaultImport = normalized;
1981
+ }
1982
+ const namedPart = clause.slice(braceStart + 1, braceEnd).trim();
1983
+ if (namedPart.length === 0) return null;
1984
+ const named = [];
1985
+ for (const raw of namedPart.split(",")) {
1986
+ const token = raw.trim();
1987
+ if (token.length === 0) continue;
1988
+ const normalized = token.replace(/^type\s+/, "").trim();
1989
+ const match = /^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/.exec(normalized);
1990
+ if (!match) return null;
1991
+ named.push({
1992
+ imported: match[1],
1993
+ local: match[2] ?? match[1]
1994
+ });
1995
+ }
1996
+ if (named.length === 0) return null;
1997
+ return {
1998
+ defaultImport,
1999
+ named
2000
+ };
2001
+ }
2002
+
1881
2003
  //#endregion
1882
2004
  //#region src/plugins/esm-shim.ts
1883
2005
  const CJSYNTAX_RE = /__filename|__dirname|require\(|require\.resolve\(/;
@@ -1964,6 +2086,7 @@ function createNodeConfig(opts) {
1964
2086
  plugins: [
1965
2087
  importMetaPlugin(),
1966
2088
  ...opts.plugins ?? [],
2089
+ cjsExternalInteropPlugin(opts.cjsInteropDeps ?? []),
1967
2090
  esmShimPlugin()
1968
2091
  ],
1969
2092
  customLogger: opts.customLogger,
@@ -2800,7 +2923,9 @@ async function build$1(options) {
2800
2923
  stepFail("codegen", err instanceof Error ? err.message : String(err));
2801
2924
  process.exit(1);
2802
2925
  }
2803
- const externals = await resolveExternals(root);
2926
+ const resolvedExternals = await resolveExternals(root);
2927
+ const externals = resolvedExternals.externals;
2928
+ const cjsInteropDeps = resolvedExternals.cjsInteropDeps;
2804
2929
  const logger = createBuildLogger();
2805
2930
  try {
2806
2931
  buildScope("main");
@@ -2812,7 +2937,8 @@ async function build$1(options) {
2812
2937
  sourcemap: options.sourcemap,
2813
2938
  logger,
2814
2939
  bytecode: options.bytecode,
2815
- format: nodeFormat
2940
+ format: nodeFormat,
2941
+ cjsInteropDeps
2816
2942
  });
2817
2943
  } catch (err) {
2818
2944
  stepFail("main", err instanceof Error ? err.message : String(err));
@@ -2829,7 +2955,8 @@ async function build$1(options) {
2829
2955
  sourcemap: options.sourcemap,
2830
2956
  logger,
2831
2957
  bytecode: options.bytecode,
2832
- format: nodeFormat
2958
+ format: nodeFormat,
2959
+ cjsInteropDeps
2833
2960
  });
2834
2961
  } catch (err) {
2835
2962
  stepFail("preload", err instanceof Error ? err.message : String(err));
@@ -2882,6 +3009,7 @@ async function buildMain(args) {
2882
3009
  customLogger: args.logger,
2883
3010
  logLevel: "info",
2884
3011
  format: args.format,
3012
+ cjsInteropDeps: args.cjsInteropDeps,
2885
3013
  define: { __ELECTRO_VIEW_REGISTRY__: JSON.stringify(viewRegistry) }
2886
3014
  }));
2887
3015
  }
@@ -2908,7 +3036,8 @@ async function buildPreload(args) {
2908
3036
  sourcemap: args.sourcemap,
2909
3037
  customLogger: args.logger,
2910
3038
  logLevel: "info",
2911
- format: args.format
3039
+ format: args.format,
3040
+ cjsInteropDeps: args.cjsInteropDeps
2912
3041
  });
2913
3042
  if (Object.keys(input).length > 1) {
2914
3043
  const subBuildConfig = createNodeConfig({
@@ -2926,7 +3055,8 @@ async function buildPreload(args) {
2926
3055
  sourcemap: args.sourcemap,
2927
3056
  customLogger: args.logger,
2928
3057
  logLevel: "info",
2929
- format: args.format
3058
+ format: args.format,
3059
+ cjsInteropDeps: args.cjsInteropDeps
2930
3060
  });
2931
3061
  baseConfig.plugins.push(isolateEntriesPlugin(subBuildConfig));
2932
3062
  }
@@ -3062,11 +3192,13 @@ var DevServer = class {
3062
3192
  this.attachConfigWatcher();
3063
3193
  return;
3064
3194
  }
3065
- const externals = await resolveExternals(this.root);
3195
+ const resolvedExternals = await resolveExternals(this.root);
3196
+ const externals = resolvedExternals.externals;
3197
+ const cjsInteropDeps = resolvedExternals.cjsInteropDeps;
3066
3198
  if (views.length > 0) {
3067
3199
  const preloadTimer = startTimer();
3068
3200
  try {
3069
- await this.buildPreload(externals);
3201
+ await this.buildPreload(externals, cjsInteropDeps);
3070
3202
  step("preload", preloadTimer());
3071
3203
  } catch (err) {
3072
3204
  stepFail("preload", err instanceof Error ? err.message : String(err));
@@ -3075,7 +3207,7 @@ var DevServer = class {
3075
3207
  }
3076
3208
  const mainBuildTimer = startTimer();
3077
3209
  try {
3078
- await this.buildMain(externals);
3210
+ await this.buildMain(externals, cjsInteropDeps);
3079
3211
  step("main", mainBuildTimer());
3080
3212
  } catch (err) {
3081
3213
  stepFail("main", err instanceof Error ? err.message : String(err));
@@ -3162,7 +3294,7 @@ var DevServer = class {
3162
3294
  const addr = this.rendererServer.httpServer?.address();
3163
3295
  this.rendererUrl = `http://localhost:${typeof addr === "object" && addr ? addr.port : 5173}`;
3164
3296
  }
3165
- async buildPreload(externals) {
3297
+ async buildPreload(externals, cjsInteropDeps) {
3166
3298
  const views = (this.config.views ?? []).filter((v) => v.entry);
3167
3299
  const preloadOutDir = resolve(this.outputDir, "preload");
3168
3300
  const input = {};
@@ -3183,7 +3315,8 @@ var DevServer = class {
3183
3315
  logLevel: this.logLevel,
3184
3316
  clearScreen: this.clearScreen,
3185
3317
  sourcemap: this.sourcemap,
3186
- format: this.nodeFormat
3318
+ format: this.nodeFormat,
3319
+ cjsInteropDeps
3187
3320
  });
3188
3321
  if (Object.keys(input).length > 1) {
3189
3322
  const subBuildConfig = createNodeConfig({
@@ -3201,7 +3334,8 @@ var DevServer = class {
3201
3334
  logLevel: this.logLevel,
3202
3335
  clearScreen: this.clearScreen,
3203
3336
  sourcemap: this.sourcemap,
3204
- format: this.nodeFormat
3337
+ format: this.nodeFormat,
3338
+ cjsInteropDeps
3205
3339
  });
3206
3340
  baseConfig.plugins.push(isolateEntriesPlugin(subBuildConfig));
3207
3341
  }
@@ -3227,7 +3361,7 @@ var DevServer = class {
3227
3361
  });
3228
3362
  this.preloadWatch = await build(baseConfig);
3229
3363
  }
3230
- async buildMain(externals) {
3364
+ async buildMain(externals, cjsInteropDeps) {
3231
3365
  const runtimeEntry = this.config.runtime.entry;
3232
3366
  const entry = resolve(dirname(this.config.runtime.__source), runtimeEntry);
3233
3367
  this.mainInitialBuildPromise = new Promise((resolve) => {
@@ -3259,6 +3393,7 @@ var DevServer = class {
3259
3393
  userViteConfig: this.config.runtime.vite,
3260
3394
  sourcemap: this.sourcemap,
3261
3395
  format: this.nodeFormat,
3396
+ cjsInteropDeps,
3262
3397
  define: { __ELECTRO_VIEW_REGISTRY__: JSON.stringify(viewRegistry) }
3263
3398
  });
3264
3399
  const self = this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cordy/electro-cli",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
4
4
  "description": "CLI for @cordy/electro — dev server, build, and code generation commands",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -55,7 +55,7 @@
55
55
  "@cordy/electro-generator": "1.2.8"
56
56
  },
57
57
  "devDependencies": {
58
- "@cordy/electro": "1.2.6",
58
+ "@cordy/electro": "1.2.9",
59
59
  "@types/node": "^25.2.3",
60
60
  "cac": "^6.7.14",
61
61
  "electron": "^40.4.1",