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

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.
@@ -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
@@ -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
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-C-qmVhAt.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-BJCk7uxG.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-C-qmVhAt.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-BJCk7uxG.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
  /**
@@ -38,27 +34,17 @@ interface ElectronOptions {
38
34
  /**
39
35
  * Electron App startup function.
40
36
  * It will mount the Electron App child-process to `process.electronApp`.
41
- * @param argv default value `['.', '--no-sandbox']`
42
- * @param options options for `child_process.spawn`
43
- * @param customElectronPkg custom electron package name (default: 'electron')
37
+ * - argv: electron startup arguments (default `['.', '--no-sandbox']`)
38
+ * - options: options for `child_process.spawn`
39
+ * - customElectronPkg: custom electron package name (default: `'electron'`)
44
40
  */
45
41
  startup: (argv?: string[], options?: SpawnOptions, customElectronPkg?: string) => Promise<void>; /** Reload Electron-Renderer */
46
42
  reload: () => void;
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;
@@ -149,8 +141,14 @@ interface ElectronWithUpdaterOptions {
149
141
  */
150
142
  isBuild: boolean;
151
143
  /**
144
+ * Project root directory. Can be an absolute path, or a path relative from
145
+ * the location of the config file itself.
146
+ * @default process.cwd()
147
+ */
148
+ root?: string;
149
+ /**
152
150
  * Whether to generate sourcemap
153
- * @default !isBuild
151
+ * @default !isBuild || !!process.env.VSCODE_DEBUG
154
152
  */
155
153
  sourcemap?: boolean;
156
154
  /**
@@ -177,19 +175,73 @@ interface ElectronWithUpdaterOptions {
177
175
  */
178
176
  buildVersionJson?: boolean;
179
177
  /**
178
+ * Addtional `external` option in `build.rolldownOptions`,
179
+ *
180
+ * If is in dev and `entry.postBuild` is not setup,
181
+ * external `dependencies` in `package.json` by default
182
+ */
183
+ external?: (string | RegExp)[];
184
+ /**
180
185
  * Options for entry (app.asar)
186
+ *
187
+ * To change output directories, use `options.updater.paths.electronDistPath` instead
181
188
  */
182
- entry?: BuildEntryOption;
189
+ entry: {
190
+ /**
191
+ * By default, all the unbundled modules will be packaged by packager like `electron-builder`.
192
+ * If setup, all the `dependencies` in `package.json` will be bundled by default, and you need
193
+ * to manually handle the native module files.
194
+ *
195
+ * If you are using `electron-buidler`, don't forget to append `'!node_modules/**'` in
196
+ * electron-build config's `files` array
197
+ */
198
+ postBuild?: (args: {
199
+ /**
200
+ * Whether is in build mode
201
+ */
202
+ isBuild: boolean;
203
+ /**
204
+ * Get path from `entryOutputDirPath`
205
+ */
206
+ getPathFromEntryOutputDir: (...paths: string[]) => string;
207
+ /**
208
+ * Check exist and copy file to `entryOutputDirPath`
209
+ *
210
+ * If `to` absent, set to `basename(from)`
211
+ *
212
+ * If `skipIfExist` absent, skip copy if `to` exist
213
+ */
214
+ copyToEntryOutputDir: (options: {
215
+ from: string;
216
+ to?: string;
217
+ /**
218
+ * Skip copy if `to` exist
219
+ * @default true
220
+ */
221
+ skipIfExist?: boolean;
222
+ }) => void;
223
+ /**
224
+ * Copy specified modules to entry output dir, just like `external` option in rolldown
225
+ */
226
+ copyModules: (options: {
227
+ /**
228
+ * External Modules
229
+ */
230
+ modules: string[];
231
+ /**
232
+ * Skip copy if `to` exist
233
+ * @default true
234
+ */
235
+ skipIfExist?: boolean;
236
+ }) => void;
237
+ }) => Promisable<void>;
238
+ } & CommonBuildOption;
183
239
  /**
184
240
  * Main process options
185
241
  *
186
242
  * To change output directories, use `options.updater.paths.electronDistPath` instead
187
243
  */
188
244
  main: {
189
- /**
190
- * Shortcut of `build.rolldownOptions.input`
191
- */
192
- files: NonNullable<ElectronOptions["entry"]>;
193
245
  /**
194
246
  * Electron App startup function.
195
247
  *
@@ -199,125 +251,18 @@ interface ElectronWithUpdaterOptions {
199
251
  * @param customElectronPkg custom electron package name (default: 'electron')
200
252
  */
201
253
  onstart?: ElectronOptions["onstart"];
202
- } & ViteOverride;
254
+ } & CommonBuildOption;
203
255
  /**
204
256
  * Preload process options
205
257
  *
206
258
  * To change output directories, use `options.updater.paths.electronDistPath` instead
207
259
  */
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;
260
+ preload?: CommonBuildOption;
216
261
  /**
217
262
  * Updater options
218
263
  */
