Skip to content

Commit 25b5dd2

Browse files
authored
fix: aliased packages not packaged with the correct name (#9492)
1 parent fcdf151 commit 25b5dd2

2 files changed

Lines changed: 31 additions & 11 deletions

File tree

.changeset/rotten-mugs-peel.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: aliased packages not packaged with the correct name

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

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
2525
}
2626

2727
protected async collectAllDependencies(tree: NpmDependency) {
28-
for (const [, value] of Object.entries(tree.dependencies || {})) {
28+
for (const [key, value] of Object.entries(tree.dependencies || {})) {
2929
if (this.isDuplicatedNpmDependency(value)) {
3030
continue
3131
}
32-
this.allDependencies.set(this.packageVersionString(value), value)
32+
// Use the key (alias name) instead of value.name for npm aliased packages
33+
// e.g., { "foo": { name: "@scope/bar", ... } } should be stored as "foo@version"
34+
// This ensures aliased packages are copied to the correct location in node_modules
35+
const normalizedDep: NpmDependency = key !== value.name ? { ...value, name: key } : value
36+
this.allDependencies.set(this.packageVersionString(normalizedDep), normalizedDep)
3337
await this.collectAllDependencies(value)
3438
}
3539
}
@@ -53,7 +57,9 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
5357
continue
5458
}
5559
const dependency = resolvedDeps[packageName]
56-
const childDependencyId = this.packageVersionString(dependency)
60+
// Use the key (alias name) for aliased packages to match how they're stored in allDependencies
61+
const normalizedName = packageName !== dependency.name ? packageName : dependency.name
62+
const childDependencyId = `${normalizedName}@${dependency.version}`
5763
await this.extractProductionDependencyGraph(dependency, childDependencyId)
5864
collectedDependencies.push(childDependencyId)
5965
}
@@ -83,8 +89,12 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
8389

8490
/**
8591
* Recursively builds dependency tree starting from a package directory.
92+
* @param packageDir - The directory of the package to process
93+
* @param aliasName - Optional alias name for npm aliased dependencies (e.g., "foo": "npm:@scope/bar@1.0.0")
94+
* When provided, this name is used instead of the package.json name for the module name,
95+
* ensuring the package is copied to the correct location in node_modules.
8696
*/
87-
const buildFromPackage = async (packageDir: string): Promise<NpmDependency> => {
97+
const buildFromPackage = async (packageDir: string, aliasName?: string): Promise<NpmDependency> => {
8898
const pkgPath = path.join(packageDir, "package.json")
8999

90100
log.debug({ pkgPath }, "building dependency node from package.json")
@@ -96,11 +106,15 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
96106
const pkg: PackageJson = await this.cache.packageJson[pkgPath]
97107
const resolvedPackageDir = await this.cache.realPath[packageDir]
98108

109+
// Use the alias name if provided, otherwise fall back to the package.json name
110+
// This ensures npm aliased packages are copied to the correct location
111+
const moduleName = aliasName ?? pkg.name
112+
99113
// Use resolved path as the unique identifier to prevent circular dependencies
100114
if (visited.has(resolvedPackageDir)) {
101-
log.debug({ name: pkg.name, version: pkg.version, path: resolvedPackageDir }, "skipping already visited package")
115+
log.debug({ name: moduleName, version: pkg.version, path: resolvedPackageDir }, "skipping already visited package")
102116
return {
103-
name: pkg.name,
117+
name: moduleName,
104118
version: pkg.version,
105119
path: resolvedPackageDir,
106120
}
@@ -120,12 +134,12 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
120134
const depPath = await this.locatePackageVersion(resolvedPackageDir, depName, depVersion)
121135

122136
if (!depPath || depPath.packageDir.length === 0) {
123-
log.warn({ package: pkg.name, dependency: depName, version: depVersion }, "dependency not found, skipping")
137+
log.warn({ package: moduleName, dependency: depName, version: depVersion }, "dependency not found, skipping")
124138
continue
125139
}
126140

127141
const resolvedDepPath = await this.cache.realPath[depPath.packageDir]
128-
const logFields = { package: pkg.name, dependency: depName, resolvedPath: resolvedDepPath }
142+
const logFields = { package: moduleName, dependency: depName, resolvedPath: resolvedDepPath }
129143

130144
// Skip if this dependency resolves to the base directory or any parent we're already processing
131145
if (resolvedDepPath === resolvedPackageDir || resolvedDepPath === (await this.cache.realPath[baseDir])) {
@@ -136,14 +150,15 @@ export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency,
136150
log.debug(logFields, "processing production dependency")
137151

138152
// Recursively build the dependency tree for this dependency
139-
prodDeps[depName] = await buildFromPackage(resolvedDepPath)
153+
// Pass depName as the alias - it will be used as the module name if different from the actual package name
154+
prodDeps[depName] = await buildFromPackage(resolvedDepPath, depName)
140155
} catch (error: any) {
141-
log.warn({ package: pkg.name, dependency: depName, error: error.message }, "failed to process dependency, skipping")
156+
log.warn({ package: moduleName, dependency: depName, error: error.message }, "failed to process dependency, skipping")
142157
}
143158
}
144159

145160
return {
146-
name: pkg.name,
161+
name: moduleName,
147162
version: pkg.version,
148163
path: resolvedPackageDir,
149164
dependencies: Object.keys(prodDeps).length > 0 ? prodDeps : undefined,

0 commit comments

Comments
 (0)