electron-incremental-update 3.0.0-beta.2 → 3.0.0-beta.3

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.
@@ -173,10 +173,11 @@ function handleUnexpectedErrors(callback) {
173
173
  process.on("uncaughtException", callback);
174
174
  process.on("unhandledRejection", callback);
175
175
  }
176
+ /**
177
+ * @deprecated No longer needed. It is embeded in `startupWithUpdater()
178
+ */
176
179
  function reloadOnPreloadScriptChanged() {
177
- if (isDev) process.on("message", (msg) => {
178
- if (msg === "electron-vite&type=hot-reload") for (const window of electron.BrowserWindow.getAllWindows()) window.reload();
179
- });
180
+ console.warn("`reloadOnPreloadScriptChange()` is no longer needed. It is embeded in `startupWithUpdater()`");
180
181
  }
181
182
 
182
183
  //#endregion
@@ -1,4 +1,4 @@
1
- import { BrowserWindow, app } from "electron";
1
+ import { app } from "electron";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
 
@@ -170,10 +170,11 @@ function handleUnexpectedErrors(callback) {
170
170
  process.on("uncaughtException", callback);
171
171
  process.on("unhandledRejection", callback);
172
172
  }
173
+ /**
174
+ * @deprecated No longer needed. It is embeded in `startupWithUpdater()
175
+ */
173
176
  function reloadOnPreloadScriptChanged() {
174
- if (isDev) process.on("message", (msg) => {
175
- if (msg === "electron-vite&type=hot-reload") for (const window of BrowserWindow.getAllWindows()) window.reload();
176
- });
177
+ console.warn("`reloadOnPreloadScriptChange()` is no longer needed. It is embeded in `startupWithUpdater()`");
177
178
  }
178
179
 
179
180
  //#endregion
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const require_version = require('./version-aPrLuz_-.cjs');
2
- const require_electron = require('./electron-BFoZUBhU.cjs');
2
+ const require_electron = require('./electron-DH-Uyikp.cjs');
3
3
  let electron = require("electron");
4
4
  let node_fs = require("node:fs");
5
5
  node_fs = require_version.__toESM(node_fs);
@@ -219,7 +219,9 @@ async function autoUpdate(updater) {
219
219
  * })
220
220
  */
221
221
  function startupWithUpdater(fn) {
222
- console.log(typeof fn);
222
+ if (require_electron.isDev) process.on("message", (msg) => {
223
+ if (msg === "electron-vite&type=hot-reload") for (const window of electron.BrowserWindow.getAllWindows()) window.reload();
224
+ });
223
225
  return fn;
224
226
  }
225
227
  function runWithDefaultExport(mod, args) {
@@ -259,7 +261,7 @@ async function createElectronApp(appOptions = {}) {
259
261
  if (__EIU_IS_ESM__) runWithDefaultExport(await import(`file://${mainPath}`), updaterInstance);
260
262
  else runWithDefaultExport(require(mainPath), updaterInstance);
261
263
  } catch (error) {
262
- logger?.error("startup error, exit", error);
264
+ logger?.error("Fail to startup", error);
263
265
  onStartError?.(error, logger);
264
266
  electron.app.quit();
265
267
  }
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { a as getPathFromAppNameAsar, f as isDev, i as getEntryVersion, r as getAppVersion, y as restartApp } from "./electron-CJIoO4ny.mjs";
1
+ import { a as getPathFromAppNameAsar, f as isDev, i as getEntryVersion, r as getAppVersion, y as restartApp } from "./electron-OKQIYbcw.mjs";
2
2
  import { r as isUpdateJSON } from "./version--eVB2A7n.mjs";
3
- import { app } from "electron";
3
+ import { BrowserWindow, app } from "electron";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import { EventEmitter } from "node:events";
@@ -217,7 +217,9 @@ async function autoUpdate(updater) {
217
217
  * })
218
218
  */
219
219
  function startupWithUpdater(fn) {
220
- console.log(typeof fn);
220
+ if (isDev) process.on("message", (msg) => {
221
+ if (msg === "electron-vite&type=hot-reload") for (const window of BrowserWindow.getAllWindows()) window.reload();
222
+ });
221
223
  return fn;
222
224
  }
