Skip to content

Commit 88070e9

Browse files
authored
fix: pnpm collector returning zero modules (#9535)
1 parent cf10da8 commit 88070e9

4 files changed

Lines changed: 36 additions & 40 deletions

File tree

.changeset/poor-moles-win.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: pnpm collector returning zero modules

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export abstract class NodeModulesCollector<ProdDepType extends Dependency<ProdDe
101101
async () => {
102102
await this.streamCollectorCommandToFile(command, args, this.rootDir, tempOutputFile)
103103
const shellOutput = await fs.readFile(tempOutputFile, { encoding: "utf8" })
104-
const result = Promise.resolve(this.parseDependenciesTree(shellOutput))
104+
const result = await Promise.resolve(this.parseDependenciesTree(shellOutput))
105105
return result
106106
},
107107
{

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,7 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
4545
continue
4646
}
4747
const dependency = resolvedDeps[packageName]
48-
// Use the key (alias name) for aliased packages to match how they're stored in allDependencies
49-
const normalizedName = packageName !== dependency.name ? packageName : dependency.name
50-
const childDependencyId = `${normalizedName}@${dependency.version}`
48+
const childDependencyId = this.packageVersionString({ name: packageName, version: dependency.version })
5149
await this.extractProductionDependencyGraph(dependency, childDependencyId)
5250
collectedDependencies.push(childDependencyId)
5351
}

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

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { isEmptyOrSpaces, log } from "builder-util"
2-
import * as path from "path"
1+
import { log } from "builder-util"
32
import { NodeModulesCollector } from "./nodeModulesCollector"
43
import { PM } from "./packageManager"
54
import { PnpmDependency } from "./types"
@@ -14,67 +13,61 @@ export class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmDependenc
1413
return ["list", "--prod", "--json", "--depth", "Infinity"]
1514
}
1615

17-
private async getProductionDependencies(depTree: PnpmDependency): Promise<{ path: string; dependencies: Record<string, string>; optionalDependencies: Record<string, string> }> {
18-
const packageName = depTree.name || depTree.from
19-
if (isEmptyOrSpaces(packageName)) {
20-
log.error(depTree, `Cannot determine production dependencies for package with empty name`)
21-
throw new Error(`Cannot compute production dependencies for package with empty name: ${packageName}`)
22-
}
23-
24-
const result = await this.cache.locatePackageVersion({ parentDir: depTree.path, pkgName: packageName, requiredRange: depTree.version })
25-
if (result == null) {
26-
return { path: path.resolve(depTree.path), dependencies: {}, optionalDependencies: {} }
27-
}
28-
29-
const { dependencies, optionalDependencies } = result.packageJson
30-
return { path: result.packageDir, dependencies: { ...dependencies }, optionalDependencies: { ...optionalDependencies } }
31-
}
32-
3316
protected async extractProductionDependencyGraph(tree: PnpmDependency, dependencyId: string) {
3417
if (this.productionGraph[dependencyId]) {
3518
return
3619
}
3720
this.productionGraph[dependencyId] = { dependencies: [] }
3821

3922
const packageName = tree.name || tree.from
23+
const { packageJson } = (await this.cache.locatePackageVersion({ pkgName: packageName, parentDir: this.rootDir, requiredRange: tree.version })) || {}
4024

41-
const treeDep = { ...(tree.dependencies || {}), ...(tree.optionalDependencies || {}) }
42-
const json = packageName === dependencyId ? null : await this.getProductionDependencies(tree)
43-
const prodDependencies = json ? { ...json.dependencies, ...json.optionalDependencies } : treeDep
25+
const all = packageJson ? { ...packageJson.dependencies, ...packageJson.optionalDependencies } : { ...tree.dependencies, ...tree.optionalDependencies }
26+
const optional = packageJson ? { ...packageJson.optionalDependencies } : {}
4427

45-
const collectedDependencies: string[] = []
46-
for (const packageName in treeDep) {
47-
if (!prodDependencies[packageName]) {
48-
continue
28+
const deps = { ...(tree.dependencies || {}), ...(tree.optionalDependencies || {}) }
29+
this.productionGraph[dependencyId] = { dependencies: [] }
30+
const depPromises = Object.entries(deps).map(async ([packageName, dependency]) => {
31+
// First check if it's in production dependencies
32+
if (!all[packageName]) {
33+
return undefined
4934
}
5035

5136
// Then check if optional dependency path exists (using actual resolved path)
52-
const version = json?.optionalDependencies?.[packageName] || tree.optionalDependencies?.[packageName]?.version || ""
53-
const result = await this.locatePackageWithVersion({ name: packageName, version, path: json?.path ?? tree.path })
54-
if (result == null || !(await this.cache.exists[result.packageDir])) {
55-
log.debug({ packageName, version: version, searchPath: result?.packageDir }, `optional dependency not installed, skipping`)
56-
continue
37+
if (optional[packageName]) {
38+
const pkg = await this.cache.locatePackageVersion({ pkgName: packageName, parentDir: this.rootDir, requiredRange: dependency.version })
39+
if (!pkg) {
40+
log.debug({ name: packageName, version: dependency.version, path: dependency.path }, `optional dependency doesn't exist, skipping - likely not installed`)
41+
return undefined
42+
}
5743
}
58-
const dependency = treeDep[packageName]
5944
const childDependencyId = this.packageVersionString(dependency)
6045
await this.extractProductionDependencyGraph(dependency, childDependencyId)
61-
collectedDependencies.push(childDependencyId)
46+
return childDependencyId
47+
})
48+
49+
const collectedDependencies: string[] = []
50+
for (const dep of depPromises) {
51+
const result = await dep
52+
if (result !== undefined) {
53+
collectedDependencies.push(result)
54+
}
6255
}
6356
this.productionGraph[dependencyId] = { dependencies: collectedDependencies }
6457
}
6558

6659
protected async collectAllDependencies(tree: PnpmDependency) {
6760
// Collect regular dependencies
6861
for (const [key, value] of Object.entries(tree.dependencies || {})) {
69-
const json = await this.getProductionDependencies({ ...value, name: key })
70-
this.allDependencies.set(`${key}@${value.version}`, { ...value, path: json.path })
62+
const pkg = await this.cache.locatePackageVersion({ pkgName: key, parentDir: this.rootDir, requiredRange: value.version })
63+
this.allDependencies.set(`${key}@${value.version}`, { ...value, path: pkg?.packageDir ?? value.path })
7164
await this.collectAllDependencies(value)
7265
}
7366

7467
// Collect optional dependencies if they exist
7568
for (const [key, value] of Object.entries(tree.optionalDependencies || {})) {
76-
const json = await this.getProductionDependencies(value)
77-
this.allDependencies.set(`${key}@${value.version}`, { ...value, path: json.path })
69+
const pkg = await this.cache.locatePackageVersion({ pkgName: key, parentDir: this.rootDir, requiredRange: value.version })
70+
this.allDependencies.set(`${key}@${value.version}`, { ...value, path: pkg?.packageDir ?? value.path })
7871
await this.collectAllDependencies(value)
7972
}
8073
}

0 commit comments

Comments
 (0)