219
264
  updater?: UpdaterOptions;
220
265
  }
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
266
  interface GeneratorOverrideFunctions {
322
267
  /**
323
268
  * Custom signature generate function
@@ -358,6 +303,11 @@ interface UpdaterOptions {
358
303
  */
359
304
  asarOutputPath?: string;
360
305
  /**
306
+ * Path to app entry output file
307
+ * @default 'dist-entry'
308
+ */
309
+ entryOutDir?: string;
310
+ /**
361
311
  * Path to version info output, content is {@link UpdateJSON}
362
312
  * @default `version.json`
363
313
  */
@@ -427,6 +377,17 @@ interface UpdaterOptions {
427
377
  }
428
378
  //#endregion
429
379
  //#region src/vite/core.d.ts
380
+ interface ElectronSimpleOptions {
381
+ main: ElectronOptions;
382
+ preload?: Omit<ElectronOptions, "entry"> & {
383
+ /**
384
+ * Shortcut of `build.rolldownOptions.input`.
385
+ *
386
+ * Preload scripts may contain Web assets, so use the `build.rolldownOptions.input` instead `build.lib.entry`.
387
+ */
388
+ input: RolldownOptions["input"];
389
+ };
390
+ }
430
391
  type StartupFn = NonNullable<NonNullable<ElectronSimpleOptions["main"]>["onstart"]>;
431
392
  /**
432
393
  * Startup function for debug
@@ -527,7 +488,7 @@ interface ElectronViteHelperOptions extends MakeOptional<ElectronWithUpdaterOpti
527
488
  /**
528
489
  * Config for renderer process
529
490
  */
530
- renderer?: UserConfig;
491
+ renderer?: Omit<UserConfig, "root">;
531
492
  }