223
225
  function runWithDefaultExport(mod, args) {
@@ -257,7 +259,7 @@ async function createElectronApp(appOptions = {}) {
257
259
  if (__EIU_IS_ESM__) runWithDefaultExport(await import(`file://${mainPath}`), updaterInstance);
258
260
  else runWithDefaultExport(require(mainPath), updaterInstance);
259
261
  } catch (error) {
260
- logger?.error("startup error, exit", error);
262
+ logger?.error("Fail to startup", error);
261
263
  onStartError?.(error, logger);
262
264
  app.quit();
263
265
  }
package/dist/utils.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const require_version = require('./version-aPrLuz_-.cjs');
2
- const require_electron = require('./electron-BFoZUBhU.cjs');
2
+ const require_electron = require('./electron-DH-Uyikp.cjs');
3
3
  const require_zip = require('./zip-BCC7FAQ_.cjs');
4
4
 
5
5
  exports.aesDecrypt = require_zip.aesDecrypt;
package/dist/utils.d.cts CHANGED
@@ -144,6 +144,9 @@ declare function getPathFromEntryAsar(...paths: string[]): string;
144
144
  * @param callback callback function
145
145
  */
146
146
  declare function handleUnexpectedErrors(callback: (err: unknown) => void): void;
147
+ /**
148
+ * @deprecated No longer needed. It is embeded in `startupWithUpdater()
149
+ */
147
150
  declare function reloadOnPreloadScriptChanged(): void;
148
151
  //#endregion
149
152
  //#region src/utils/zip.d.ts
package/dist/utils.d.mts CHANGED
@@ -144,6 +144,9 @@ declare function getPathFromEntryAsar(...paths: string[]): string;
144
144
  * @param callback callback function
145
145
  */
146
146
  declare function handleUnexpectedErrors(callback: (err: unknown) => void): void;
147
+ /**
148
+ * @deprecated No longer needed. It is embeded in `startupWithUpdater()
149
+ */
147
150
  declare function reloadOnPreloadScriptChanged(): void;
148
151
  //#endregion
149
152
  //#region src/utils/zip.d.ts
package/dist/utils.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { C as singleInstance, S as setPortableDataPath, _ as reloadOnPreloadScriptChanged, a as getPathFromAppNameAsar, b as setAppUserModelId, c as getPathFromPreload, d as importNative, f as isDev, g as loadPage, h as isWin, i as getEntryVersion, l as getPathFromPublic, m as isMac, n as disableHWAccForWin7, o as getPathFromEntryAsar, p as isLinux, r as getAppVersion, s as getPathFromMain, t as beautifyDevTools, u as handleUnexpectedErrors, v as requireNative, x as setPortableAppDataPath, y as restartApp } from "./electron-CJIoO4ny.mjs";
1
+ import { C as singleInstance, S as setPortableDataPath, _ as reloadOnPreloadScriptChanged, a as getPathFromAppNameAsar, b as setAppUserModelId, c as getPathFromPreload, d as importNative, f as isDev, g as loadPage, h as isWin, i as getEntryVersion, l as getPathFromPublic, m as isMac, n as disableHWAccForWin7, o as getPathFromEntryAsar, p as isLinux, r as getAppVersion, s as getPathFromMain, t as beautifyDevTools, u as handleUnexpectedErrors, v as requireNative, x as setPortableAppDataPath, y as restartApp } from "./electron-OKQIYbcw.mjs";
2
2
  import { i as parseVersion, n as defaultVersionJsonGenerator, r as isUpdateJSON, t as defaultIsLowerVersion } from "./version--eVB2A7n.mjs";
3
3
  import { a as defaultDownloadUpdateJSON, c as resolveJson, d as defaultSignature, f as defaultVerifySignature, i as defaultDownloadText, l as aesDecrypt, n as defaultZipFile, o as downloadUtil, p as hashBuffer, r as defaultDownloadAsar, s as getHeader, t as defaultUnzipFile, u as aesEncrypt } from "./zip-Dwm7s1C9.mjs";
4
4
 
package/dist/vite.d.mts CHANGED
@@ -1,4 +1,3 @@
1
- import "local-pkg";
2
1
  import { SpawnOptions } from "node:child_process";
3
2
  import { BuildEnvironmentOptions, InlineConfig, LibraryOptions, PluginOption, UserConfig, UserConfigFn, build } from "vite";
4
3
 
@@ -18,9 +17,6 @@ declare function convertLiteral(code: string, sourcemap?: boolean, offset?: numb
18
17
  type Promisable<T> = T | Promise<T>;
19
18
  type AnyFunction<Return = any> = (...args: any[]) => Return;
20
19
  //#endregion
21
- //#region src/vite/electron/utils.d.ts
22
- type RolldownOptions = Exclude<BuildEnvironmentOptions["rolldownOptions"], undefined>;
23
- //#endregion
24
20
  //#region src/vite/electron/core.d.ts
25
21
  interface ElectronOptions {
26
22
  /**
@@ -47,18 +43,8 @@ interface ElectronOptions {
47
43
  }) => void | Promise<void>;
48
44
  }
49
45
  //#endregion
50
- //#region src/vite/electron/simple.d.ts
51
- interface ElectronSimpleOptions {
52
- main: ElectronOptions;
53
- preload?: Omit<ElectronOptions, "entry"> & {
54
- /**
55
- * Shortcut of `build.rolldownOptions.input`.
56
- *
57
- * Preload scripts may contain Web assets, so use the `build.rolldownOptions.input` instead `build.lib.entry`.
58
- */
59
- input: RolldownOptions["input"];
60
- };
61
- }
46
+ //#region src/vite/electron/utils.d.ts
47
+ type RolldownOptions = Exclude<BuildEnvironmentOptions["rolldownOptions"], undefined>;
62
48
  //#endregion
63
49
  //#region src/utils/version.d.ts
64
50
  /**
@@ -123,13 +109,19 @@ interface DistinguishedName {
123
109
  }
124
110
  //#endregion
125
111
  //#region src/vite/option.d.ts
126
- interface ViteOverride {
112
+ interface CommonBuildOption {
113
+ /**
114
+ * Shortcut of `build.rolldownOptions.input`
115
+ */
116
+ files: NonNullable<ElectronOptions["entry"]>;
127
117
  /**
128
118
  * Override vite options
129
119
  */
130
120
  vite?: ElectronOptions["vite"] & {
131
121
  build?: {
132
122
  outDir: never;
123
+ sourcemap: never;
124
+ minify: never;
133
125
  rolldownOptions?: {
134
126
  output?: {
135
127
  dir: never;
@@ -177,19 +169,74 @@ interface ElectronWithUpdaterOptions {
177
169
  */
178
170
  buildVersionJson?: boolean;
179
171
  /**
172
+ * `external` option in `build.rolldownOptions`,
173
+ * default is node built-in modules or native modules.
174
+ *
175
+ * If is in dev and `entry.postBuild` is not setup, will also
176
+ * external `dependencies` in `package.json`
177
+ */
178
+ external?: NonNullable<NonNullable<InlineConfig["build"]>["rolldownOptions"]>["external"];
179
+ /**
180
180
  * Options for entry (app.asar)
181
+ *
182
+ * To change output directories, use `options.updater.paths.electronDistPath` instead
181
183
  */
182
- entry?: BuildEntryOption;
184
+ entry: {
185
+ /**
186
+ * By default, all the unbundled modules will be packaged by packager like `electron-builder`.
187
+ * If setup, all the `dependencies` in `package.json` will be bundled by default, and you need
188
+ * to manually handle the native module files.
189
+ *
190
+ * If you are using `electron-buidler`, don't forget to append `'!node_modules/**'` in
191
+ * electron-build config's `files` array
192
+ */
193
+ postBuild?: (args: {
194
+ /**
195
+ * Whether is in build mode
196
+ */
197
+ isBuild: boolean;
198
+ /**
199
+ * Get path from `entryOutputDirPath`
200
+ */
201
+ getPathFromEntryOutputDir: (...paths: string[]) => string;
202
+ /**
203
+ * Check exist and copy file to `entryOutputDirPath`
204
+ *
205
+ * If `to` absent, set to `basename(from)`
206
+ *
207
+ * If `skipIfExist` absent, skip copy if `to` exist
208
+ */
209
+ copyToEntryOutputDir: (options: {
210
+ from: string;
211
+ to?: string;
212
+ /**
213
+ * Skip copy if `to` exist
214
+ * @default true
215
+ */
216
+ skipIfExist?: boolean;
217
+ }) => void;
218
+ /**
219
+ * Copy specified modules to entry output dir, just like `external` option in rolldown
220
+ */
221
+ copyModules: (options: {
222
+ /**
223
+ * External Modules
224
+ */
225
+ modules: string[];
226
+ /**
227
+ * Skip copy if `to` exist
228
+ * @default true
229
+ */
230
+ skipIfExist?: boolean;
231
+ }) => void;
232
+ }) => Promisable<void>;
233
+ } & CommonBuildOption;
183
234
  /**
184
235
  * Main process options
185
236
  *
186
237
  * To change output directories, use `options.updater.paths.electronDistPath` instead
187
238
  */
188
239
  main: {
189
- /**
190
- * Shortcut of `build.rolldownOptions.input`
191
- */
192
- files: NonNullable<ElectronOptions["entry"]>;
193
240
  /**
194
241
  * Electron App startup function.
195
242
  *
@@ -199,125 +246,18 @@ interface ElectronWithUpdaterOptions {
199
246
  * @param customElectronPkg custom electron package name (default: 'electron')
200
247
  */
201
248
  onstart?: ElectronOptions["onstart"];
202
- } & ViteOverride;
249
+ } & CommonBuildOption;
203
250
  /**
204
251
  * Preload process options
205
252
  *
206
253
  * To change output directories, use `options.updater.paths.electronDistPath` instead
207
254
  */
208
- preload: {
209
- /**
210
- * Shortcut of `build.rolldownOptions.input`.
211
- *
212
- * Preload scripts may contain Web assets, so use the `build.rolldownOptions.input` instead `build.lib.entry`.
213
- */
214
- files: NonNullable<ElectronOptions["entry"]>;
215
- } & ViteOverride;
255
+ preload?: CommonBuildOption;
216
256
  /**
217
257
  * Updater options
218
258
  */
219
259
  updater?: UpdaterOptions;
220
260
  }
221
- interface BuildEntryOption {
222
- /**
223
- * Override to minify on entry
224
- * @default isBuild
225
- */
226
- minify?: boolean;
227
- /**
228
- * Override to generate sourcemap on entry
229
- */
230
- sourcemap?: boolean;
231
- /**
232
- * Path to app entry output file
233
- * @default 'dist-entry'
234
- */
235
- outDir?: string;
236
- /**
237
- * Path to app entry file
238
- * @default 'electron/entry.ts'
239
- */
240
- files?: NonNullable<ElectronOptions["entry"]>;
241
- /**
242
- * Skip process dynamic require
243
- *
244
- * Useful for `better-sqlite3` and other old packages
245
- */
246
- ignoreDynamicRequires?: boolean;
247
- /**
248
- * `external` option in `build.rolldownOptions`,
249
- * default is node built-in modules or native modules.
250
- *
251
- * If is in dev and {@link postBuild} is not setup, will also
252
- * external `dependencies` in `package.json`
253
- */
254
- external?: NonNullable<NonNullable<InlineConfig["build"]>["rolldownOptions"]>["external"];
255
- /**
256
- * Custom options for `vite` build
257
- * ```ts
258
- * const options = {
259
- * plugins: [esm(), bytecodePlugin()], // load on needed
260
- * build: {
261
- * sourcemap,
262
- * minify,
263
- * outDir: entryOutputDirPath,
264
- * commonjsOptions: { ignoreDynamicRequires },
265
- * rolldownOptions: { external },
266
- * },
267
- * define,
268
- * }
269
- * ```
270
- */
271
- vite?: InlineConfig;
272
- /**
273
- * By default, all the unbundled modules will be packaged by packager like `electron-builder`.
274
- * If setup, all the `dependencies` in `package.json` will be bundled by default, and you need
275
- * to manually handle the native module files.
276
- *
277
- * If you are using `electron-buidler`, don't forget to append `'!node_modules/**'` in
278
- * electron-build config's `files` array
279
- */
280
- postBuild?: (args: {
281
- /**
282
- * Whether is in build mode
283
- */
284
- isBuild: boolean;
285
- /**
286
- * Get path from `entryOutputDirPath`
287
- */
288
- getPathFromEntryOutputDir: (...paths: string[]) => string;
289
- /**
290
- * Check exist and copy file to `entryOutputDirPath`
291
- *
292
- * If `to` absent, set to `basename(from)`
293
- *
294
- * If `skipIfExist` absent, skip copy if `to` exist
295
- */
296
- copyToEntryOutputDir: (options: {
297
- from: string;
298
- to?: string;
299
- /**
300
- * Skip copy if `to` exist
301
- * @default true
302
- */
303
- skipIfExist?: boolean;
304
- }) => void;
305
- /**
306
- * Copy specified modules to entry output dir, just like `external` option in rolldown
307
- */
308
- copyModules: (options: {
309
- /**
310
- * External Modules
311
- */
312
- modules: string[];
313
- /**
314
- * Skip copy if `to` exist
315
- * @default true
316
- */
317
- skipIfExist?: boolean;
318
- }) => void;
319
- }) => Promisable<void>;
320
- }
321
261
  interface GeneratorOverrideFunctions {
322
262
  /**
323
263
  * Custom signature generate function
@@ -358,6 +298,11 @@ interface UpdaterOptions {
358
298
  */
359
299
  asarOutputPath?: string;
360
300
  /**
301
+ * Path to app entry output file
302
+ * @default 'dist-entry'
303
+ */
304
+ entryOutDir?: string;
305
+ /**
361
306
  * Path to version info output, content is {@link UpdateJSON}
362
307
  * @default `version.json`
363
308
  */
@@ -427,6 +372,17 @@ interface UpdaterOptions {
427
372
  }
428
373
  //#endregion
429
374
  //#region src/vite/core.d.ts
375
+ interface ElectronSimpleOptions {
376
+ main: ElectronOptions;
377
+ preload?: Omit<ElectronOptions, "entry"> & {
378
+ /**
379
+ * Shortcut of `build.rolldownOptions.input`.
380
+ *
381
+ * Preload scripts may contain Web assets, so use the `build.rolldownOptions.input` instead `build.lib.entry`.
382
+ */
383
+ input: RolldownOptions["input"];
384
+ };
385
+ }
430
386
  type StartupFn = NonNullable<NonNullable<ElectronSimpleOptions["main"]>["onstart"]>;
431
387
  /**
432
388
  * Startup function for debug
package/dist/vite.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { builtinModules, createRequire } from "node:module";
2
2
  import * as babel from "@babel/core";
3
- import { getPackageInfoSync, loadPackageJSON, loadPackageJSONSync } from "local-pkg";
3
+ import { getPackageInfoSync, loadPackageJSON } from "local-pkg";
4
4
  import MagicString from "magic-string";
5
5
  import cp from "node:child_process";
6
6
  import fs from "node:fs";
@@ -69,7 +69,6 @@ function defaultVersionJsonGenerator(existingJson, signature, version, minimumVe
69
69
  //#region src/vite/constant.ts
70
70
  const id = "electron-incremental-updater";
71
71
  const bytecodeId = `${id}-bytecode`;
72
- const esmId = `${id}-esm`;
73
72
  const log = createLogger("info", { prefix: `[${id}]` });
74
73
  const bytecodeLog = createLogger("info", { prefix: `[${bytecodeId}]` });
75
74
 
@@ -221,10 +220,39 @@ function copyAndSkipIfExist(from, to, skipIfExist) {
221
220
  log.warn(`Copy failed: ${error}`, { timestamp: true });
222
221
  }
223
222
  }
224
- function resolveInputToArray(files) {
225
- if (typeof files === "string") return [files];
226
- if (Array.isArray(files)) return files;
227
- return Object.values(files);
223
+
224
+ //#endregion
225
+ //#region src/vite/build.ts
226
+ async function buildAsar({ version, asarOutputPath, gzipPath, electronDistPath, rendererDistPath, generateGzipFile }) {
227
+ await fs.promises.rename(rendererDistPath, path.join(electronDistPath, "renderer"));
228
+ fs.writeFileSync(path.join(electronDistPath, "version"), version);
229
+ await createPackage(electronDistPath, asarOutputPath);
230
+ const buf = await generateGzipFile(fs.readFileSync(asarOutputPath));
231
+ fs.writeFileSync(gzipPath, buf);
232
+ log.info(`Build update asar to '${gzipPath}' [${readableSize(buf.length)}]`, { timestamp: true });
233
+ return buf;
234
+ }
235
+ async function buildUpdateJson({ versionPath, privateKey, cert, version, minimumVersion, generateSignature, generateUpdateJson }, asarBuffer) {
236
+ let _json = {
237
+ beta: {
238
+ minimumVersion: version,
239
+ signature: "",
240
+ version
241
+ },
242
+ minimumVersion: version,
243
+ signature: "",
244
+ version
245
+ };
246
+ if (fs.existsSync(versionPath)) try {
247
+ const oldVersionJson = JSON.parse(fs.readFileSync(versionPath, "utf-8"));
248
+ if (isUpdateJSON(oldVersionJson)) _json = oldVersionJson;
249
+ else log.warn("Old version json is invalid, ignore it", { timestamp: true });
250
+ } catch {}
251
+ const sig = await generateSignature(asarBuffer, privateKey, cert, version);
252
+ _json = await generateUpdateJson(_json, sig, version, minimumVersion);
253
+ if (!isUpdateJSON(_json)) throw new Error("Invalid update json");
254
+ fs.writeFileSync(versionPath, JSON.stringify(_json, null, 2));
255
+ log.info(`build update json to '${versionPath}'`, { timestamp: true });
228
256
  }
229
257
 
230
258
  //#endregion
@@ -352,15 +380,14 @@ function bytecodePlugin(env, options) {
352
380
  //#endregion
353
381
  //#region src/vite/electron/utils.ts
354
382
  /** Resolve the default Vite's `InlineConfig` for build Electron-Main */
355
- function resolveViteConfig(options) {
356
- const esmodule = (loadPackageJSONSync() ?? {}).type === "module";
383
+ function resolveViteConfig(isESM, options) {
357
384
  return mergeConfig({
358
385
  configFile: false,
359
386
  publicDir: false,
360
387
  build: {
361
388
  lib: options.entry && {
362
389
  entry: options.entry,
363
- formats: esmodule ? ["es"] : ["cjs"],
390
+ formats: isESM ? ["es"] : ["cjs"],
364
391
  fileName: () => "[name].js"
365
392
  },
366
393
  outDir: "dist-electron",
@@ -377,53 +404,6 @@ function resolveViteConfig(options) {
377
404
  define: { "process.env": "process.env" }
378
405
  }, options?.vite || {});
379
406
  }
380
- function withExternalBuiltins(config) {
381
- const builtins = builtinModules.filter((e) => !e.startsWith("_"));
382
- builtins.push("electron", ...builtins.map((m) => `node:${m}`));
383
- config.build ??= {};
384
- config.build.rolldownOptions ??= {};
385
- let external = config.build.rolldownOptions.external;
386
- if (Array.isArray(external) || typeof external === "string" || external instanceof RegExp) external = builtins.concat(external);
387
- else if (typeof external === "function") {
388
- const original = external;
389
- external = function(source, importer, isResolved) {
390
- if (builtins.includes(source)) return true;
391
- return original(source, importer, isResolved);
392
- };
393
- } else external = builtins;
394
- config.build.rolldownOptions.external = external;
395
- return config;
396
- }
397
- /**
398
- * @see https://github.com/vitejs/vite/blob/v4.0.1/packages/vite/src/node/constants.ts#L137-L147
399
- */
400
- function resolveHostname(hostname) {
401
- const loopbackHosts = new Set([
402
- "localhost",
403
- "127.0.0.1",
404
- "::1",
405
- "0000:0000:0000:0000:0000:0000:0000:0001"
406
- ]);
407
- const wildcardHosts = new Set([
408
- "0.0.0.0",
409
- "::",
410
- "0000:0000:0000:0000:0000:0000:0000:0000"
411
- ]);
412
- return loopbackHosts.has(hostname) || wildcardHosts.has(hostname) ? "localhost" : hostname;
413
- }
414
- function resolveServerUrl(server) {
415
- const addressInfo = server.httpServer?.address();
416
- const isAddressInfo = (x) => x?.address;
417
- if (isAddressInfo(addressInfo)) {
418
- const { address, port } = addressInfo;
419
- const hostname = resolveHostname(address);
420
- const options = server.config.server;
421
- const protocol = options.https ? "https" : "http";
422
- const devBase = server.config.base;
423
- const path = typeof options.open === "string" ? options.open : devBase;
424
- return path.startsWith("http") ? path : `${protocol}://${hostname}:${port}${path}`;
425
- }
426
- }
427
407
  /** @see https://github.com/vitejs/vite/blob/v5.4.9/packages/vite/src/node/build.ts#L489-L504 */
428
408
  function resolveInput(config) {
429
409
  const options = config.build;
@@ -498,10 +478,10 @@ function killTree(tree) {
498
478
 
499
479
  //#endregion
500
480
  //#region src/vite/electron/core.ts
501
- function build$1(options) {
502
- return build(withExternalBuiltins(resolveViteConfig(options)));
481
+ function build$1(isESM, options) {
482
+ return build(resolveViteConfig(isESM, options));
503
483
  }
504
- function electron(options) {
484
+ function electron(isESM, options) {
505
485
  const optionsArray = Array.isArray(options) ? options : [options];
506
486
  let userConfig;
507
487
  let configEnv;
@@ -512,7 +492,7 @@ function electron(options) {
512
492
  apply: "serve",
513
493
  configureServer(server) {
514
494
  server.httpServer?.once("listening", () => {
515
- Object.assign(process.env, { VITE_DEV_SERVER_URL: resolveServerUrl(server) });
495
+ Object.assign(process.env, { VITE_DEV_SERVER_URL: server.resolvedUrls?.local[0] });
516
496
  const entryCount = optionsArray.length;
517
497
  let closeBundleCount = 0;
518
498
  for (const options of optionsArray) {
@@ -541,7 +521,7 @@ function electron(options) {
541
521
  else startup();
542
522
  }
543
523
  });
544
- build$1(options);
524
+ build$1(isESM, options);
545
525
  }
546
526
  });
547
527
  }
@@ -564,7 +544,7 @@ function electron(options) {
564
544
  options.vite.root ??= userConfig.root;
565
545
  options.vite.envDir ??= userConfig.envDir;
566
546
  options.vite.envPrefix ??= userConfig.envPrefix;
567
- await build$1(options);
547
+ await build$1(isESM, options);
568
548
  }
569
549
  }
570
550
  }];
@@ -615,64 +595,6 @@ startup.exit = async () => {
615
595
  });
616
596
  };
617
597
 
618
- //#endregion
619
- //#region src/vite/build.ts
620
- async function buildAsar({ version, asarOutputPath, gzipPath, electronDistPath, rendererDistPath, generateGzipFile }) {
621
- fs.renameSync(rendererDistPath, path.join(electronDistPath, "renderer"));
622
- fs.writeFileSync(path.join(electronDistPath, "version"), version);
623
- await createPackage(electronDistPath, asarOutputPath);
624
- const buf = await generateGzipFile(fs.readFileSync(asarOutputPath));
625
- fs.writeFileSync(gzipPath, buf);
626
- log.info(`Build update asar to '${gzipPath}' [${readableSize(buf.length)}]`, { timestamp: true });
627
- return buf;
628
- }
629
- async function buildUpdateJson({ versionPath, privateKey, cert, version, minimumVersion, generateSignature, generateUpdateJson }, asarBuffer) {
630
- let _json = {
631
- beta: {
632
- minimumVersion: version,
633
- signature: "",
634
- version
635
- },
636
- minimumVersion: version,
637
- signature: "",
638
- version
639
- };
640
- if (fs.existsSync(versionPath)) try {
641
- const oldVersionJson = JSON.parse(fs.readFileSync(versionPath, "utf-8"));
642
- if (isUpdateJSON(oldVersionJson)) _json = oldVersionJson;
643
- else log.warn("Old version json is invalid, ignore it", { timestamp: true });
644
- } catch {}
645
- const sig = await generateSignature(asarBuffer, privateKey, cert, version);
646
- _json = await generateUpdateJson(_json, sig, version, minimumVersion);
647
- if (!isUpdateJSON(_json)) throw new Error("Invalid update json");
648
- fs.writeFileSync(versionPath, JSON.stringify(_json, null, 2));
649
- log.info(`build update json to '${versionPath}'`, { timestamp: true });
650
- }
651
- async function buildEntry({ sourcemap, minify, files, outDir, ignoreDynamicRequires, external, vite }, isESM, define, bytecodeOptions) {
652
- await build$1({
653
- entry: files,
654
- vite: mergeConfig({
655
- plugins: [bytecodeOptions && bytecodePlugin("main", bytecodeOptions)],
656
- build: {
657
- sourcemap,
658
- minify,
659
- outDir,
660
- emptyOutDir: true,
661
- rolldownOptions: {
662
- external,
663
- platform: "node",
664
- output: {
665
- polyfillRequire: false,
666
- format: isESM ? "esm" : "cjs",
667
- dynamicImportInCjs: !ignoreDynamicRequires
668
- }
669
- }
670
- },
671
- define
672
- }, vite ?? {})
673
- });
674
- }
675
-
676
598
  //#endregion
677
599
  //#region src/vite/electron/plugin.ts
678
600
  /**
@@ -715,34 +637,6 @@ function notBundle(options = {}) {
715
637
  };
716
638
  }
717
639
 
718
- //#endregion
719
- //#region src/vite/electron/simple.ts
720
- async function electronSimple(options) {
721
- const flatApiOptions = [options.main];
722
- const esmodule = (await loadPackageJSON() ?? {}).type === "module";
723
- if (options.preload) {
724
- const { input, vite: viteConfig = {}, ...preloadOptions } = options.preload;
725
- const preload = {
726
- onstart(args) {
727
- args.reload();
728
- },
729
- ...preloadOptions,
730
- vite: mergeConfig({ build: { rolldownOptions: {
731
- input,
732
- output: {
733
- format: "cjs",
734
- inlineDynamicImports: true,
735
- entryFileNames: `[name].${esmodule ? "mjs" : "js"}`,
736
- chunkFileNames: `[name].${esmodule ? "mjs" : "js"}`,
737
- assetFileNames: "[name].[ext]"
738
- }
739
- } } }, viteConfig)
740
- };
741
- flatApiOptions.push(preload);
742
- }
743
- return electron(flatApiOptions);
744
- }
745
-
746
640
  //#endregion
747
641
  //#region src/utils/crypto.ts
748
642
  function hashBuffer(data, length) {
@@ -827,15 +721,8 @@ function parseSubjects(subject) {
827
721
 
828
722
  //#endregion
829
723
  //#region src/vite/option.ts
830
- async function parseOptions(isBuild, pkg, sourcemap = false, minify = false, entry = {}, options = {}) {
831
- const { minify: entryMinify, sourcemap: entrySourcemap, outDir = "dist-entry", files = "electron/entry.ts", postBuild, ignoreDynamicRequires = false, external = [
832
- /^node:.*/,
833
- /.*\.(node|dll|dylib|so)$/,
834
- "original-fs",
835
- "electron",
836
- ...isBuild || postBuild ? [] : Object.keys("dependencies" in pkg ? pkg.dependencies : {})
837
- ], vite = {} } = entry;
838
- const { minimumVersion = "0.0.0", paths: { asarOutputPath = `release/${pkg.name}.asar`, gzipPath = `release/${pkg.name}-${pkg.version}.asar.gz`, electronDistPath = "dist-electron", rendererDistPath = "dist", versionPath = "version.json" } = {}, keys: { privateKeyPath = "keys/private.pem", certPath = "keys/cert.pem", keyLength = 2048, certInfo: { subject = {
724
+ async function parseOptions(pkg, options = {}) {
725
+ const { minimumVersion = "0.0.0", paths: { asarOutputPath = `release/${pkg.name}.asar`, gzipPath = `release/${pkg.name}-${pkg.version}.asar.gz`, entryOutDir = "dist-entry", electronDistPath = "dist-electron", rendererDistPath = "dist", versionPath = "version.json" } = {}, keys: { privateKeyPath = "keys/private.pem", certPath = "keys/cert.pem", keyLength = 2048, certInfo: { subject = {
839
726
  commonName: pkg.name,
840
727
  organizationName: `org.${pkg.name}`
841
728
  }, days = 3650 } = {} } = {}, overrideGenerator: { generateGzipFile = defaultZipFile, generateSignature = defaultSignature, generateUpdateJson = defaultVersionJsonGenerator } = {} } = options;
@@ -847,15 +734,6 @@ async function parseOptions(isBuild, pkg, sourcemap = false, minify = false, ent
847
734
  rendererDistPath,
848
735
  generateGzipFile
849
736
  };
850
- const buildEntryOption = {
851
- minify: entryMinify ?? minify,
852
- sourcemap: entrySourcemap ?? sourcemap,
853
- outDir,
854
- files,
855
- vite,
856
- ignoreDynamicRequires,
857
- external
858
- };
859
737
  const { privateKey, cert } = await parseKeys({
860
738
  keyLength,
861
739
  privateKeyPath,
@@ -865,7 +743,6 @@ async function parseOptions(isBuild, pkg, sourcemap = false, minify = false, ent
865
743
  });
866
744
  return {
867
745
  buildAsarOption,
868
- buildEntryOption,
869
746
  buildVersionOption: {
870
747
  version: pkg.version,
871
748
  minimumVersion,
@@ -875,8 +752,8 @@ async function parseOptions(isBuild, pkg, sourcemap = false, minify = false, ent
875
752
  generateSignature,
876
753
  generateUpdateJson
877
754
  },
878
- postBuild,
879
- cert
755
+ cert,
756
+ entryOutDir
880
757
  };
881
758
  }
882
759
 
@@ -1022,151 +899,146 @@ function parseVersionPath(versionPath) {
1022
899
  async function electronWithUpdater(options) {
1023
900
  let { isBuild, entry: _entry, main: _main, preload: _preload, sourcemap = !isBuild, minify = isBuild, buildVersionJson, updater, bytecode, useNotBundle = true } = options;
1024
901
  const pkg = await loadPackageJSON();
1025
- if (!pkg || !pkg.version || !pkg.name || !pkg.main) {
1026
- log.error("package.json not found or invalid, must contains version, name and main field", { timestamp: true });
1027
- return;
1028
- }
902
+ if (!pkg || !pkg.version || !pkg.name || !pkg.main) throw new Error("package.json not found or invalid, must contains version, name and main field");
903
+ log.info(`Clear cache files`, { timestamp: true });
1029
904
  const isESM = pkg.type === "module";
905
+ const external = [
906
+ ...builtinModules,
907
+ "electron",
908
+ /^node:/,
909
+ /.*\.(node|dll|dylib|so)$/,
910
+ "original-fs",
911
+ ...isBuild || _entry.postBuild ? [] : Object.keys(pkg.dependencies || {})
912
+ ];
1030
913
  let bytecodeOptions = typeof bytecode === "object" ? bytecode : bytecode === true ? { enable: true } : void 0;
1031
914
  if (isESM && bytecodeOptions?.enable) throw new Error("`bytecodePlugin` does not support ES module, please remove \"type\": \"module\" in package.json");
1032
- const { buildAsarOption, buildEntryOption, buildVersionOption, postBuild, cert } = await parseOptions(isBuild, pkg, sourcemap, minify, _entry, updater);
1033
- const { outDir: entryOutputDirPath, files, external } = buildEntryOption;
915
+ const { buildAsarOption, buildVersionOption, cert, entryOutDir } = await parseOptions(pkg, updater);
916
+ sourcemap ??= isBuild || !!process.env.VSCODE_DEBUG;
1034
917
  try {
1035
918
  fs.rmSync(buildAsarOption.electronDistPath, {
1036
919
  recursive: true,
1037
920
  force: true
1038
921
  });
1039
- fs.rmSync(entryOutputDirPath, {
922
+ fs.rmSync(entryOutDir, {
1040
923
  recursive: true,
1041
924
  force: true
1042
925
  });
1043
926
  } catch {}
1044
- log.info(`Clear cache files`, { timestamp: true });
1045
- sourcemap ??= isBuild || !!process.env.VSCODE_DEBUG;
1046
- const _appPath = normalizePath(path.join(entryOutputDirPath, "entry.js"));
1047
- if (path.resolve(normalizePath(pkg.main)) !== path.resolve(_appPath)) throw new Error(`Wrong "main" field in package.json: "${pkg.main}", it should be "${_appPath}"`);
1048
927
  const define = {
1049
928
  __EIU_ASAR_BASE_NAME__: JSON.stringify(path.basename(buildAsarOption.asarOutputPath)),
1050
929
  __EIU_ELECTRON_DIST_PATH__: JSON.stringify(normalizePath(buildAsarOption.electronDistPath)),
1051
- __EIU_ENTRY_DIST_PATH__: JSON.stringify(normalizePath(buildEntryOption.outDir)),
930
+ __EIU_ENTRY_DIST_PATH__: JSON.stringify(normalizePath(entryOutDir)),
1052
931
  __EIU_IS_DEV__: JSON.stringify(!isBuild),
1053
932
  __EIU_IS_ESM__: JSON.stringify(isESM),
1054
933
  __EIU_MAIN_FILE__: JSON.stringify(getMainFileBaseName(_main.files)),
1055
934
  __EIU_SIGNATURE_CERT__: JSON.stringify(cert),
1056
935
  __EIU_VERSION_PATH__: JSON.stringify(parseVersionPath(normalizePath(buildVersionOption.versionPath)))
1057
936
  };
1058
- async function _buildEntry() {
1059
- await buildEntry(buildEntryOption, isESM, define, bytecodeOptions);
1060
- log.info(`Build entry to '${entryOutputDirPath}'`, { timestamp: true });
1061
- await postBuild?.({
1062
- isBuild,
1063
- getPathFromEntryOutputDir(...paths) {
1064
- return path.join(entryOutputDirPath, ...paths);
1065
- },
1066
- copyToEntryOutputDir({ from, to = path.basename(from), skipIfExist = true }) {
1067
- if (!fs.existsSync(from)) {
1068
- log.warn(`${from} not found`, { timestamp: true });
1069
- return;
937
+ const _electronOptions = [{
938
+ entry: _main.files,
939
+ onstart: async (args) => {
940
+ if (_main.onstart) await _main.onstart(args);
941
+ else await args.startup();
942
+ },
943
+ vite: mergeConfig({
944
+ plugins: [!isBuild && useNotBundle && notBundle(), bytecodeOptions && bytecodePlugin("main", bytecodeOptions)],
945
+ build: {
946
+ sourcemap,
947
+ minify,
948
+ outDir: `${buildAsarOption.electronDistPath}/main`,
949
+ rolldownOptions: {
950
+ external,
951
+ platform: "node",
952
+ output: {
953
+ cleanDir: true,
954
+ polyfillRequire: false
955
+ }
1070
956
  }
1071
- copyAndSkipIfExist(from, path.join(entryOutputDirPath, to), skipIfExist);
1072
957
  },
1073
- copyModules({ modules, skipIfExist = true }) {
1074
- const nodeModulesPath = path.join(entryOutputDirPath, "node_modules");
1075
- for (const m of modules) {
1076
- const { rootPath } = getPackageInfoSync(m) || {};
1077
- if (!rootPath) {
1078
- log.warn(`Package '${m}' not found`, { timestamp: true });
1079
- continue;
958
+ define
959
+ }, _main.vite ?? {})
960
+ }];
961
+ if (_preload?.files) _electronOptions.push({
962
+ onstart(args) {
963
+ args.reload();
964
+ },
965
+ vite: mergeConfig({
966
+ plugins: [bytecodeOptions && bytecodePlugin("preload", bytecodeOptions)],
967
+ build: {
968
+ sourcemap: sourcemap ? "inline" : void 0,
969
+ minify,
970
+ outDir: `${buildAsarOption.electronDistPath}/preload`,
971
+ rolldownOptions: {
972
+ external,
973
+ input: _preload.files,
974
+ output: {
975
+ format: "cjs",
976
+ inlineDynamicImports: true,
977
+ polyfillRequire: false,
978
+ entryFileNames: `[name].${isESM ? "mjs" : "js"}`,
979
+ chunkFileNames: `[name].${isESM ? "mjs" : "js"}`,
980
+ assetFileNames: "[name].[ext]"
1080
981
  }
1081
- copyAndSkipIfExist(rootPath, path.join(nodeModulesPath, m), skipIfExist);
1082
982
  }
1083
- }
1084
- });
1085
- }
1086
- let isInit = false;
1087
- const result = [electronSimple({
1088
- main: {
1089
- entry: _main.files,
1090
- onstart: async (args) => {
1091
- if (!isInit) {
1092
- isInit = true;
1093
- await _buildEntry();
1094
- }
1095
- if (_main.onstart) await _main.onstart(args);
1096
- else await args.startup();
1097
983
  },
1098
- vite: mergeConfig({
1099
- plugins: [!isBuild && useNotBundle && notBundle(), bytecodeOptions && bytecodePlugin("main", bytecodeOptions)],
1100
- build: {
1101
- sourcemap,
1102
- minify,
1103
- outDir: `${buildAsarOption.electronDistPath}/main`,
1104
- rolldownOptions: {
1105
- external,
1106
- output: {
1107
- polyfillRequire: false,
1108
- format: isESM ? "esm" : "cjs"
984
+ define
985
+ }, _preload?.vite ?? {})
986
+ });
987
+ _electronOptions.push({
988
+ entry: _entry.files,
989
+ vite: mergeConfig({
990
+ plugins: [bytecodeOptions && bytecodePlugin("main", bytecodeOptions), {
991
+ name: `${id}:entry`,
992
+ enforce: "post",
993
+ async closeBundle() {
994
+ log.info(`Build entry to '${entryOutDir}'`, { timestamp: true });
995
+ await _entry.postBuild?.({
996
+ isBuild,
997
+ getPathFromEntryOutputDir(...paths) {
998
+ return path.join(entryOutDir, ...paths);
999
+ },
1000
+ copyToEntryOutputDir({ from, to = path.basename(from), skipIfExist = true }) {
1001
+ if (!fs.existsSync(from)) {
1002
+ log.warn(`${from} not found`, { timestamp: true });
1003
+ return;
1004
+ }
1005
+ copyAndSkipIfExist(from, path.join(entryOutDir, to), skipIfExist);
1006
+ },
1007
+ copyModules({ modules, skipIfExist = true }) {
1008
+ const nodeModulesPath = path.join(entryOutDir, "node_modules");
1009
+ for (const m of modules) {
1010
+ const { rootPath } = getPackageInfoSync(m) || {};
1011
+ if (!rootPath) {
1012
+ log.warn(`Package '${m}' not found`, { timestamp: true });
1013
+ continue;
1014
+ }
1015
+ copyAndSkipIfExist(rootPath, path.join(nodeModulesPath, m), skipIfExist);
1016
+ }
1109
1017
  }
1110
- }
1111
- },
1112
- define
1113
- }, _main.vite ?? {})
1114
- },
1115
- preload: {
1116
- input: _preload.files,
1117
- vite: mergeConfig({
1118
- plugins: [bytecodeOptions && bytecodePlugin("preload", bytecodeOptions), {
1119
- name: `${id}-build`,
1120
- enforce: "post",
1121
- apply() {
1122
- return isBuild;
1123
- },
1124
- async closeBundle() {
1125
- await _buildEntry();
1018
+ });
1019
+ if (isBuild) try {
1126
1020
  const buffer = await buildAsar(buildAsarOption);
1127
1021
  if (!buildVersionJson && !isCI) log.warn("No `buildVersionJson` option setup, skip build version json. Only build in CI by default", { timestamp: true });
1128
1022
  else await buildUpdateJson(buildVersionOption, buffer);
1023
+ } catch (error) {
1024
+ console.error(error);
1129
1025
  }
1130
- }],
1131
- build: {
1132
- sourcemap: sourcemap ? "inline" : void 0,
1133
- minify,
1134
- outDir: `${buildAsarOption.electronDistPath}/preload`,
1135
- rolldownOptions: {
1136
- external,
1137
- output: { polyfillRequire: false }
1138
- }
1139
- },
1140
- define
1141
- }, _preload?.vite ?? {})
1142
- }
1143
- })];
1144
- if (files) {
1145
- const watchFiles = resolveInputToArray(files).map((file) => path.resolve(normalizePath(file)));
1146
- result.push({
1147
- name: `${id}-dev`,
1148
- apply() {
1149
- return !isBuild;
1026
+ }
1027
+ }],
1028
+ build: {
1029
+ sourcemap,
1030
+ minify,
1031
+ outDir: entryOutDir,
1032
+ rolldownOptions: {
1033
+ external,
1034
+ platform: "node",
1035
+ output: { polyfillRequire: false }
1036
+ }
1150
1037
  },
1151
- configureServer(server) {
1152
- server.watcher.add(watchFiles).on("change", async (p) => {
1153
- if (!watchFiles.includes(p)) return;
1154
- await _buildEntry();
1155
- if (_main.onstart) await _main.onstart({
1156
- startup,
1157
- reload: () => {
1158
- if (process.electronApp) {
1159
- (server.hot || server.ws).send({ type: "full-reload" });
1160
- startup.send("electron-vite&type=hot-reload");
1161
- } else startup();
1162
- }
1163
- });
1164
- else await startup();
1165
- });
1166
- }
1167
- });
1168
- }
1169
- return result;
1038
+ define
1039
+ }, _entry.vite || {})
1040
+ });
1041
+ return electron(isESM, _electronOptions);
1170
1042
  }
1171
1043
 
1172
1044
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electron-incremental-update",
3
- "version": "3.0.0-beta.2",
3
+ "version": "3.0.0-beta.3",
4
4
  "description": "Electron incremental update tools with Vite plugin, support bytecode protection",
5
5
  "keywords": [
6
6
  "bytecode",
@@ -65,7 +65,8 @@
65
65
  "test": "bun test",
66
66
  "test:dev": "bun test --watch",
67
67
  "format": "oxfmt",
68
- "lint": "oxlint --fix"
68
+ "lint": "oxlint --fix",
69
+ "qa": "oxlint --fix && oxfmt && tsc --noEmit"
69
70
  },
70
71
  "dependencies": {
71
72
  "@babel/plugin-transform-arrow-functions": "^7.27.1",