fix(render): lazy-load prettier so it's only loaded when pretty is used
Fixes #3781
Problem
pretty.ts imported prettier/standalone and prettier/plugins/html at module top level, so every render() loaded prettier, even without pretty: true.
Next.js always externalizes prettier. In next 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 a node_modules symlink created after the directory was first resolved (oven-sh/bun#42776, oven-sh/bun#25370), so the import fails with Cannot find package 'prettier-<hash>'. Node resolves it fine, and next build + next start on Bun also works because the symlink already exists at startup.
Fix
Import prettier dynamically the first time pretty() is called (cached afterwards), the same way render already loads react-dom/server. pretty was already async, so the public API is unchanged. As a side effect, render() without pretty no 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 pretty is called. @react-email/render tests pass (90/90) and biome check is clean.
š¤ Generated with Claude Code
Summary by cubic
Lazy-loads prettier so render no longer loads it unless pretty: true is used.
Previously pretty.ts imported prettier/standalone and prettier/plugins/html at module load time, so every render() 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 made render() fail with "Failed to load external module prettier". Prettier is now imported dynamically on the first pretty() call, keeping the public API unchanged.
- Fixes
render()failing in Next.js dev with Turbopack on Bun. render()withoutprettyno longer pays prettier's load cost.- Adds a test verifying prettier isn't loaded until
prettyis called.