Skip to content

Commit 4cc475e

Browse files
authored
fix: allow usage of node-linker=hoisted with pnpm (#8885)
1 parent aafb531 commit 4cc475e

File tree

7 files changed

+5229
-87
lines changed

7 files changed

+5229
-87
lines changed

.changeset/lemon-moles-rhyme.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+
fix: `node-linker=hoisted` fallback to utilize Npm module collector

packages/app-builder-lib/src/node-module-collector/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,25 @@ import { PnpmNodeModulesCollector } from "./pnpmNodeModulesCollector"
33
import { YarnNodeModulesCollector } from "./yarnNodeModulesCollector"
44
import { detect, PM, getPackageManagerVersion } from "./packageManager"
55
import { NodeModuleInfo } from "./types"
6+
import { exec } from "builder-util"
7+
8+
async function isPnpmProjectHoisted(rootDir: string) {
9+
const command = await PnpmNodeModulesCollector.pmCommand.value
10+
const config = await exec(command, ["config", "list"], { cwd: rootDir, shell: true })
11+
const lines = Object.fromEntries(config.split("\n").map(line => line.split("=").map(s => s.trim())))
12+
return lines["node-linker"] === "hoisted"
13+
}
614

715
async function getCollectorByPackageManager(rootDir: string) {
816
const manager: PM = await detect({ cwd: rootDir })
917
switch (manager) {
10-
case "npm":
11-
return new NpmNodeModulesCollector(rootDir)
1218
case "pnpm":
19+
if (await isPnpmProjectHoisted(rootDir)) {
20+
return new NpmNodeModulesCollector(rootDir)
21+
}
1322
return new PnpmNodeModulesCollector(rootDir)
23+
case "npm":
24+
return new NpmNodeModulesCollector(rootDir)
1425
case "yarn":
1526
return new YarnNodeModulesCollector(rootDir)
1627
default:

packages/app-builder-lib/src/node-module-collector/nodeModulesCollector.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as path from "path"
33
import * as fs from "fs"
44
import type { NodeModuleInfo, DependencyTree, DependencyGraph, Dependency } from "./types"
55
import { exec, log } from "builder-util"
6+
import { Lazy } from "lazy-val"
67

78
export abstract class NodeModulesCollector<T extends Dependency<T, OptionalsType>, OptionalsType> {
89
private nodeModules: NodeModuleInfo[] = []
@@ -27,13 +28,13 @@ export abstract class NodeModulesCollector<T extends Dependency<T, OptionalsType
2728
return this.nodeModules
2829
}
2930

30-
protected abstract getCommand(): string
31+
protected abstract readonly pmCommand: Lazy<string>
3132
protected abstract getArgs(): string[]
3233
protected abstract parseDependenciesTree(jsonBlob: string): T
3334
protected abstract extractProductionDependencyTree(tree: Dependency<T, OptionalsType>): DependencyTree
3435

3536
protected async getDependenciesTree(): Promise<T> {
36-
const command = this.getCommand()
37+
const command = await this.pmCommand.value
3738
const args = this.getArgs()
3839
const dependencies = await exec(command, args, {
3940
cwd: this.rootDir,

packages/app-builder-lib/src/node-module-collector/npmNodeModulesCollector.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Lazy } from "lazy-val"
12
import { NodeModulesCollector } from "./nodeModulesCollector"
23
import { DependencyTree, NpmDependency, ParsedDependencyTree } from "./types"
34
import { log } from "builder-util"
@@ -7,11 +8,9 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
78
super(rootDir)
89
}
910

10-
getCommand(): string {
11-
return process.platform === "win32" ? "npm.cmd" : "npm"
12-
}
11+
protected readonly pmCommand = new Lazy<string>(() => Promise.resolve(process.platform === "win32" ? "npm.cmd" : "npm"))
1312

14-
getArgs(): string[] {
13+
protected getArgs(): string[] {
1514
return ["list", "-a", "--include", "prod", "--include", "optional", "--omit", "dev", "--json", "--long", "--silent"]
1615
}
1716

packages/app-builder-lib/src/node-module-collector/pnpmNodeModulesCollector.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
1+
import { Lazy } from "lazy-val"
12
import { NodeModulesCollector } from "./nodeModulesCollector"
23
import { Dependency, DependencyTree, PnpmDependency } from "./types"
34
import * as path from "path"
5+
import { exec, log } from "builder-util"
46

57
export class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmDependency, PnpmDependency> {
68
constructor(rootDir: string) {
79
super(rootDir)
810
}
911

10-
getCommand(): string {
11-
return process.platform === "win32" ? "pnpm.cmd" : "pnpm"
12-
}
12+
static readonly pmCommand = new Lazy<string>(async () => {
13+
if (process.platform === "win32") {
14+
try {
15+
await exec("pnpm", ["--version"])
16+
} catch (_error: any) {
17+
log.debug(null, "pnpm not detected, falling back to pnpm.cmd")
18+
return "pnpm.cmd"
19+
}
20+
}
21+
return "pnpm"
22+
})
23+
24+
protected readonly pmCommand: Lazy<string> = PnpmNodeModulesCollector.pmCommand
1325

14-
getArgs(): string[] {
26+
protected getArgs(): string[] {
1527
return ["list", "--prod", "--json", "--depth", "Infinity"]
1628
}
1729

0 commit comments

Comments
 (0)