532
493
  /**
533
494
  * Vite config helper
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,96 +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
- /** @see https://github.com/vitejs/vite/blob/v5.4.9/packages/vite/src/node/build.ts#L489-L504 */
428
- function resolveInput(config) {
429
- const options = config.build;
430
- const { root } = config;
431
- const libOptions = options.lib;
432
- const resolve = (p) => path.resolve(root, p);
433
- const input = libOptions ? options.rolldownOptions?.input || (typeof libOptions.entry === "string" ? resolve(libOptions.entry) : Array.isArray(libOptions.entry) ? libOptions.entry.map(resolve) : Object.fromEntries(Object.entries(libOptions.entry).map(([alias, file]) => [alias, resolve(file)]))) : options.rolldownOptions?.input;
434
- if (input) return input;
435
- const indexHtml = resolve("index.html");
436
- return fs.existsSync(indexHtml) ? indexHtml : void 0;
437
- }
438
- /**
439
- * When run the `vite build` command, there must be an entry file.
440
- * If the user does not need Renderer, we need to create a temporary entry file to avoid Vite throw error.
441
- * @see https://github.com/vitejs/vite/blob/v5.4.9/packages/vite/src/node/config.ts#L1234-L1236
442
- */
443
- async function mockIndexHtml(config) {
444
- const { root, build } = config;
445
- const output = path.resolve(root, build.outDir);
446
- const content = `
447
- <!doctype html>
448
- <html lang="en">
449
- <head>
450
- <title>vite-plugin-electron</title>
451
- </head>
452
- <body>
453
- <div>An entry file for electron renderer process.</div>
454
- </body>
455
- </html>
456
- `.trim();
457
- const index = "index.html";
458
- const filepath = path.join(root, index);
459
- const distpath = path.join(output, index);
460
- await fs.promises.writeFile(filepath, content);
461
- return {
462
- async remove() {
463
- await fs.promises.unlink(filepath);
464
- await fs.promises.unlink(distpath);
465
- },
466
- filepath,
467
- distpath
468
- };
469
- }
470
407
  /**
471
408
  * Inspired `tree-kill`, implemented based on sync-api. #168
472
409
  * @see https://github.com/pkrumins/node-tree-kill/blob/v1.2.2/index.js
@@ -498,29 +435,35 @@ function killTree(tree) {
498
435
 
499
436
  //#endregion
500
437
  //#region src/vite/electron/core.ts
501
- function build$1(options) {
502
- return build(withExternalBuiltins(resolveViteConfig(options)));
438
+ function build$1(isESM, options) {
439
+ return build(resolveViteConfig(isESM, options));
503
440
  }
504
- function electron(options) {
441
+ function electron(isESM, root, options) {
505
442
  const optionsArray = Array.isArray(options) ? options : [options];
506
443
  let userConfig;
507
444
  let configEnv;
508
- let mockdInput;
509
445
  if (!version.startsWith("8.")) throw new Error(`[vite-plugin-electron] Vite v${version} does not support \`rolldownOptions\`, please install \`vite@>=8\` or use an earlier version of \`vite-plugin-electron\`.`);
446
+ async function parallelBuild(options) {
447
+ await Promise.all(options.map(build$1.bind(build$1, isESM)));
448
+ }
510
449
  return [{
511
450
  name: "vite-plugin-electron:dev",
512
451
  apply: "serve",
452
+ configResolved(config) {
453
+ if (config.root !== root) throw new Error(`Renderer's root (${config.root}) is not same as electron's root (${root}). Please setup \`root\` in electron plugin`);
454
+ },
513
455
  configureServer(server) {
514
456
  server.httpServer?.once("listening", () => {
515
- Object.assign(process.env, { VITE_DEV_SERVER_URL: resolveServerUrl(server) });
457
+ Object.assign(process.env, { VITE_DEV_SERVER_URL: server.resolvedUrls?.local[0] });
516
458
  const entryCount = optionsArray.length;
517
459
  let closeBundleCount = 0;
518
- for (const options of optionsArray) {
460
+ parallelBuild(optionsArray.map((options) => {
519
461
  options.vite ??= {};
520
462
  options.vite.mode ??= server.config.mode;
521
463
  options.vite.root ??= server.config.root;
522
464
  options.vite.envDir ??= server.config.envDir;
523
465
  options.vite.envPrefix ??= server.config.envPrefix;
466
+ const defaultArgs = [options.vite.root || ".", "--no-sandbox"];
524
467
  options.vite.build ??= {};
525
468
  if (!Object.keys(options.vite.build).includes("watch")) options.vite.build.watch = {};
526
469
  options.vite.build.minify ??= false;
@@ -530,19 +473,21 @@ function electron(options) {
530
473
  closeBundle() {
531
474
  if (++closeBundleCount < entryCount) return;
532
475
  if (options.onstart) options.onstart.call(this, {
533
- startup,
476
+ async startup(args = defaultArgs, ...opt) {
477
+ await startup(args, ...opt);
478
+ },
534
479
  reload() {
535
480
  if (process.electronApp) {
536
481
  (server.hot || server.ws).send({ type: "full-reload" });
537
482
  startup.send("electron-vite&type=hot-reload");
538
- } else startup();
483
+ } else startup(defaultArgs);
539
484
  }
540
485
  });
541
- else startup();
486
+ else startup(defaultArgs);
542
487
  }
543
488
  });
544
- build$1(options);
545
- }
489
+ return options;
490
+ }));
546
491
  });
547
492
  }
548
493
  }, {
@@ -553,19 +498,15 @@ function electron(options) {
553
498
  configEnv = env;
554
499
  config.base ??= "./";
555
500
  },
556
- async configResolved(config) {
557
- if (resolveInput(config) == null) mockdInput = await mockIndexHtml(config);
558
- },
559
501
  async closeBundle() {
560
- mockdInput?.remove();
561
- for (const options of optionsArray) {
502
+ await parallelBuild(optionsArray.map((options) => {
562
503
  options.vite ??= {};
563
504
  options.vite.mode ??= configEnv.mode;
564
505
  options.vite.root ??= userConfig.root;
565
506
  options.vite.envDir ??= userConfig.envDir;
566
507
  options.vite.envPrefix ??= userConfig.envPrefix;
567
- await build$1(options);
568
- }
508
+ return options;
509
+ }));
569
510
  }
570
511
  }];
571
512
  }
@@ -615,64 +556,6 @@ startup.exit = async () => {
615
556
  });
616
557
  };
617
558
 
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
559
  //#endregion
677
560
  //#region src/vite/electron/plugin.ts
678
561
  /**
@@ -715,34 +598,6 @@ function notBundle(options = {}) {
715
598
  };
716
599
  }
717
600
 
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
601
  //#endregion
747
602
  //#region src/utils/crypto.ts
748
603
  function hashBuffer(data, length) {
@@ -827,15 +682,8 @@ function parseSubjects(subject) {
827
682
 
828
683
  //#endregion
829
684
  //#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 = {
685
+ async function parseUpdaterOption(pkg, options = {}) {
686
+ 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
687
  commonName: pkg.name,
840
688
  organizationName: `org.${pkg.name}`
841
689
  }, days = 3650 } = {} } = {}, overrideGenerator: { generateGzipFile = defaultZipFile, generateSignature = defaultSignature, generateUpdateJson = defaultVersionJsonGenerator } = {} } = options;
@@ -847,15 +695,6 @@ async function parseOptions(isBuild, pkg, sourcemap = false, minify = false, ent
847
695
  rendererDistPath,
848
696
  generateGzipFile
849
697
  };
850
- const buildEntryOption = {
851
- minify: entryMinify ?? minify,
852
- sourcemap: entrySourcemap ?? sourcemap,
853
- outDir,
854
- files,
855
- vite,
856
- ignoreDynamicRequires,
857
- external
858
- };
859
698
  const { privateKey, cert } = await parseKeys({
860
699
  keyLength,
861
700
  privateKeyPath,
@@ -865,7 +704,6 @@ async function parseOptions(isBuild, pkg, sourcemap = false, minify = false, ent
865
704
  });
866
705
  return {
867
706
  buildAsarOption,
868
- buildEntryOption,
869
707
  buildVersionOption: {
870
708
  version: pkg.version,
871
709
  minimumVersion,
@@ -875,8 +713,8 @@ async function parseOptions(isBuild, pkg, sourcemap = false, minify = false, ent
875
713
  generateSignature,
876
714
  generateUpdateJson
877
715
  },
878
- postBuild,
879
- cert
716
+ cert,
717
+ entryOutDir
880
718
  };
881
719
  }
882
720
 
@@ -973,6 +811,13 @@ function parseVersionPath(versionPath) {
973
811
  if (!versionPath.startsWith("./")) versionPath = `./${versionPath}`;
974
812
  return new URL(versionPath, "file://").pathname.slice(1);
975
813
  }
814
+ const defaultExternal = [
815
+ ...builtinModules,
816
+ "electron",
817
+ /^node:/,
818
+ /.*\.(node|dll|dylib|so)$/,
819
+ "original-fs"
820
+ ];
976
821
  /**
977
822
  * Base on `./electron/simple`
978
823
  * - integrate with updater
@@ -1020,153 +865,135 @@ function parseVersionPath(versionPath) {
1020
865
  * ```
1021
866
  */
