microsoft / microsoft/aspire

addBunApp's auto-installer pollutes parent npm workspaces (Windows): bun install rewrites all workspace .bin shims

Open
#17,682 1 comment 0 reactions 0 assignees View on GitHub
area-app-model triage:bot-seen
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

## Summary

When using `addBunApp` from `Aspire.Hosting.JavaScript` in a TypeScript AppHost where the Bun app's folder is matched by an existing npm `workspaces` glob (e.g. `services/*`), Aspire's auto-generated `-installer` resource runs `bun install` inside that folder. Bun then walks up to the repo root, detects the npm workspace tree, creates a `bun.lock`, and **rewrites every workspace's `node_modules/.bin/` shims into Bun-format shims** (`` + `.bunx` + `.exe`) that hardcode paths to a per-workspace `node_modules//...` that doesn't exist when the dependency was hoisted to the root.

The result on Windows is that any other JS app whose build relies on a hoisted `.bin` shim (e.g. `tsc` from a root-hoisted `typescript`) breaks silently with errors like `tsc not recognized` or `Cannot find module .../node_modules/typescript/bin/tsc`. This cascades through Aspire's resource graph: a `JavaScriptApp` whose `runScriptName` invokes the broken `tsc` exits non-zero → any resource that `waitForCompletion`s on it goes `FailedToStart`.

The really nasty part: the corruption persists across `aspire stop`/`aspire run` cycles and even survives `npm install` (the `.bin` shims stay in Bun format until you delete `node_modules` and the root `bun.lock`).

## Repro

Brownfield npm monorepo (Aspire 13.4, TS AppHost):

```
root/
package.json # "workspaces": ["packages/*", "services/*", "apps/*"]
packages/shared/ # builds with `tsc -p tsconfig.json` (typescript hoisted to root)
services/api/ # JavaScriptApp, runScriptName: "dev"
services/bun-svc/ # NEW Bun app for addBunApp
aspire-apphost/apphost.mts
```

`apphost.mts`:

```ts
const shared = builder.addJavaScriptApp("shared-build", "../packages/shared", { runScriptName: "build" }).withHidden();
const api = builder.addJavaScriptApp("api", "../services/api", { runScriptName: "dev" })
.waitForCompletion(shared);
const bunSvc = await builder.addBunApp("bun-svc", "../services/bun-svc", "index.ts")
.withHttpEndpoint({ name: "http", env: "PORT" });
```

Steps:
1. Fresh clone, `npm install` at root — `packages/shared/node_modules/.bin/tsc.exe` is a normal npm shim resolving to root-hoisted `typescript`.
2. `aspire run` from `aspire-apphost/`.
3. Aspire creates `bun-svc-installer` which runs `bun install` in `services/bun-svc/`.
4. Bun walks up, sees root `package.json` workspaces, claims the tree, writes `bun.lock` at root.
5. Every workspace's `.bin/` is rewritten in Bun format. `packages/shared`'s `tsc` shim now points at a non-existent `packages/shared/node_modules/typescript/bin/tsc`.
6. `shared-build` resource exits 1 with `tsc not recognized` / module-not-found.
7. `api` waits on `shared-build` → `FailedToStart`.

## Environment
- OS: Windows 11
- Aspire CLI: 13.4
- Bun: 1.3.14 (installed via official `irm bun.sh/install.ps1 | iex`)
- npm: shipped with Node 22

## Workaround

Exclude the Bun app folder from the npm `workspaces` glob (i.e. list `services/api` explicitly instead of `services/*`), then **delete** `bun.lock` and every `node_modules/` under the repo, then re-run `npm install`. After that, `aspire run` works.

## Asks

1. The Bun installer Aspire generates should run `bun install` in a way that doesn't mutate parent workspaces — e.g. with an isolated install root, `--no-save`, or by detecting an outer npm workspace and refusing/warning.
2. At minimum, document this collision in the Aspire JS hosting docs with the workaround above — this will hit anyone adopting `addBunApp` in a mixed npm-workspace repo.
3. Consider an `aspire doctor` check that flags Bun-format `.bin/` shims in folders that are also npm workspaces.

## References
- `addBunApp` introduced in dotnet/aspire#17416
- Hit during Phase 5 validation of Aspire 13.4 (TS AppHost, polyglot brownfield).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.