Skip to content

Commit 16283cc

Browse files
authored
fix: utilizing frameworkInfo as primary manner of fetching electron version for installation. (#7511)
1 parent d4c90b6 commit 16283cc

File tree

17 files changed

+754
-28
lines changed

17 files changed

+754
-28
lines changed

.changeset/new-cats-cross.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"app-builder-lib": patch
3+
"electron-builder": patch
4+
---
5+
6+
fix: utilizing frameworkInfo as primary manner of fetching electron version for installation. (fixes: #7494)

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ electron-builder-*.d.ts
2626

2727
tsconfig.tsbuildinfo
2828

29-
.pnpm-store/
29+
.pnpm-store/
30+
**/node_modules

packages/app-builder-lib/src/electron/ElectronFramework.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import BluebirdPromise from "bluebird-lst"
22
import { asArray, executeAppBuilder, log } from "builder-util"
33
import { CONCURRENCY, copyDir, DO_NOT_USE_HARD_LINKS, statOrNull, unlinkIfExists } from "builder-util/out/fs"
44
import { emptyDir, readdir, rename } from "fs-extra"
5-
import { Lazy } from "lazy-val"
65
import * as path from "path"
76
import { Configuration } from "../configuration"
87
import { BeforeCopyExtraFilesOptions, Framework, PrepareApplicationStageDirectoryOptions } from "../Framework"
@@ -155,7 +154,7 @@ export async function createElectronFrameworkSupport(configuration: Configuratio
155154
throw new Error(`Cannot compute electron version for prepacked asar`)
156155
}
157156
} else {
158-
version = await computeElectronVersion(packager.projectDir, new Lazy(() => Promise.resolve(packager.metadata)))
157+
version = await computeElectronVersion(packager.projectDir)
159158
}
160159
configuration.electronVersion = version
161160
}

packages/app-builder-lib/src/electron/electronVersion.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getProjectRootPath } from "@electron/rebuild/lib/src/search-module"
12
import { InvalidConfigurationError, log } from "builder-util"
23
import { parseXml } from "builder-util-runtime"
34
import { httpExecutor } from "builder-util/out/nodeHttpExecutor"
@@ -13,21 +14,17 @@ export type MetadataValue = Lazy<{ [key: string]: any } | null>
1314

1415
const electronPackages = ["electron", "electron-prebuilt", "electron-prebuilt-compile", "electron-nightly"]
1516