1022
867
  async function electronWithUpdater(options) {
1023
- let { isBuild, entry: _entry, main: _main, preload: _preload, sourcemap = !isBuild, minify = isBuild, buildVersionJson, updater, bytecode, useNotBundle = true } = options;
1024
- 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
- }
868
+ let { isBuild, root = process.cwd(), external, entry: _entry, main: _main, preload: _preload, sourcemap = !isBuild || !!process.env.VSCODE_DEBUG, minify = isBuild, buildVersionJson, updater, bytecode, useNotBundle = true } = options;
869
+ const pkg = await loadPackageJSON(root);
870
+ if (!pkg || !pkg.version || !pkg.name || !pkg.main) throw new Error("package.json not found or invalid, must contains version, name and main field");
1029
871
  const isESM = pkg.type === "module";
872
+ const finalExternal = [...defaultExternal, ...isBuild || _entry.postBuild ? [] : external || Object.keys(pkg.dependencies || {})];
1030
873
  let bytecodeOptions = typeof bytecode === "object" ? bytecode : bytecode === true ? { enable: true } : void 0;
1031
874
  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;
1034
- try {
1035
- fs.rmSync(buildAsarOption.electronDistPath, {
1036
- recursive: true,
1037
- force: true
1038
- });
1039
- fs.rmSync(entryOutputDirPath, {
1040
- recursive: true,
1041
- force: true
1042
- });
1043
- } catch {}
875
+ const { buildAsarOption, buildVersionOption, cert, entryOutDir } = await parseUpdaterOption(pkg, updater);
1044
876
  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}"`);
