Skip to content

JSX v4: keep an async component's @directive on its own function - #9289

Open
jfrolich wants to merge 1 commit into
rescript-lang:masterfrom
tellahq:jsx-async-directive
Open

jfrolich wants to merge 1 commit into
rescript-lang:masterfrom
tellahq:jsx-async-directive

Conversation

@jfrolich

Copy link
Copy Markdown
Collaborator

The JSX PPX moved every attribute of a component's function onto the generated props => make(props) wrapper. For an async component that wrapper is a sync function returning make's promise, so

@react.component
let make = @directive("'use cache'") async (~id) => ...

compiled to function Name(props) { 'use cache'; return make(props); }, which Next.js rejects ("'use cache' functions must be async"). A directive on an async component now stays on make, which the wrapper then reduces to. Sync components are unchanged: their wrapper inlines make, so the directive already lands on the one function.

@github-actions

github-actions Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Changelog

🐛 Bug fix

  • JSX v4: keep @directive on an async component's own function instead of its generated sync wrapper, so @react.component let make = @directive("'use cache'") async (...) => ... compiles to an async function starting with 'use cache', which Next.js accepts.

Semantic Diff

1 commit · Full page

✏️ JSX v4: keep an async component's @directive on its own function

19ea2c4 · open-session-os-tella-dev[bot] + Jaap Frolich · Nov 09, 2026, 19:12 UTC · edited

The JSX PPX moved every attribute of a component's function onto the generated props => make(props) wrapper. For an async component that wrapper is a sync function returning make's promise, so

@react.component let make = @directive("'use cache'") async (~id) => ...

compiled to function Name(props) { 'use cache'; return make(props); }, which Next.js rejects ("'use cache' functions must be async"). A directive on an async component now stays on make, which the wrapper then reduces to. Sync components are unchanged: their wrapper inlines make, so the directive already lands on the one function.

@codecov

codecov Bot commented Nov 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.92%. Comparing base (b82d944) to head (8f971d7).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #9289   +/-   ##
=======================================
  Coverage   81.92%   81.92%           
=======================================
  Files         456      456           
  Lines       65464    65468    +4     
=======================================
+ Hits        53631    53635    +4     
  Misses      11833    11833           
Files with missing lines Coverage Δ
compiler/syntax/src/jsx_v4.ml 86.98% <100.00%> (+0.09%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pkg-pr-new

pkg-pr-new Bot commented Nov 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript@9289

@rescript/belt

npm i https://pkg.pr.new/@rescript/belt@9289

@rescript/darwin-arm64

npm i https://pkg.pr.new/@rescript/darwin-arm64@9289

@rescript/linux-arm64

npm i https://pkg.pr.new/@rescript/linux-arm64@9289

@rescript/linux-x64

npm i https://pkg.pr.new/@rescript/linux-x64@9289

@rescript/runtime

npm i https://pkg.pr.new/@rescript/runtime@9289

@rescript/win32-x64

npm i https://pkg.pr.new/@rescript/win32-x64@9289

commit: 8f971d7

@cknitt

cknitt commented Nov 13, 2026

Copy link
Copy Markdown
Member

@jfrolich could you rebase on latest master, and have your agent follow the new changelog workflow?

The JSX PPX moved every attribute of a component's function onto the
generated props => make(props) wrapper. For an async component that wrapper
is a sync function returning make's promise, so

  @react.component
  let make = @directive("'use cache'") async (~id) => ...

compiled to function Name(props) { 'use cache'; return make(props); },
which Next.js rejects ("'use cache' functions must be async"). A directive
on an async component now stays on make, which the wrapper then reduces to.
Sync components are unchanged: their wrapper inlines make, so the directive
already lands on the one function.

Signed-off-by: Jaap Frolich <[email protected]>
Co-authored-by: Jaap Frolich <[email protected]>
Session: https://os.submodule.nl/session/os-01a1d60a-44bb-7e9a-aa09-a62c0e5a22fd
@jfrolich
jfrolich force-pushed the jsx-async-directive branch from 8f971d7 to 19ea2c4 Compare November 13, 2026 18:48

This branch has not been deployed

No deployments
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.

2 participants