Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Backport React 19 use API - #32

Draft
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use
Draft

Backport React 19 use API#32
christopher-buss wants to merge 65 commits into
Roblox:mainfrom
christopher-buss:backport-react-19-use

Conversation

@christopher-buss

@christopher-busschristopher-buss commented Aug 31, 2026

Copy link
Copy Markdown

Summary

  • add stable React 19.2 use(Context) and cached Promise-compatible thenable reads
  • add generic reconciler thenable tracking, opaque suspension bridging, and retry/error behavior
  • support conditional and looped use calls without normal Hook ordering
  • add Debug Tools, shallow renderer, API docs, and a pinned upstream ledger

Compatibility boundary

This is the client cached-Promise API. Promises must be created and cached outside render, must settle normally, and expose andThen. React 19 server/RSC behavior, cache APIs, hydration, sibling prewarming, Actions, Promise-as-child, async components, and uncached component replay are excluded. Roblox Promise cancellation is unsupported because ordinary andThen listeners are not notified reliably.

React-Luau 17 has no React 19 SuspendedOnImmediate replay state machine. The opaque use exception is therefore converted before the existing unwind, Suspense capture, ping, and retry path; the cached Promise's instrumented status survives the retry.

Provenance

  • runtime and tests are pinned to React 19.2.0 at ae74234eae6ebd62f19190731278e20bc1c37d51
  • the swallowed try/catch warning follows ReactUse-test.js lines 534-568: exactly one warning containing the complete upstream text
  • React 17's console harness appends the component stack, so the translated toErrorDev assertion validates the stack instead of incorrectly requiring its absence; this adaptation is marked at the test site

The implementation and complete test/deviation classification are pinned in docs/backports/react-19-use.md.

Verification

Exact candidate: cf0a258d87d06fb09f13fb549f5564d1123f77d6 / tree f82a837524a8281e9c3af8c6e8450124b056bc77

  • preserved RED baseline at 28c57e5d4ab256956980c4fd3bf9f4d3c865630e: identity 1/1; ReactUse 13/14, with the expected warning text/count and component stack rejected only by the unsupported no-stack matcher option
  • hardened Studio debug.loadmodule rerun: identity 1/1 and complete ReactUse 14/14, including the try/catch warning regression
  • archive SHA-256: 1E1168AB3994E61A079852A148CCD70E4965C1C65374EF31E729337CBF92B59F
  • project SHA-256: 2302E858AE23831EBBE5FF0BFF2A351940F97CF6CEFE78C733940E835910457D
  • config SHA-256: A5800572BCEBADA709F02E0BA9C9E486EEC8919B40CBCDBFD7D5D71BF07E7C71
  • ReactUse Jest SHA-256: FAEEADA030DAA0BC6D41CBB8085E1CED9E3A1F3E13E7FA81FD2B6D03A5050E67
  • identity Jest SHA-256: D9984A6FE84B2A031B55DA85B5470C88EFAF73C4F7819C3434FA3159F8E84A59
  • full Selene 0.28.0: passed
  • full StyLua 0.18.1 check: passed
  • Luau bytecode compilation for every changed Lua file: passed
  • WorkLoop compiler register probe: R188, matching the known-good reconciler chunk
  • git diff and public privacy checks: passed
  • canonical bin/ci.sh: dependency installation, Roblox analysis, and DEV/release runtime stages remain unavailable locally because the pinned Roblox-internal Foreman sources and required CLI binaries are not accessible

Generated with Codex.