877
+ await Promise.all([fs.promises.rm(buildAsarOption.electronDistPath, {
878
+ recursive: true,
879
+ force: true
880
+ }), fs.promises.rm(entryOutDir, {
881
+ recursive: true,
882
+ force: true
883
+ })]).catch(() => {});
1048
884
  const define = {
1049
885
  __EIU_ASAR_BASE_NAME__: JSON.stringify(path.basename(buildAsarOption.asarOutputPath)),
1050
886
  __EIU_ELECTRON_DIST_PATH__: JSON.stringify(normalizePath(buildAsarOption.electronDistPath)),
1051
- __EIU_ENTRY_DIST_PATH__: JSON.stringify(normalizePath(buildEntryOption.outDir)),
887
+ __EIU_ENTRY_DIST_PATH__: JSON.stringify(normalizePath(entryOutDir)),
1052
888
  __EIU_IS_DEV__: JSON.stringify(!isBuild),
1053
889
  __EIU_IS_ESM__: JSON.stringify(isESM),
1054
890
  __EIU_MAIN_FILE__: JSON.stringify(getMainFileBaseName(_main.files)),
1055
891
  __EIU_SIGNATURE_CERT__: JSON.stringify(cert),
1056
892
  __EIU_VERSION_PATH__: JSON.stringify(parseVersionPath(normalizePath(buildVersionOption.versionPath)))
1057
893
  };
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;
894
+ const _electronOptions = [{
895
+ entry: _main.files,
896
+ onstart: _main.onstart,
897
+ vite: mergeConfig({
898
+ plugins: [!isBuild && useNotBundle && notBundle(), bytecodeOptions && bytecodePlugin("main", bytecodeOptions)],
899
+ build: {
900
+ sourcemap,
901
+ minify,
902
+ outDir: `${buildAsarOption.electronDistPath}/main`,
903
+ rolldownOptions: {
904
+ external: finalExternal,
905
+ platform: "node",
906
+ output: { polyfillRequire: false }
1070
907
  }
1071
- copyAndSkipIfExist(from, path.join(entryOutputDirPath, to), skipIfExist);
1072
908
  },
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;
909
+ define
910
+ }, _main.vite ?? {})
911
+ }];
912
+ if (_preload?.files) _electronOptions.push({
913
+ onstart(args) {
914
+ args.reload();
915
+ },
916
+ vite: mergeConfig({
917
+ plugins: [bytecodeOptions && bytecodePlugin("preload", bytecodeOptions)],
918
+ build: {
919
+ sourcemap: sourcemap ? "inline" : void 0,
920
+ minify,
921
+ outDir: `${buildAsarOption.electronDistPath}/preload`,
922
+ rolldownOptions: {
923
+ external: finalExternal,
924
+ input: _preload.files,
925
+ output: {
926
+ format: "cjs",
927
+ inlineDynamicImports: true,
928
+ polyfillRequire: false,
929
+ entryFileNames: `[name].${isESM ? "mjs" : "js"}`,
930
+ chunkFileNames: `[name].${isESM ? "mjs" : "js"}`,
931
+ assetFileNames: "[name].[ext]"
1080
932
  }
1081
- copyAndSkipIfExist(rootPath, path.join(nodeModulesPath, m), skipIfExist);
1082
- }
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
933
  }
1095
- if (_main.onstart) await _main.onstart(args);
1096
- else await args.startup();
1097
934
  },
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"
1109
- }
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`,
935
+ define
936
+ }, _preload?.vite ?? {})
937
+ });
938
+ _electronOptions.push({
939
+ entry: _entry.files,
940
+ vite: mergeConfig({
941
+ plugins: [
942
+ bytecodeOptions && bytecodePlugin("main", bytecodeOptions),
943
+ !isBuild && useNotBundle && notBundle(),
944
+ {
945
+ name: `${id}:entry`,
1120
946
  enforce: "post",
1121
- apply() {
1122
- return isBuild;
1123
- },
1124
947
  async closeBundle() {
1125
- await _buildEntry();
1126
- const buffer = await buildAsar(buildAsarOption);
1127
- if (!buildVersionJson && !isCI) log.warn("No `buildVersionJson` option setup, skip build version json. Only build in CI by default", { timestamp: true });
1128
- else await buildUpdateJson(buildVersionOption, buffer);
1129
- }
1130
- }],
1131
- build: {
1132
- sourcemap: sourcemap ? "inline" : void 0,
1133
- minify,
1134
- outDir: `${buildAsarOption.electronDistPath}/preload`,
1135
- rolldownOptions: {
1136
- external,
1137
- output: { polyfillRequire: false }
948
+ log.info(`Build entry to '${entryOutDir}'`, { timestamp: true });
949
+ await _entry.postBuild?.({
950
+ isBuild,
951
+ getPathFromEntryOutputDir(...paths) {
952
+ return path.join(entryOutDir, ...paths);
953
+ },
954
+ copyToEntryOutputDir({ from, to = path.basename(from), skipIfExist = true }) {
955
+ if (!fs.existsSync(from)) {
956
+ log.warn(`${from} not found`, { timestamp: true });
957
+ return;
958
+ }
959
+ copyAndSkipIfExist(from, path.join(entryOutDir, to), skipIfExist);
960
+ },
961
+ copyModules({ modules, skipIfExist = true }) {
962
+ const nodeModulesPath = path.join(entryOutDir, "node_modules");
963
+ for (const m of modules) {
964
+ const { rootPath } = getPackageInfoSync(m) || {};
965
+ if (!rootPath) {
966
+ log.warn(`Package '${m}' not found`, { timestamp: true });
967
+ continue;
968
+ }
969
+ copyAndSkipIfExist(rootPath, path.join(nodeModulesPath, m), skipIfExist);
970
+ }
971
+ }
972
+ });
973
+ if (isBuild) try {
974
+ const buffer = await buildAsar(buildAsarOption);
975
+ if (!buildVersionJson && !isCI) log.warn("No `buildVersionJson` option setup, skip build version json. Only build in CI by default", { timestamp: true });
976
+ else await buildUpdateJson(buildVersionOption, buffer);
977
+ } catch (error) {
978
+ console.error(error);
979
+ }
1138
980
  }
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;
981
+ }
982
+ ],
983
+ build: {
984
+ sourcemap,
985
+ minify,
986
+ outDir: entryOutDir,
987
+ rolldownOptions: {
988
+ external: finalExternal,
989
+ platform: "node",
990
+ output: { polyfillRequire: false }
991
+ }
1150
992
  },
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;
993
+ define
994
+ }, _entry.vite || {})
995
+ });
996
+ return electron(isESM, normalizePath(path.resolve(root)), _electronOptions);
1170
997
  }
1171
998
 
1172
999
  //#endregion
@@ -1209,6 +1036,7 @@ function defineElectronConfig(options) {
1209
1036
  const result = options.renderer ?? {};
1210
1037
  result.plugins ??= [];
1211
1038
  result.plugins.push(electronPlugin);
1039
+ result.root = options.root;
1212
1040
  const rendererDistPath = options.updater?.paths?.rendererDistPath;
1213
1041
  if (rendererDistPath) {
1214
1042
  result.build ??= {};
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.4",
4
4
  "description": "Electron incremental update tools with Vite plugin, support bytecode protection",
5
5
  "keywords": [
6
6
  "bytecode",
@@ -60,12 +60,13 @@
60
60
  "scripts": {
61
61
  "dev": "tsdown --watch",
62
62
  "build": "tsdown",
63
- "play": "cd ./playground && vite",
63
+ "play": "vite",
64
64
  "release": "bun run format && bun run lint && bun run test && bun run build && bumpp --all",
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",