Skip to content

Commit 193abcf

Browse files
authored
chore(deps): update electron/rebuild to resolve node-gyp dependency issue (#9285)
1 parent 9f06a85 commit 193abcf

File tree

9 files changed

+407
-308
lines changed

9 files changed

+407
-308
lines changed

.changeset/serious-rings-build.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"app-builder-lib": patch
3+
---
4+
5+
chore(deps): update electron/rebuild to resolve node-gyp dependency issue
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
if (!process.send) {
2+
console.error("The remote rebuilder expects to be spawned with an IPC channel")
3+
process.exit(1)
4+
}
5+
6+
const rebuilder = (rebuilder) => {
7+
rebuilder.lifecycle.on("module-found", (moduleName) => process.send?.({ msg: "module-found", moduleName }))
8+
rebuilder.lifecycle.on("module-done", (moduleName) => process.send?.({ msg: "module-done", moduleName }))
9+
rebuilder.lifecycle.on("module-skip", (moduleName) => process.send?.({ msg: "module-skip", moduleName }))
10+
11+
return rebuilder
12+
.then(() => {
13+
process.send?.({ msg: "rebuild-done" })
14+
return process.exit(0)
15+
})
16+
.catch((err) => {
17+
process.send?.({
18+
msg: "rebuild-error",
19+
err: {
20+
message: err.message,
21+
stack: err.stack,
22+
},
23+
})
24+
process.exit(0)
25+
})
26+
}
27+
28+
const main = () => {
29+
const options = JSON.parse(process.argv[2])
30+
31+
const dynamicImport = require("./dynamic-import").dynamicImportMaybe
32+
return dynamicImport("@electron/rebuild").then((module) => {
33+
const { rebuild } = module
34+
return rebuilder(rebuild(options))
35+
})
36+
}
37+
38+
main()

packages/app-builder-lib/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"@electron/fuses": "^1.8.0",
5353
"@electron/notarize": "2.5.0",
5454
"@electron/osx-sign": "1.3.3",
55-
"@electron/rebuild": "3.7.2",
55+
"@electron/rebuild": "4.0.1",
5656
"@electron/universal": "2.0.3",
5757
"@malept/flatpak-bundler": "^0.4.0",
5858
"@types/fs-extra": "9.0.13",

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { getProjectRootPath } from "@electron/rebuild/lib/search-module"
2-
31
import { httpExecutor, InvalidConfigurationError, log } from "builder-util"
42
import { parseXml } from "builder-util-runtime"
53
import { readJson } from "fs-extra"
@@ -9,6 +7,7 @@ import * as semver from "semver"
97
import { Configuration } from "../configuration"
108
import { getConfig } from "../util/config/config"
119
import { orNullIfFileNotExist } from "../util/config/load"
10+
import { getProjectRootPath } from "./search-module"
1211

1312
export type MetadataValue = Lazy<Record<string, any> | null>
1413

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import * as fs from "fs-extra"
2+
import * as path from "node:path"
3+
4+
async function shouldContinueSearch(traversedPath: string, rootPath?: string, stopAtPackageJSON?: boolean): Promise<boolean> {
5+
if (rootPath) {
6+
return Promise.resolve(traversedPath !== path.dirname(rootPath))
7+
} else if (stopAtPackageJSON) {
8+
return fs.existsSync(path.join(traversedPath, "package.json"))
9+
} else {
10+
return true
11+
}
12+
}
13+
14+
type PathGeneratorFunction = (traversedPath: string) => string
15+
16+
async function traverseAncestorDirectories(
17+
cwd: string,
18+
pathGenerator: PathGeneratorFunction,
19+
rootPath?: string,
20+
maxItems?: number,
21+
stopAtPackageJSON?: boolean
22+
): Promise<string[]> {
23+
const paths: string[] = []
24+
let traversedPath = path.resolve(cwd)
25+
26+
while (await shouldContinueSearch(traversedPath, rootPath, stopAtPackageJSON)) {
27+
const generatedPath = pathGenerator(traversedPath)
28+
if (fs.existsSync(generatedPath)) {
29+
paths.push(generatedPath)
30+
}
31+
32+
const parentPath = path.dirname(traversedPath)
33+
if (parentPath === traversedPath || (maxItems && paths.length >= maxItems)) {
34+
break
35+
}
36+
traversedPath = parentPath
37+
}
38+
39+
return paths
40+
}
41+
42+
/**
43+
* Find all instances of a given module in node_modules subdirectories while traversing up
44+
* ancestor directories.
45+
*
46+
* @param cwd the initial directory to traverse
47+
* @param moduleName the Node module name (should work for scoped modules as well)
48+
* @param rootPath the project's root path. If provided, the traversal will stop at this path.
49+
*/
50+
export async function searchForModule(cwd: string, moduleName: string, rootPath?: string): Promise<string[]> {
51+
const pathGenerator: PathGeneratorFunction = traversedPath => path.join(traversedPath, "node_modules", moduleName)
52+
return traverseAncestorDirectories(cwd, pathGenerator, rootPath, undefined, true)
53+
}
54+
55+
/**
56+
* Find all instances of node_modules subdirectories while traversing up ancestor directories.
57+
*
58+
* @param cwd the initial directory to traverse
59+
* @param rootPath the project's root path. If provided, the traversal will stop at this path.
60+
*/
61+
export async function searchForNodeModules(cwd: string, rootPath?: string): Promise<string[]> {
62+
const pathGenerator: PathGeneratorFunction = traversedPath => path.join(traversedPath, "node_modules")
63+
return traverseAncestorDirectories(cwd, pathGenerator, rootPath, undefined, true)
64+
}
65+
66+
/**
67+
* Determine the root directory of a given project, by looking for a directory with an
68+
* NPM or yarn lockfile or pnpm lockfile.
69+
*
70+
* @param cwd the initial directory to traverse
71+
*/
72+
export async function getProjectRootPath(cwd: string): Promise<string> {
73+
for (const lockFilename of ["yarn.lock", "package-lock.json", "pnpm-lock.yaml"]) {
74+
const pathGenerator: PathGeneratorFunction = traversedPath => path.join(traversedPath, lockFilename)
75+
const lockPaths = await traverseAncestorDirectories(cwd, pathGenerator, undefined, 1)
76+
if (lockPaths.length > 0) {
77+
return path.dirname(lockPaths[0])
78+
}
79+
}
80+
81+
return cwd
82+
}

packages/app-builder-lib/src/util/rebuild/rebuild.ts renamed to packages/app-builder-lib/src/util/rebuild.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const rebuild = async (options: RebuildOptions): Promise<void> => {
77
const { arch } = options
88
log.info({ arch }, `installing native dependencies`)
99

10-
const child = cp.fork(path.resolve(__dirname, "remote-rebuild.js"), [JSON.stringify(options)], {
10+
const child = cp.fork(path.resolve(__dirname, "../../helpers/remote-rebuild.js"), [JSON.stringify(options)], {
1111
stdio: ["pipe", "pipe", "pipe", "ipc"],
1212
})
1313

packages/app-builder-lib/src/util/rebuild/remote-rebuild.ts

Lines changed: 0 additions & 30 deletions
This file was deleted.

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import * as electronRebuild from "@electron/rebuild"
2-
import { RebuildMode } from "@electron/rebuild/lib/types"
31
import { asArray, log, spawn } from "builder-util"
42
import { pathExists } from "fs-extra"
53
import { Lazy } from "lazy-val"
@@ -9,8 +7,9 @@ import { Configuration } from "../configuration"
97
import { executeAppBuilderAndWriteJson } from "./appBuilder"
108
import { PM, detectPackageManager, getPackageManagerCommand } from "../node-module-collector"
119
import { NodeModuleDirInfo } from "./packageDependencies"
12-
import { rebuild as remoteRebuild } from "./rebuild/rebuild"
10+
import { rebuild as remoteRebuild } from "./rebuild"
1311
import * as which from "which"
12+
import { RebuildOptions as ElectronRebuildOptions } from "@electron/rebuild"
1413

1514
export async function installOrRebuild(config: Configuration, { appDir, projectDir }: DirectoryPaths, options: RebuildOptions, forceInstall = false) {
1615
const effectiveOptions: RebuildOptions = {
@@ -176,14 +175,14 @@ export async function rebuild(config: Configuration, { appDir, projectDir }: Dir
176175
}
177176
log.info(logInfo, "executing @electron/rebuild")
178177

179-
const rebuildOptions: electronRebuild.RebuildOptions = {
178+
const rebuildOptions: ElectronRebuildOptions = {
180179
buildPath: appDir,
181180
electronVersion,
182181
arch,
183182
platform,
184183
buildFromSource,
185184
projectRootPath: projectDir,
186-
mode: (config.nativeRebuilder as RebuildMode) || "sequential",
185+
mode: config.nativeRebuilder || "sequential",
187186
disablePreGypCopy: true,
188187
}
189188
return remoteRebuild(rebuildOptions)

0 commit comments

Comments
 (0)