Repository navigation
fix(render): lazy-load prettier so it's only loaded when pretty is used - #3790
Merged
felipefreitag merged 1 commit intoOct 15, 2026
Merged
felipefreitag merged 1 commit into
felipefreitag merged 1 commit into
Conversation
`pretty.ts` imported `prettier/standalone` and `prettier/plugins/html` at the top level, so every `render()` call loaded prettier, even without `pretty: true`. Next.js externalizes `prettier`, and in `next dev` Turbopack loads it through a hashed alias symlink (`.next/dev/node_modules/prettier-<hash>`) that it creates after the server process has started. Bun's resolver doesn't pick up that late-created symlink, so loading the external fails. Prettier is now imported dynamically the first time `pretty` is called, so `render()` without `pretty` never touches it. Fixes resend#3781 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
@AmineBenzaazaa is attempting to deploy a commit to the resend Team on Vercel. A member of the Team first needs to authorize it. |
馃 Changeset detectedLatest commit: c437dc7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
felipefreitag
approved these changes
Oct 15, 2026
commit: |
Contributor
Author
|
Thanks for the review and merge, @felipefreitag! Happy to help with the remaining |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3781
Problem
pretty.tsimportedprettier/standaloneandprettier/plugins/htmlat module top level, so everyrender()loaded prettier, even withoutpretty: true.Next.js always externalizes
prettier. Innext dev, Turbopack loads externals through a hashed alias symlink (.next/dev/node_modules/prettier-<hash>) that it creates after the server process has started. Bun's resolver doesn't see anode_modulessymlink created after the directory was first resolved (oven-sh/bun#42776, oven-sh/bun#25370), so the import fails withCannot find package 'prettier-<hash>'. Node resolves it fine, andnext build+next starton Bun also works because the symlink already exists at startup.Fix
Import prettier dynamically the first time
pretty()is called (cached afterwards), the same wayrenderalready loadsreact-dom/server.prettywas already async, so the public API is unchanged. As a side effect,render()withoutprettyno longer pays prettier's load cost.Verification
Packed this build and installed it into the reproduction (https://github.com/pthneo/react-email-turbopack-bun-prettier-bug, Next 16.4.0, Bun 1.4.2):
render()withoutpretty: works on Turbopack + Bun (previously failed), Turbopack + Node, webpack + Bun, webpack + Node.render(..., { pretty: true }): works on Turbopack + Node, webpack + Bun and webpack + Node. On Turbopack + Bun in dev it still hits the Bun resolver bug;transpilePackages: ["prettier"]innext.configworks around it.Added a test that prettier isn't loaded until
prettyis called.@react-email/rendertests pass (90/90) andbiome checkis clean.馃 Generated with Claude Code
Summary by cubic
Lazy-loads prettier so
renderno longer loads it unlesspretty: trueis used.Previously
pretty.tsimportedprettier/standaloneandprettier/plugins/htmlat module load time, so everyrender()call loaded prettier. In Next.js dev with Turbopack, prettier is externalized and resolved through a hashed symlink Bun can't pick up after startup, which maderender()fail with "Failed to load external module prettier". Prettier is now imported dynamically on the firstpretty()call, keeping the public API unchanged.render()failing in Next.js dev with Turbopack on Bun.render()withoutprettyno longer pays prettier's load cost.prettyis called.Written for commit c437dc7. Summary will update on new commits.