Skip to content

Commit 18a4138

Browse files
authored
Fix desktop native optional dependency packaging (#3816)
1 parent 0c66565 commit 18a4138

2 files changed

Lines changed: 45 additions & 11 deletions

File tree

scripts/build-desktop-artifact.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
resolveGitHubPublishConfig,
3434
resolveMockUpdateServerPort,
3535
resolveMockUpdateServerUrl,
36+
resolvePackageManagerUserAgent,
3637
stageLinuxIconSize,
3738
STAGE_INSTALL_ARGS,
3839
} from "./build-desktop-artifact.ts";
@@ -208,6 +209,13 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
208209
cpu: ["x64"],
209210
},
210211
});
212+
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "linux", arch: "x64" }), {
213+
supportedArchitectures: {
214+
os: ["linux"],
215+
cpu: ["x64"],
216+
libc: ["glibc"],
217+
},
218+
});
211219
// Windows artifacts also bundle the same-architecture WSL (Linux, glibc) backend, so the
212220
// staged install must fetch its native optional deps (e.g. ffi-rs) too.
213221
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "win", arch: "x64" }), {
@@ -253,6 +261,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
253261
supportedArchitectures: {
254262
os: ["linux"],
255263
cpu: ["x64"],
264+
libc: ["glibc"],
256265
},
257266
allowBuilds: {
258267
electron: true,
@@ -529,6 +538,12 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
529538
assert.equal(resolveMockUpdateServerUrl(4123), "http://localhost:4123");
530539
});
531540

541+
it("derives the electron-builder package manager user agent from packageManager", () => {
542+
assert.equal(resolvePackageManagerUserAgent("pnpm@11.10.0"), "pnpm/11.10.0");
543+
assert.equal(resolvePackageManagerUserAgent(" yarn@4.9.2 "), "yarn/4.9.2");
544+
assert.equal(resolvePackageManagerUserAgent("pnpm"), "pnpm");
545+
});
546+
532547
it.effect("normalizes mock update server ports from env-style strings", () =>
533548
Effect.gen(function* () {
534549
assert.equal(yield* resolveMockUpdateServerPort(undefined), undefined);

scripts/build-desktop-artifact.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -890,22 +890,27 @@ export function createStageWorkspaceConfig(input: {
890890
const { platform, arch, allowBuilds, patchedDependencies, overrides } = input;
891891
const hostOs = platform === "mac" ? "darwin" : platform === "win" ? "win32" : "linux";
892892
const hostCpu = arch === "universal" ? ["arm64", "x64"] : [arch];
893-
// Windows artifacts also bundle the same-architecture WSL Linux backend, which loads
894-
// Linux-native optional deps at runtime (e.g. @yuuang/ffi-rs-linux-x64-gnu).
895-
// Pull the Linux (glibc) variants in addition to the host platform's so
896-
// they ship in the asar; without them the WSL backend crash-loops on require
897-
// ("Cannot find module '@yuuang/ffi-rs-linux-x64-gnu'").
893+
// Linux AppImages and Windows WSL backends both execute a Linux/glibc Node
894+
// process that loads Linux-native optional deps at runtime (e.g.
895+
// @yuuang/ffi-rs-linux-x64-gnu). Keep libc explicit so pnpm includes those
896+
// optional packages in the staged production install.
898897
const supportedArchitectures =
899-
platform === "win"
898+
platform === "linux"
900899
? {
901-
os: Array.from(new Set([hostOs, "linux"])),
900+
os: [hostOs],
902901
cpu: hostCpu,
903902
libc: ["glibc"],
904903
}
905-
: {
906-
os: [hostOs],
907-
cpu: hostCpu,
908-
};
904+
: platform === "win"
905+
? {
906+
os: Array.from(new Set([hostOs, "linux"])),
907+
cpu: hostCpu,
908+
libc: ["glibc"],
909+
}
910+
: {
911+
os: [hostOs],
912+
cpu: hostCpu,
913+
};
909914

910915
return {
911916
supportedArchitectures,
@@ -1339,6 +1344,19 @@ export function resolveMockUpdateServerUrl(mockUpdateServerPort: number | undefi
13391344
return `http://localhost:${mockUpdateServerPort ?? 3000}`;
13401345
}
13411346
1347+
// Electron Builder detects pnpm from npm_config_user_agent, whose value uses
1348+
// user-agent syntax (pnpm/11.10.0) rather than packageManager syntax
1349+
// (pnpm@11.10.0).
1350+
export function resolvePackageManagerUserAgent(packageManager: string): string {
1351+
const trimmed = packageManager.trim();
1352+
const versionSeparator = trimmed.lastIndexOf("@");
1353+
if (versionSeparator <= 0 || versionSeparator === trimmed.length - 1) {
1354+
return trimmed;
1355+
}
1356+
1357+
return `${trimmed.slice(0, versionSeparator)}/${trimmed.slice(versionSeparator + 1)}`;
1358+
}
1359+
13421360
export function resolveDesktopProductName(version: string): string {
13431361
return resolveDesktopUpdateChannel(version) === "nightly"
13441362
? "T3 Code (Nightly)"
@@ -1799,6 +1817,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* (
17991817
const buildEnv: NodeJS.ProcessEnv = {
18001818
...process.env,
18011819
};
1820+
buildEnv.npm_config_user_agent = resolvePackageManagerUserAgent(rootPackageJson.packageManager);
18021821
for (const [key, value] of Object.entries(buildEnv)) {
18031822
if (value === "") {
18041823
delete buildEnv[key];

0 commit comments

Comments
 (0)