Skip to content

Update esbuild from 0.23 to 0.28 - #538

Merged
zaerl merged 1 commit into
trunkfrom
update/esbuild-0.28
Sep 28, 2026
Merged

zaerl merged 1 commit into
trunkfrom
update/esbuild-0.28

Conversation

@zaerl

@zaerl zaerl commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Why

esbuild, the renderer bundler, was five minors behind at 0.23. It is a dev-only tool with the smallest surface of the majors npm outdated lists after #537, so it goes first: one flag set in two scripts, and the bundle it produces is exercised by every journey.

What changes

The esbuild range moves from ^0.23.0 to ^0.28.2, and the allowScripts key follows, since it is keyed by exact version. The lockfile diff is esbuild and its @esbuild/* platform packages only. No flag in build:once or build:watch changes.

Of the behaviour changes between 0.23 and 0.28, two apply to this repository and both are dev-only:

  • Since 0.25, watch mode deletes the output files when a rebuild fails. Under npm start, saving a syntax error in src/renderer/index.jsx now removes src/renderer/index.js until the next successful save, instead of leaving the last good bundle in place. A reload of the running window in that state shows a blank page rather than stale code, which is the more honest failure.
  • Since 0.27, the esbuild binary needs macOS 12 or Linux kernel 3.2 on the machine that runs it. esbuild is a devDependency that electron-builder excludes, so users are not affected; CI runners and the Buildkite Node image satisfy it.

Not in this PR: the other majors from the list (electron-store, diff, concurrently, Electron 44, ESLint 10, the WordPress components jump). Each is its own PR.

How to test this

Platforms: any. There is no user-visible surface. The proof is the bundle building and the app running on it.

From the repository root:

npm install
npm run build:once
npm run test:e2e

Expected: the build reports src/renderer/index.js and index.css written, and all 33 journeys pass. The journeys drive the built bundle through every flow the app has, including the terminal panel, so a bundle that esbuild 0.28 produced differently would fail there.

To see the one dev-visible change: run npm start, save a deliberate syntax error into src/renderer/index.jsx, and confirm the watcher reports the error and src/renderer/index.js is gone; fix the error and confirm it comes back.

What must not have happened:

  • Lint or the unit suite failing, which would mean the bundler change leaked into something it should not touch.
  • Any package other than esbuild and @esbuild/* changing in the lockfile.

Risks and limitations

  • The watch-mode deletion is a workflow change for whoever runs npm start and then reloads the window mid-edit. It cannot break a build or a user.
  • A developer on macOS 11 or older can no longer run the bundler locally. The README already assumes a current machine, and the signed builds come from CI.

Related

Follow-up to #537, first of the majors listed there.


Design decisions and alternatives considered

Pinning to a specific 0.28.x was considered and rejected: the repository already uses a caret range for esbuild, and the lockfile pins the resolution. Adding an esbuild config file instead of CLI flags was not needed; nothing in the flag set is affected by the upgrade.

Review outcome (required — see AGENTS.md)

0 [fix here] · 1 [follow-up] — the follow-up is recorded here and not acted on in this PR.

  • Review: completed — fresh-context review agent (separate from the session that produced the change), against .github/instructions/code-review.instructions.md; reviewed head d8d0eed / base 9d2bc17 (trunk); outcome: 1 finding.
    • 🔵 Architecture (failure paths), [follow-up], src/main.js:563: the main window loads index.html with no did-fail-load handling, so a reload while watch mode has deleted the bundle paints an empty page with no message. Pre-existing; this bump only adds a second way to reach it, and only in the dev loop. Deferred because it is not something the bundler change should fix and cannot reach a packaged build, where the smoke test asserts the bundle is present.
  • Since review: none. The reviewed head is the PR head.
  • CodeRabbit: completed — run 98a7e545-8511-49d3-bc3e-3fef4f7c3fe7, reviewed head d8d0eed / base 9d2bc17; no actionable comments. It reviewed package.json only: package-lock.json is excluded by its path filter, so the lockfile is covered by the fresh-context review above.
  • CI on d8d0eed: eslint, journeys (macOS, Windows), packaged smoke (macOS, Windows) and unit (Windows) passed on the first attempt. Unit (macOS) failed once and passed on re-run. The failure was in esbuild's postinstall, which runs the just-installed binary with --version; macOS refused it with system error -88 (EBADMACHO, a malformed executable). The journeys and packaged-smoke jobs on the same commit and the same macos-26-arm64 image ran the identical npm ci and passed, and the re-run passed, so this was a corrupted download or extraction on that one runner, not the 0.28 binary. If it recurs, it is worth an upstream issue: 0.28's new integrity check covers only the fallback download path, not the npm optional-dependency path that CI takes.
Implementation notes
  • Deterministic layer on the head: npm run lint clean; npm test 1674 pass, 2 skipped; npm run test:electron 1676 pass; npm run test:e2e 33 passed; build:once writes a 2.9 MB index.js and a 105 KB index.css.
  • Behaviour changes in the changelog that do not apply here: dev-server CORS (no --serve), BigInt transforms and --drop:console (not used), the text loader stripping a BOM (no text loader), the binary loader using Uint8Array.fromBase64 (no binary loader), and the 0.28 integrity check on the fallback binary download in install.js (only reached when the platform package is missing).
Screenshots or recording

Nothing on screen changes.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: WordPress/contributor-toolkit/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 696a03a8-9d2c-4667-a6db-937921f66a19

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: WordPress/contributor-toolkit/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 98a7e545-8511-49d3-bc3e-3fef4f7c3fe7

📥 Commits

Reviewing files that changed from the base of the PR and between 9d2bc17 and d8d0eed.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !package-lock.json
📒 Files selected for processing (1)
  • package.json

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The package manifest updates the esbuild development dependency range from ^0.23.0 to ^0.28.2. It also changes the allowed install-script version from esbuild@0.23.1 to esbuild@0.28.2.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to d8d0e

The dependency update affects development-time renderer tooling, while shipped builds consume generated output. No merge-blocking risk is established.

Architecture Summary

Architecture risk: 🔵 Low · up to d8d0e

The change affects 1 system.

Changed systems: package.json

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — package.json (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in package.json: The esbuild dependency range changes from ^0.23.0 to ^0.28.2; the allowed install-script version changes from esbuild@0.23.1 to esbuild@0.28.2. Other entries in this block remain unchanged.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description includes all required sections. It explains the reason, implementation, testing steps, expected results, risks, related issue, review outcome, implementation notes, and un…
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zaerl

zaerl commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

The renderer bundler moves five minors. Nothing in the flags the build scripts pass changed meaning across them; the behaviour changes that do apply are dev-only: watch mode now deletes the bundle when a rebuild fails, and the esbuild binary itself needs macOS 12 or newer on the machine that builds. The allowScripts key follows the version, as it is keyed by name@version.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@zaerl
zaerl force-pushed the update/esbuild-0.28 branch from d8d0eed to fae8652 Compare September 28, 2026 15:17
@zaerl
zaerl merged commit 0dc54da into trunk Sep 28, 2026
8 checks passed
@zaerl
zaerl deleted the update/esbuild-0.28 branch September 28, 2026 18:41
zaerl added a commit that referenced this pull request Sep 30, 2026
… system redesign (#563)

## Why

The redesign in #542 is built on `@wordpress/ui` and `@wordpress/theme`,
and both are developed against the current `@wordpress/components`. The
app is on 28, thirteen majors behind, so nothing from the design system
can be added until the renderer stands on 41. This is the first step of
#542 and changes no behaviour.

## What changes

- `@wordpress/components` moves from `^28.2.0` to `^41.0.0` and
`@wordpress/icons` from `^10.7.0` to `^17.0.0`. React stays on 18.3.1,
which both packages support.
- The `edit` icon was removed from `@wordpress/icons`; `pencil` is the
same glyph under its current name.
- `build.files` excludes the thirteen packages the update brought into
the packaged app. `@wordpress/components` 41 depends on `@wordpress/ui`
and `@wordpress/theme`, and `@wordpress/theme` names esbuild as an
optional peer, so npm stopped marking esbuild as dev-only and
electron-builder started shipping its binary. None of the thirteen is
loaded at run time: the renderer is the esbuild bundle, and nothing
under `src/` requires them.
- The sidebar title is kept on one line. Buttons are set in a heavier
weight now, and the wider "Collapse" button wrapped "Contributor
Toolkit" onto two.
- Text inputs are now 40px tall instead of 36px. So the buttons are
slightly smaller. But they will be removed anyway.

Deliberately not in this PR: adding `@wordpress/ui` or
`@wordpress/theme` as dependencies of the app, any use of design tokens,
and any layout change. Those are the next steps of #542.

## How to test this

Platforms: any. Nothing here touches paths, spawning or signing. Use the
Buildkite build for the current head of this branch.

The journeys carry the behavior: `npm run test:e2e` from the repository
root drives every flow the renderer has through the updated components,
and `npm run test:e2e:packaged`, after
`CSC_IDENTITY_AUTO_DISCOVERY=false npm run pack:dir`, proves the
packaged app still boots without the excluded packages. What they cannot
see is how the app looks, so that is what a person should check.

**Starting state:** the app open with at least one site that has
finished setup.

1. Look at the sidebar. "Contributor Toolkit" is on one line, beside
"Collapse".
2. Click "Collapse", then the arrow to expand again. The sidebar returns
to the same layout.
3. Click the pencil beside the site name. The "Rename site" dialog
opens; close it.
4. Open the menu at the top right of the site. It lists "Copy path", the
file manager entry, "Update to latest trunk" and "Delete this site".
5. Click "Create a site". The dialog shows "Site name", "Contribute to"
with two choices, and "Site location"; close it.
6. Scroll to "Logs" and click each tab. The selected tab is underlined
and its content changes.

**What must not have happened:**

- No button, field or menu has lost its label or become unreachable.
- No text is clipped or overlapping where a control grew: text fields
are 40px tall instead of 36px, and button labels are heavier.

## Risks and limitations

- **The look changes slightly, and that is the design system's doing.**
Button labels are heavier, text fields are taller, menu items are more
compact, and the selected tab is marked in neutral grey and black where
it was blue. Details under Screenshots.
- **The docs screenshots are not retaken.** The twelve the harness can
produce differ slightly from the app after this. #542 retakes all of
them, and the harness is not reproducible across runs (#326), so
refreshing them here would add churn twice.
- **Checked on macOS only by hand and by local runs.** Windows is
covered by CI's journeys and packaged smoke, not by a person.
- **The exclusion list is by name.** A future update that adds another
renderer-only package will ship it until someone adds a line. Excluding
the whole renderer-only tree is the real fix and overlaps with #23.
- **The first commit of this branch was pushed to `trunk` by mistake and
removed again.** `trunk` is back at 0dc54da; anyone who fetched in
between has b6a6151 on their local `trunk`.
- Review: 2 [fix here], both fixed; 1 [follow-up] deferred.

## Related

Part of #542.
Fixes #548.

---

<details>
<summary>Design decisions and alternatives considered</summary>

**Excluding in `build.files` rather than moving the renderer's
dependencies to `devDependencies`.** Moving them would stop the whole
renderer-only tree from shipping, not just what this update added, but
that is a change to how the app is packaged and #23 is already about it.
This PR only undoes the growth it would otherwise cause.

**One jump from 28 to 41 rather than a major at a time.** The renderer
uses seventeen components, all of which still exist with the same props.
The only break was the removed icon alias, which fails the build rather
than the app.

</details>

<details>
<summary>Review outcome (required — see AGENTS.md)</summary>

**2 [fix here] · 1 [follow-up]** — both [fix here] fixed.

- Architecture, medium, [fix here], fixed: the packaged app shipped the
esbuild binary, because `@wordpress/theme` names esbuild as an optional
peer and electron-builder collects optional packages.
- Performance, medium, [fix here], fixed: twelve more packages the
update added were collected into the app and never loaded.
- Performance, low, [follow-up], deferred: the whole renderer dependency
tree ships although only the bundle is loaded. It predates this branch
and is the subject of #23.

Style notes, not applied: with `white-space: nowrap` the sidebar title
can paint outside the sidebar during the 200ms expand animation; the
`esbuild@0.23.1` entry in `allowScripts` has been stale since #538.

- **Review:** completed — fresh agent context, local, before the PR
existed; head b6a6151 / base
0dc54da; committed work only, working
tree clean; outcome above. CodeRabbit: not run yet.
- **Since review:** `b6a6151 → 4b2d52e` checked. The difference is the
thirteen exclusion lines in `build.files` that fix the two findings. It
was not reviewed again by a fresh context; it was verified by packaging
and running the packaged smoke test.

Checks on 4b2d52e, macOS, local:

| Check | Result |
|---|---|
| `npm run lint` | clean |
| `npm test` | 1676 tests, 1674 pass, 2 skipped, 0 fail |
| `npm run test:electron` | 1676 pass, 0 fail |
| `npm run test:e2e` | 33 of 33 pass |
| `npm run test:e2e:packaged` | 15 of 15 pass |

Lint, the unit tests and the journeys ran on b6a6151; the second commit
changes `build.files` only, which none of the three reads.

</details>

<details>
<summary>Implementation notes</summary>

`app.asar` on macOS arm64, unsigned, `npm run pack:dir`:

| State | Size |
|---|---|
| After the update, before the exclusions | 238,010,661 bytes |
| With the exclusions | 199,873,553 bytes |

The size on `trunk` was not measured.

Packages excluded: `esbuild`, `@esbuild/*`, `@base-ui/*`, `@date-fns/*`,
`@daypicker/*`, `react-day-picker`, `reselect`, `tabbable`,
`colorjs.io`, `@wordpress/base-styles`, `@wordpress/kebab-case`,
`@wordpress/style-runtime`, `@wordpress/ui`. The list is the difference
between the two lockfiles in what is not marked dev-only.

`@wordpress/components` 41 injects part of its CSS at run time through
`@wordpress/style-runtime`. The renderer's content security policy
already allows it (`style-src 'self' 'unsafe-inline'`).

</details>

<details>
<summary>Screenshots or recording</summary>

No images attached. The comparison was made between the committed docs
screenshots and the same twelve shots captured on this branch with `npm
run shots`. What differs:

- Button labels are set in weight 500.
- Text fields are 40px tall instead of 36px.
- Menu items are more compact.
- In "Logs", the selected tab has black text and a grey underline; it
was blue.
- The sidebar title wrapped onto two lines before the fix in this PR,
and is on one line with it.

</details>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@zaerl zaerl added this to the v2.0.0 milestone Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant