Skip to content

Commit d1d6370

Browse files
committed
new blog post
1 parent 20de966 commit d1d6370

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
title: "Setting up Changesets with Bun Workspaces"
3+
description: "Getting Changesets working with Bun Workspaces to have proper versioning and publishing."
4+
tags:
5+
- changesets
6+
- bun
7+
- workspaces
8+
---
9+
10+
Changesets does not support Bun out of the box: it doesn't resolve workspaces or catalogs. This is a known issue ([Bun incompatibility](https://github.com/oven-sh/bun/issues/16074), [workspace protocol support request](https://github.com/changesets/changesets/issues/1454), [unmerged PR for workspace support](https://github.com/changesets/changesets/pull/674)). Here's how to resolve it.
11+
12+
## The Problem
13+
14+
When you try to publish packages with Changesets in a Bun monorepo, your published packages will contain unresolved `workspace:*` references:
15+
16+
```json
17+
{
18+
"name": "@macalinao/eslint-config-react",
19+
"dependencies": {
20+
"@macalinao/eslint-config": "workspace:*"
21+
}
22+
}
23+
```
24+
25+
This breaks npm installations for anyone trying to use your packages. The workspace references that work perfectly in development don't get resolved to actual version numbers during publishing.
26+
27+
## My Solution
28+
29+
I created custom scripts that ensure workspace references get resolved properly. You can see the full implementation in my [style-guide repository](https://github.com/macalinao/style-guide):
30+
31+
```json
32+
{
33+
"scripts": {
34+
"ci:version": "changeset version && bun update",
35+
"ci:publish": "for dir in packages/*; do (cd \"$dir\" && bun publish || true); done && changeset tag"
36+
}
37+
}
38+
```
39+
40+
### Why I Added `bun update`
41+
42+
The key insight was adding `bun update` after `changeset version`. Here's what happens:
43+
44+
1. `changeset version` updates the version numbers in package.json files
45+
2. `bun update` then fixes the bun.lockb file to properly resolve all `workspace:*` references to these new version numbers
46+
47+
Without `bun update`, the lockfile remains out of sync with the updated package versions. This causes `bun publish` to fail or publish packages with unresolved workspace references. The `bun update` command ensures that when `@macalinao/eslint-config` gets bumped to version 4.2.2, the lockfile is updated so that `bun publish` can properly resolve and replace `workspace:*` with `4.2.2` during publishing.
48+
49+
## Why I Publish All Packages
50+
51+
Instead of using `changeset publish`, I iterate through every package and publish them individually:
52+
53+
```bash
54+
for dir in packages/*; do
55+
(cd "$dir" && bun publish || true)
56+
done && changeset tag
57+
```
58+
59+
I do this because:
60+
61+
1. It ensures all `workspace:*` references are resolved before publishing
62+
2. The `|| true` means if one package fails (maybe it's already published), the others still get published
63+
3. I get direct control over the publishing process using Bun's native publish command
64+
4. After everything publishes, I create git tags with `changeset tag`
65+
66+
This approach prevents partial-publish disasters where some packages would fail and leave my monorepo in an inconsistent state.
67+
68+
## GitHub Actions Setup
69+
70+
The GitHub action is largely the same as the official documentation, utilizing the [changesets/action](https://github.com/changesets/action) GitHub action. Here's my workflow from [release.yml](https://github.com/macalinao/style-guide/blob/master/.github/workflows/release.yml):
71+
72+
```yaml
73+
name: Release
74+
on:
75+
push:
76+
branches:
77+
- master
78+
79+
jobs:
80+
version:
81+
runs-on: ubuntu-latest
82+
steps:
83+
- name: Checkout
84+
uses: actions/checkout@v4
85+
86+
- uses: oven-sh/setup-bun@v2
87+
88+
- name: Setup npmrc
89+
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
90+
91+
- name: Install dependencies
92+
run: bun install --frozen-lockfile
93+
94+
- name: Build
95+
run: bun run build
96+
97+
- name: Create and publish versions
98+
uses: changesets/action@v1
99+
with:
100+
version: bun run ci:version
101+
commit: "chore: update versions"
102+
title: "chore: update versions"
103+
publish: bun run ci:publish
104+
env:
105+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
106+
```
107+
108+
The workflow:
109+
110+
1. Sets up Bun using `oven-sh/setup-bun@v2`
111+
2. Creates an `.npmrc` with my npm auth token
112+
3. Builds all packages before publishing
113+
4. Uses the changesets action with my custom `ci:version` and `ci:publish` scripts
114+
115+
When I push changesets to master, this workflow creates a PR with version updates. When I merge that PR, it automatically publishes all packages to npm.
116+
117+
## Configuration Details
118+
119+
Each package needs proper publishing configuration to publish to npm:
120+
121+
```json
122+
{
123+
"publishConfig": {
124+
"access": "public",
125+
"registry": "https://registry.npmjs.org/"
126+
}
127+
}
128+
```
129+
130+
A similar configuration works for private packages published on GitHub Packages:
131+
132+
```json
133+
{
134+
"publishConfig": {
135+
"access": "restricted",
136+
"registry": "https://npm.pkg.github.com/"
137+
}
138+
}
139+
```
140+
141+
The workflow just uses `bun publish`, so you can use the same configuration you'd use for `yarn` or `pnpm`.
142+
143+
## The Complete Workflow
144+
145+
Here's how I release packages now:
146+
147+
1. I make changes and create changesets with `bun changeset`
148+
2. I push to master, which triggers the GitHub Action
149+
3. The action creates a "Version Packages" PR
150+
4. I merge the PR, which triggers another action run
151+
5. The action publishes all packages with resolved dependencies
152+
153+
The beauty is that what I test locally with `workspace:*` references is exactly what gets published to npm, just with resolved version numbers.
154+
155+
## Conclusion
156+
157+
This workaround has been working reliably for my monorepo. While I'm looking forward to first-class support ([tracked here](https://github.com/oven-sh/bun/issues/16074)), this solution gets the job done today.
158+
159+
The key takeaway: **always run `bun update` after `changeset version`** to fix the lockfile, and **use `bun publish` directly** for each package. This combination ensures workspace references are properly resolved during publishing.
160+
161+
If you're struggling with the same issue, check out my [style-guide repo](https://github.com/macalinao/style-guide) for a working example. The approach has eliminated all the workspace reference issues I was experiencing, and my packages now publish reliably with properly resolved dependencies.

0 commit comments

Comments
 (0)