Anonymous Authorand others added 30 commits February 13, 2025 12:05
Small update to RefObject. Should be backwards compatible with a default
of any.
Without export there is no way to use it? 😿
---------
This PR makes it possible to use `React.Profiler` in production code by
setting the `_G.__PROFILE__` flag. In particular, we:
1. Disable `enableProfiling` from SchedulerFeatureFlags.lua to be
consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/scheduler/src/SchedulerFeatureFlags.js#L10)
3. Disable `enableSchedulerTracing` since it was removed in newer
versions [upstream](react/react#20037)
2. Enable `enableProfilerCommitHooks` to be consistent with
[upstream](https://github.com/facebook/react/blob/main/packages/shared/ReactFeatureFlags.js#L252-L253)
I also deleted an old workflow which was failing OSS leak scan. It was
set up to send PR review reminders to a now-defunct channel, so it was
obviously not being used. We can add this back later if the team decides
they want it in the future.
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
…(#427)
Allow for setting scheduler flags at runtime. This is needed to support
IXP from lua-apps.
This wasn't exported properly
Adds the root child component name to the "Rendered with fewer hooks
than expected" error. This can help narrow down where the error is
coming from slightly.
https://roblox.atlassian.net/browse/APPEXP-2466
We see errors logged occasionally when enabling Root-level MP because
`profileend` is called when there are no active profiles. This seems to
be because profiles automatically end when the frame is yielded, and the
previous [fix](https://github.com/Roblox/roact-alignment/pull/413)
wasn't sufficient at addressing this.
To fix this, we now tally the number of active profiles in the current
frame, and check to make sure this number is >=0 before any profileend.
Change also bumps FFlagReactMicroprofilerLevel4.
To test - I keep the tally code but still let it profileend as it did
before. This confirms the error happens when `numActiveProfilesInFrame
<= 0`. Also tested with the fix as is, and never see the error.
<img width="1183" alt="Screenshot 2025-03-25 at 11 42 59 AM"
src="https://github.com/user-attachments/assets/cd817eed-a45d-4230-805e-68d9346765ed"
/>
Also validate that microprofiler root labeling is still working
<img width="500" alt="Screenshot 2025-03-25 at 3 53 12 PM"
src="https://github.com/user-attachments/assets/f32d6ae5-9c0f-4b74-a71c-5fcc54a86ac9"
/>
UIBlox Button component implementation triggered a react warning that
setState is called when we render component.
However this warning crashed the test because renderingComponentName
could be nil.
[Apps-fastFlags-allOff] ERR TestService: Error: table index is nil
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3499
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:640
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1893
function dispatchAction
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:1195
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.CursorProvider:82
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.SelectionCursor.useCursor:9
function useCursor
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.UIBlox.UIBlox.App.Button.Button:222
[Apps-fastFlags-allOff]
CorePackages.Packages._Index.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3124
function renderWithHooks
Reproducible when turn on the test in UniversalApp.spec.lua Fixing this table index is nil by giving nil case a default value and
improve the getComponentName function for anonymous function
Upgrades CI tools (selene was almost 4 years old)
Upgrades StyLua to support modern Luau features and fixes styles that
broke because of the upgrade.
Implements core React Devtools functionality, with lots of outstanding issues and bugs.
NOTE TO COMMUNITY: This isn't ready yet!! Please hold your horses!
Adds pcall around unprotected index in typeOf() from react-is to prevent
`strict()` wrapped tables from erroring.
Fixes nil exception when changing component props and state from
DevTools inspector.
…ools (#445)
Fixed element selection from DevTools not working. Closes two tickets in
Jira.
…ve Heartbeat event. (#449)
Closes (ISSUES HERE).
https://roblox.atlassian.net/browse/APPEXP-2466
When some codes yields to a new frame, the existing debug.profilebegin
will be cleaned up, so on the react profiling side, we should also reset
the state. Before it is using the RenderStepped, it appears too late for
some cases, the heartbeat solved this issue.
…n't sync over components and other state (#447)
Sets up the `_G.__REACT_DEVTOOLS_ATTACH__` hook so that the React
renderer starts collecting data for DevTools immediately, before
DevTools actually connects. This should help solve a few use cases (such
as profiling on start), but primarily it fixes the bug where launching
DevTools after the client starts doesn't sync state up properly.
… set personality to x86_64: Operation not permitted` (#453)
## Problem
while working on making benchmarks more stable in Foundation, noticed we
have a few things broken in roact-alignment
## Solution
- Passing `--privileged` as suggested
[here](https://roblox.slack.com/archives/C0112GAH0A1/p1752275111589509?thread_ts=1752272650.441599&cid=C0112GAH0A1)
to fix setarch permissions
## Testing
before
`setarch: failed to set personality to x86_64: Operation not permitted`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16327087530/job/46119943628))
with `--privileged`
([logs](https://github.com/Roblox/roact-alignment/actions/runs/16275837938/job/45954396993?pr=453))
```
Run ./bin/run-with-cachegrind.sh ./robloxdev-cli bin/run-first-render-benchmark.lua "FirstRenderCold" 1 | tee -a run-first-render-benchmark-output.txt
--597-- warning: L3 cache found, using its data for the LL simulation.
--597-- warning: specified LL cache: line_size 64 assoc 11 total_size 25,952,256
--597-- warning: simulated LL cache: line_size 64 assoc 12 total_size 25,165,824
[598:598:20250714,192142.632134:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.647548:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648049:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648375:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648677:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
[598:598:20250714,192142.648966:WARNING close_multiple.cc:67] close: Bad file descriptor (9)
./bin/run-with-cachegrind.sh: line 56: bc: command not found
```
after using `awk`
```
MountDeepTreeCGCold#TotalInstructionsExecuted x 1115357635.0000000000 executions ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_InstrReadCacheMisses x 0.0035760000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_InstrReadCacheMisses x 0.0001560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryReads x 269488858.0000000000 reads ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataReadCacheMisses x 0.0289310000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataReadCacheMisses x 0.0015050000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#TotalMemoryWrites x 149201992.0000000000 writes ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#L1_DataWriteCacheMisses x 0.0170560000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
MountDeepTreeCGCold#LL_DataWriteCacheMisses x 0.0090970000 misses/op ±0% (1 runs sampled)(roblox-cli version 0.682.0.682053849c0feadbc2a121e2464839b021c22701a0b1e7f)
```
Ports ReactFreshRuntime.lua and the remainder of
ReactFiberHotReloading.new.lua to support HMR.
---------
Closes [UIBLOX-2787](https://roblox.atlassian.net/browse/UIBLOX-2787).
Implements a small example app to make testing DevTools and other React
features easier. The example app itself is taken from the HMR repo.
### Why are the changes being made?
Closes [UIBLOX-2778](https://roblox.atlassian.net/browse/UIBLOX-2778).
Fixes a few bugs with native element highlights in Devtools:
- We now make sure that an instance is a GuiBase2d before trying to read
UI properties
- OverlayTip now accounts for a global ZIndex
- Focusing the viewport no longer ends selection (e.g. clicking from
devtools into studio)
- Overlapping highlight rects no longer stack their transparency
Anonymous Authorand others added 22 commits September 30, 2025 17:58
### Why are the changes being made?
When re-rendering a component using derived state idiom for functional
components, if the component had any useCallbacks inside it, React would
error with `Rendered more hooks than during the previous render.` when
in DEV mode.
It looks like this was caused by a mistranslation where instead of
calling updateCallback, we would call mountCallback in DEV mode. Note
that in non-DEV mode, we already call the correct api (updateCallback)
and this seems to be a mistranslation since this was implemented
correctly in upstream:
https://github.com/facebook/react/blob/43363e2795393a00fd77312a16d6b80e626c29de/packages/react-reconciler/src/ReactFiberHooks.new.js#L2289
Unflagged because it's under DEV mode.
### Why are the changes being made?
Closes [UIBLOX-3203](https://roblox.atlassian.net/browse/UIBLOX-3203).
Repository facelift!
- Clears out the root readme because everything there was outdated
and/or not useful for anyone
- Rewrites the readme with better branding and no internal jargon
- Adds a gitattributes file for luau
- Removes the deviations.md file as it was just a to-do file for roact
and all were resolved
- Removes standalone/ directory because it was unused
- Removes the examples/ directory because all the examples were outdated
and most showed code style we don't want to encourage
- We'll be showing better code examples in the upcoming docs refresh
Currently the readme is pretty empty. Once the docs are refreshed the
readme can be added to with useful information.
### Why are the changes being made?
Closes [UIBLOX-3261](https://roblox.atlassian.net/browse/UIBLOX-3261).
Adds a new flag for React to catch any fiber that yields when in DEV
mode. Nothing in React supports yielding today, and when you do yield it
often results in undefined behaviour. This flag enables an explicit
error telling the user that their code is yielding.
### What changes are being made?
- Adds `catchYieldingInDEV` feature flag and integrates it into React
scheduler to error on yielding within components/hooks during DEV mode
- Implements `NoYield` utility to enforce no-yield behavior in callbacks
- Updates `ReactFeatureFlags` and adds comprehensive tests for the new
yield-catching mechanism
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Just cleaning up flags that are completely unused in React today. They
have no reference anywhere else in the code.
### What changes are being made?
- Removes 13 unused feature flags from the `ReactFeatureFlags` module. - Cleans up related test files to eliminate obsolete feature flag
references.
- Improves maintainability by reducing dead code and configurations.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Adds documentation to the bulk of React's public API for a better editor
experience.
### What changes are being made?
- Adds detailed documentation comments to most React public APIs in
`react-roblox`, covering functions, hooks, and components.
- Enhances code readability and editor support with parameter
descriptions, return values, and official React API reference links.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3280](https://roblox.atlassian.net/browse/UIBLOX-3280).
React stacktraces kinda suck right now. They can be huge and the vast
majority of the frames in the stacktrace are from React internal
modules. This gets worse the larger the tree is due to React's
recursion. This PR:
- Introduces a new feature flag for filtering stack frames
- Implements a best-effort algorithm for determining if a stack frame is
from inside React
- Works out the path of known React packages in the datamodel and then
checks if the frame is under one of those paths
- Does not filter any stack frame if the first stack frame is from
inside React (i.e the error originated internally)
Before:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberHooks.new:3196 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:209 function renderWithHooks
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:867 function updateFunctionComponent
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberBeginWork.new:3509 function beginWork
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:253
CorePackages._Workspace.Shared.Shared.invokeGuardedCallbackImpl:30 function invokeGuardedCallbackProd
CorePackages._Workspace.Shared.Shared.ReactErrorUtils:49
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:3474
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1972
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1860
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:1809
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:942
CorePackages._Workspace.ReactReconciler.ReactReconciler.ReactFiberWorkLoop.new:858
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:320
CorePackages._Workspace.Scheduler.Scheduler.Scheduler:268
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:241 function doWork
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:277 function performWorkUntilDeadline
```
After:
```
CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:316: CorePackages._Workspace.Scheduler.Scheduler.forks.SchedulerHostConfig.default:293: ------ Error caught by React ------
Something went very wrong!
------ Error caught by React ------
CorePackages._Workspace.ExampleApp.ExampleApp.someLibraryModule:4 function intentionallyFailingMethod
CorePackages._Workspace.ExampleApp.ExampleApp.NameTag:25 function Name
```
### What changes are being made?
- Adds `filterInternalStackFrames` feature flag to exclude React
internal stack frames from error traces for improved readability.
- Implements `buildStackString` function to construct filtered stack
traces by identifying and omitting known React internal modules.
- Updates `describeError` to apply stack frame filtering based on the
new feature flag while preserving unfiltered errors from React
internals.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Closes [UIBLOX-3163](https://roblox.atlassian.net/browse/UIBLOX-3163).
Updates DevTools to use the new user-space WebSocket API that's
developer-accessible in Studio. This unblocks a couple of internal teams
adopting DevTools, and will allow the wider community to use it as well.
This change is flagged behind `ReactDevtoolsUseHttpWebStream` because
I'd like to get it out sooner rather than later, but releasing it
without waiting a few weeks will probably break some internal workflows
(e.g. people on an outdated version of studio). Once the new API has
been live for a month or so I'll come back and clean up the flag.
### What changes are being made?
- Updates DevTools to use `HttpService:CreateWebStreamClient` and
renders GUI in `Players.LocalPlayer.PlayerGui` with adjusted `App.lua`
GUI properties for user-space compatibility.
---
- [x] AI-assisted summary reviewed and verified by author
As mentioned in #488 we noticed that the rotriever version used in the
repo is so old that one of the bugs in it was causing non-publish
packages to become published.
This PR bumps the rotriever version to pull in any more modern bugfixes
and features :)
While working on publishing this repo to the Creator Store, I noticed
that some `publish = true` packages depend on the following `publish =
false` packages:
- `modules/react-noop-renderer`
- `modules/scheduler`
- `modules/shared`
This breaks our Creator Store publishing workflow as we assume `publish
= false` packages should not be included in the final build, but
depending on them from a `publish = true` package conflicts with this.
Furthermore, it turns out the rotriever version used in this repo is old
enough that this setting isn't respected anyway, so all of the
nonpublish packages are, in fact, published:
https://rotriever.simulprod.com/package/Shared
So this PR removes the `publish = false` declarations from the rotriever
TOMLs since they aren't doing anything (except breaking our automation!)
and don't seem to make sense anyway given they're publicly depended
upon. It is better to have these TOMLs reflect their actual behaviour so
that rotriever can be safely updated in the future without stopping
updates from being pushed to the registry.
### Why are the changes being made?
Updates the documentation site to use the new `react-luau.dev` URL.
### What changes are being made?
- Updates `mkdocs.yml` site metadata (site name, URL, repo) and fixes
`nav` indentation for nested pages.
---
- [x] AI-assisted summary reviewed and verified by author
### Why are the changes being made?
Updates the error message when a component yields in DEV mode to more
clearly explain the error and point the user towards the doc on
yielding.
### What changes are being made?
- Updates DEV no-yield error in `NoYield.lua` to multi-line; explains
yields stall scheduler and links `go/react-yield-error`
---
- [ ] AI-assisted summary reviewed and verified by author
Implements react/react#21039 on our codebase.
Creates a new deleted tree clean up level with three distinct levels.
Facebook did an experiment and found level 3 to be the best, we should
do the same and see whether the existing path, 1, 2, or 3 is the best.
Rotriever requires readmes for publishing now. Added stubs.
lute versions was too old, foreman couldn't even see it
https://github.com/Roblox/roact-alignment/actions/runs/23354471638/job/67941642914
Checklist before submitting:
* [ ] Added/updated relevant tests
* [ ] Added/updated documentation
Adds a more comprehensive Wally exclude list and bumps the version
number for the use of other packages.
## Summary
- Add runtime scheduler config fields for desired and minimum frame
rates.
- Reset scheduler frame budget state when those frame-rate overrides
change.
- Bump the workspace Rotriever patch version for the Scheduler package
change.
## Test plan
- ReadLints on
`modules/scheduler/src/forks/SchedulerHostConfig.default.lua` and
`rotriever.toml`.
Made with [Cursor](https://cursor.com)
---------
Turns out Jest needs this one, so we're publishing it to Wally :)
Removes Wally from the Foreman TOML as no internal workflows should
depend on Wally, only Rotriever.
Rotriever takes its version from the single `[workspace] version` in
rotriever.toml, while Wally takes one from each modules/*/wally.toml.
Nothing keeps the two in sync and they had drifted: rotriever.toml was
bumped to 17.3.10 alongside the scheduler frame-rate change, but no
Wally manifest was, so a Rotriever publish and a Wally publish from the
same commit emitted different version numbers.
That drift also means 17.3.10 no longer identifies one payload. A
17.3.10 was hand-published to wally-test-index before the scheduler
change landed, so on Wally that number names the older code while on
Rotriever it names the newer. Wally releases have meanwhile been stuck
at 17.3.9, which the index rejects as already published on every run.
Move both version sources to 17.3.11 so a single number means one thing
on every registry, rather than trying to reconcile 17.3.10 on indices
that do not allow republishing.
Co-authored-by: Codex <noreply@openai.com>
christopher-bussand others added 4 commits August 31, 2026 23:55
Load the thenable helper inside the two error paths so Studio debug.loadmodule can compile the near-limit WorkLoop chunk.
Co-authored-by: Codex <noreply@openai.com>
Document the React 17 replay and thenable-tracking divergences, correct pinned source ranges, and make the test ledger match the actual port.
Port the fulfilled-thenable regression and preserve observable scheduler yield order across the translated use cases.
Co-authored-by: Codex <noreply@openai.com>
Match the upstream warning count and text contract while allowing React 17's console harness to append the component stack.
Co-authored-by: Codex <noreply@openai.com>
Use the upstream development wrapper and production array shapes without an unnecessary React-Luau deviation.
Co-authored-by: Codex <noreply@openai.com>
Sign up for freeto 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.

4 participants

@christopher-buss@Nicell@BrookenRecord@dphblox