16-
export async function getElectronVersion(
17-
projectDir: string,
18-
config?: Configuration,
19-
projectMetadata: MetadataValue = new Lazy(() => orNullIfFileNotExist(readJson(path.join(projectDir, "package.json"))))
20-
): Promise<string> {
17+
export async function getElectronVersion(projectDir: string, config?: Configuration): Promise<string> {
2118
if (config == null) {
2219
config = await getConfig(projectDir, null, null)
2320
}
2421
if (config.electronVersion != null) {
2522
return config.electronVersion
2623
}
27-
return await computeElectronVersion(projectDir, projectMetadata)
24+
return computeElectronVersion(projectDir)
2825
}
2926

30-
export async function getElectronVersionFromInstalled(projectDir: string) {
27+
export async function getElectronVersionFromInstalled(projectDir: string): Promise<string | null> {
3128
for (const name of electronPackages) {
3229
try {
3330
return (await readJson(path.join(projectDir, "node_modules", name, "package.json"))).version
@@ -54,13 +51,21 @@ export async function getElectronPackage(projectDir: string) {
5451
}
5552

5653
/** @internal */
57-
export async function computeElectronVersion(projectDir: string, projectMetadata: MetadataValue): Promise<string> {
54+
export async function computeElectronVersion(projectDir: string): Promise<string> {
5855
const result = await getElectronVersionFromInstalled(projectDir)
5956
if (result != null) {
6057
return result
6158
}
6259

63-
const dependency = findFromPackageMetadata(await projectMetadata.value)
60+
const potentialRootDirs = [projectDir, await getProjectRootPath(projectDir)]
61+
let dependency: NameAndVersion | null = null
62+
for await (const dir of potentialRootDirs) {
63+
const metadata = await orNullIfFileNotExist(readJson(path.join(dir, "package.json")))
64+
dependency = metadata ? findFromPackageMetadata(metadata) : null
65+
if (dependency) {
66+
break
67+
}
68+
}
6469
if (dependency?.name === "electron-nightly") {
6570
log.info("You are using a nightly version of electron, be warned that those builds are highly unstable.")
6671
const feedXml = await httpExecutor.request({
@@ -95,7 +100,6 @@ export async function computeElectronVersion(projectDir: string, projectMetadata
95100

96101
throw new InvalidConfigurationError(`Cannot find electron dependency to get electron version in the '${path.join(projectDir, "package.json")}'`)
97102
}
98-
99103
const version = dependency?.version
100104
if (version == null || !/^\d/.test(version)) {
101105
const versionMessage = version == null ? "" : ` and version ("${version}") is not fixed in project`

packages/app-builder-lib/src/packager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ export class Packager {
495495
const frameworkInfo = { version: this.framework.version, useCustomDist: true }
496496
const config = this.config
497497
if (config.nodeGypRebuild === true) {
498-
await nodeGypRebuild(Arch[arch])
498+
await nodeGypRebuild(frameworkInfo, Arch[arch])
499499
}
500500

501501
if (config.npmRebuild === false) {

packages/app-builder-lib/src/util/yarn.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { homedir } from "os"
55
import * as path from "path"
66
import { Configuration } from "../configuration"
77
import { NodeModuleDirInfo } from "./packageDependencies"
8-
import { getElectronVersion } from "../electron/electronVersion"
98
import * as electronRebuild from "@electron/rebuild"
109
import * as searchModule from "@electron/rebuild/lib/src/search-module"
1110

@@ -26,7 +25,7 @@ export async function installOrRebuild(config: Configuration, appDir: string, op
2625
}
2726
await installDependencies(appDir, effectiveOptions)
2827
} else {
29-
await rebuild(appDir, config.buildDependenciesFromSource === true, options.arch)
28+
await rebuild(appDir, config.buildDependenciesFromSource === true, options.frameworkInfo, options.arch)
3029
}
3130
}
3231

@@ -119,8 +118,8 @@ function installDependencies(appDir: string, options: RebuildOptions): Promise<a
119118
})
120119
}
121120

122-
export async function nodeGypRebuild(arch: string) {
123-
return rebuild(process.cwd(), false, arch)
121+
export async function nodeGypRebuild(frameworkInfo: DesktopFrameworkInfo, arch: string) {
122+
return rebuild(process.cwd(), false, frameworkInfo, arch)
124123
}
125124

126125
function getPackageToolPath() {
@@ -149,15 +148,15 @@ export interface RebuildOptions {
149148
}
150149

151150
/** @internal */
152-
export async function rebuild(appDir: string, buildFromSource: boolean, arch = process.arch) {
153-
log.info({ appDir, arch }, "executing @electron/rebuild")
151+
export async function rebuild(appDir: string, buildFromSource: boolean, frameworkInfo: DesktopFrameworkInfo, arch = process.arch) {
152+
log.info({ arch, version: frameworkInfo.version, appDir }, "executing @electron/rebuild")
153+
const rootPath = await searchModule.getProjectRootPath(appDir)
154154
const options: electronRebuild.RebuildOptions = {
155155
buildPath: appDir,
156-
electronVersion: await getElectronVersion(appDir),
156+
electronVersion: frameworkInfo.version,
157157
arch,
158-
force: true,
159158
debug: log.isDebugEnabled,
160-
projectRootPath: await searchModule.getProjectRootPath(appDir),
159+
projectRootPath: rootPath,
161160
}
162161
if (buildFromSource) {
163162
options.prebuildTagPrefix = "totally-not-a-real-prefix-to-force-rebuild"

packages/electron-builder/src/cli/cli.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { createSelfSignedCert } from "./create-self-signed-cert"
1212
import { configureInstallAppDepsCommand, installAppDeps } from "./install-app-deps"
1313
import { start } from "./start"
1414
import { nodeGypRebuild } from "app-builder-lib/out/util/yarn"
15+
import { getElectronVersion } from "app-builder-lib/out/electron/electronVersion"
1516

1617
// tslint:disable:no-unused-expression
1718
void createYargs()
@@ -75,6 +76,7 @@ async function checkIsOutdated() {
7576
}
7677

7778
async function rebuildAppNativeCode(args: any) {
79+
const projectDir = process.cwd()
7880
// this script must be used only for electron
79-
return nodeGypRebuild(args.arch)
81+
return nodeGypRebuild({ version: await getElectronVersion(projectDir), useCustomDist: true }, args.arch)
8082
}

packages/electron-builder/src/cli/install-app-deps.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export async function installAppDeps(args: any) {
5252
projectDir,
5353
use(config.directories, it => it.app)
5454
),
55-
getElectronVersion(projectDir, config, packageMetadata),
55+
getElectronVersion(projectDir, config),
5656
])
5757

5858
// if two package.json — force full install (user wants to install/update app deps in addition to dev)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Hello World!</title>
6+
<script>
7+
const {ipcRenderer} = require("electron")
8+
function saveAppData() {
9+
ipcRenderer.send("saveAppData")
10+
}
11+
</script>
12+
</head>
13+
<body>
14+
<h1>Hello World!</h1>
15+
We are using node <script>document.write(process.versions.node)</script>,
16+
Chrome <script>document.write(process.versions.chrome)</script>,
17+
and Electron <script>document.write(process.versions.electron)</script>.
18+
19+
Args: <script>document.write("<br><br><pre>" + JSON.stringify(require("electron").remote.process.argv, null, 2) + "</pre>")</script>.
20+
21+
Env: <script>document.write("<br><br><pre>" + JSON.stringify(process.env, null, 2) + "</pre>")</script>.
22+
23+
<button onclick="saveAppData()">Save app data</button>
24+
</body>
25+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
'use strict'
2+
3+
const { app, ipcMain, BrowserWindow, Menu, Tray } = require("electron")
4+
const fs = require("fs")
5+
const path = require("path")
6+
7+
// Module to control application life.
8+
// Module to create native browser window.
9+
10+
// Keep a global reference of the window object, if you don't, the window will
11+
// be closed automatically when the JavaScript object is garbage collected.
12+
let mainWindow;
13+
14+
let tray = null
15+
16+
function createWindow () {
17+
if (process.platform === "linux" && process.env.APPDIR != null) {
18+
tray = new Tray(path.join(process.env.APPDIR, "testapp.png"))
19+
const contextMenu = Menu.buildFromTemplate([
20+
{label: 'Item1', type: 'radio'},
21+
{label: 'Item2', type: 'radio'},
22+
{label: 'Item3', type: 'radio', checked: true},
23+
{label: 'Item4', type: 'radio'}
24+
])
25+
tray.setToolTip('This is my application.')
26+
tray.setContextMenu(contextMenu)
27+
}
28+
29+
// Create the browser window.
30+
mainWindow = new BrowserWindow({width: 800, height: 600});
31+
32+
// and load the index.html of the app.
33+
mainWindow.loadURL('file://' + __dirname + '/index.html');
34+
35+
// Open the DevTools.
36+
mainWindow.webContents.openDevTools();
37+
38+
mainWindow.webContents.executeJavaScript(`console.log("appData: ${app.getPath("appData").replace(/\\/g, "\\\\")}")`)
39+
mainWindow.webContents.executeJavaScript(`console.log("userData: ${app.getPath("userData").replace(/\\/g, "\\\\")}")`)
40+
41+
// Emitted when the window is closed.
42+
mainWindow.on('closed', function() {
43+
// Dereference the window object, usually you would store windows
44+
// in an array if your app supports multi windows, this is the time
45+
// when you should delete the corresponding element.
46+
mainWindow = null;
47+
});
48+
}
49+
50+
// This method will be called when Electron has finished
51+
// initialization and is ready to create browser windows.
52+
app.on('ready', createWindow);
53+
54+
// Quit when all windows are closed.
55+
app.on('window-all-closed', function () {
56+
// On MacOS it is common for applications and their menu bar
57+
// to stay active until the user quits explicitly with Cmd + Q
58+
if (process.platform !== 'darwin') {
59+
app.quit();
60+
}
61+
});
62+
63+
app.on("activate", function () {
64+
if (mainWindow === null) {
65+
createWindow()
66+
}
67+
})
68+
69+
ipcMain.on("saveAppData", () => {
70+
try {
71+
// electron doesn't escape / in the product name
72+
fs.writeFileSync(path.join(app.getPath("appData"), "Test App ßW", "testFile"), "test")
73+
}
74+
catch (e) {
75+
mainWindow.webContents.executeJavaScript(`console.log(\`userData: ${e}\`)`)
76+
}
77+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "test-app-two-native-modules",
3+
"main": "index.js",
4+
"version": "1.1.1",
5+
"dependencies": {
6+
"install": "0.13.0"
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
6+
version "0.13.0"
7+
resolved "https://registry.yarnpkg.com/install/-/install-0.13.0.tgz#6af6e9da9dd0987de2ab420f78e60d9c17260776"
8+
integrity sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"private": true,
3+
"name": "TestApp2",
4+
"productName": "Test App ßW2",
5+
"version": "1.1.0",
6+
"homepage": "http://foo.example.com",
7+
"description": "Test Application (test quite \" #378)",
8+
"author": "Foo Bar <[email protected]>",
9+
"license": "MIT",
10+
"devDependencies": {
11+
"electron": "23.2.0"
12+
},
13+
"build": {
14+
"appId": "org.electron-builder.testApp2",
15+
"compression": "store",
16+
"npmRebuild": true,
17+
"directories": {
18+
"app": "app"
19+
},
20+
"files": [
21+
"index.html",
22+
"index.js",
23+
"package.json"
24+
],
25+
"mac": {
26+
"category": "your.app.category.type"
27+
},
28+
"linux": {
29+
"category": "Development"
30+
},
31+
"deb": {
32+
"packageCategory": "devel"
33+
},
34+
"squirrelWindows": {
35+
"iconUrl": "https://raw.githubusercontent.com/szwacz/electron-boilerplate/master/resources/windows/icon.ico"
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)