You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR resolves a compiler/runtime contract mismatch where react-compiler-runtime was missing exports that the React Compiler emits in compiled code when certain features are enabled.
Problem: The compiler's test/playground configuration (testComplexConfigDefaults in TestUtils.ts) enables three features that generate imports from react-compiler-runtime:
However, the runtime package did not export these helpers. The existing $makeReadOnly threw a TODO error, causing compiled code to crash at runtime.
Solution: This PR implements and exports the three missing helpers with correct semantics:
makeReadOnly(val, source) — Mutation-tracking proxy for dev-mode debugging. Implementation inlined from the existing make-read-only-util package (to avoid adding dependencies). Logs console.error when values the compiler treats as immutable are mutated. Also aliases $makeReadOnly to this implementation.
shouldInstrument — Exported as const shouldInstrument: boolean = true. The compiler emits this as a bare identifier in if (DEV && shouldInstrument), not as a function call. Value is true since the DEV global already provides the dev/prod gate.
useContext_withSelector(context, selector) — Correctness-first fallback that delegates to React.useContext(context) (ignoring the selector). The selector enables future optimizations; this implementation is semantically correct for React 17/18/19.
This PR also adds Jest test infrastructure and comprehensive export surface tests to prevent future drift.
How did you test this change?
1. New Unit Tests
cd /Users/huy/Desktop/react/compiler
yarn workspace react-compiler-runtime test
Result: [x] All 14 tests passed
Test Coverage:
All required exports are present with correct types
makeReadOnly handles primitives, objects, and logs mutations
shouldInstrument is a boolean (not a function)
$makeReadOnly no longer throws TODO error
useContext_withSelector is callable
Output:
PASS src/__tests__/exports.test.ts
react-compiler-runtime export surface
✓ exports c (memo cache polyfill) (1 ms)
✓ exports $dispatcherGuard (hook guards) (1 ms)
✓ exports $structuralCheck (change detection)
✓ exports useRenderCounter (instrumentation)
✓ exports $reset
✓ exports makeReadOnly (enableEmitFreeze)
✓ exports $makeReadOnly as alias for makeReadOnly
✓ $makeReadOnly does not throw TODO
✓ exports shouldInstrument (enableEmitInstrumentForget gating)
✓ exports useContext_withSelector (lowerContextAccess)
makeReadOnly
✓ returns primitive values unchanged (1 ms)
✓ returns same object reference
✓ logs error on mutation of frozen property
✓ source parameter is optional (1 ms)
Test Suites: 1 passed, 1 total
Tests: 14 passed, 14 total
Result: [x] No error (previously threw: "TODO: implement $makeReadOnly")
4. Before/After Comparison
Before this PR:
makeReadOnly was undefined
shouldInstrument was undefined
useContext_withSelector was undefined
$makeReadOnly() threw error: "TODO: implement $makeReadOnly in react-compiler-runtime"
Compiled code with these features enabled would crash at runtime
After this PR:
All three helpers are properly exported
$makeReadOnly is now a working alias for makeReadOnly
Compiled code executes successfully
Mutation tracking works in dev mode (logs to console)
5. Files Changed
compiler/packages/react-compiler-runtime/jest.config.js (new file)
compiler/packages/react-compiler-runtime/package.json (modified)
compiler/packages/react-compiler-runtime/src/__tests__/exports.test.ts (new file)
compiler/packages/react-compiler-runtime/src/index.ts (modified)
Total changes: 4 files changed, 275 insertions(+), 3 deletions(-)
Miscellaneous
No breaking changes: No existing public API behavior is modified (except $makeReadOnly which was non-functional and threw an error)
Backward compatible: Works with React 17/18/19 (the full peer dependency range: ^17.0.0 || ^18.0.0 || ^19.0.0)
Consistent semantics: The makeReadOnly implementation is inlined from the repo's existing make-read-only-util package, ensuring consistency
Safe fallback:useContext_withSelector returns semantically correct values (full context object). Future optimizations can be added without breaking the contract
Zero new dependencies: Implementation is self-contained, no new packages added to react-compiler-runtime
Test coverage: Comprehensive tests prevent future regression
This PR fixes a critical compiler/runtime contract mismatch where the React Compiler's test configuration enabled three features that import helpers from react-compiler-runtime, but the runtime package was missing those exports.
Changes Made:
makeReadOnly(val, source) - Implemented mutation-tracking proxy for dev-mode debugging. The implementation is correctly inlined from the existing make-read-only-util package with simplified logging (direct console.error instead of callback-based logging). Returns primitives unchanged and wraps objects with property descriptors to detect mutations.
shouldInstrument - Exported as const shouldInstrument: boolean = true. Correctly implemented as a boolean constant (not a function) since the compiler emits it as a bare identifier in conditional expressions.
useContext_withSelector(context, selector) - Implemented as a fallback that delegates to React.useContext(context) while ignoring the selector parameter. This is semantically correct for all React versions and provides a foundation for future optimization.
$makeReadOnly - Changed from throwing a TODO error to being an alias for makeReadOnly, maintaining backwards compatibility.
Test Infrastructure - Added comprehensive Jest tests that verify all exports exist and function correctly, preventing future contract drift.
The implementation is well-documented, follows existing patterns in the codebase, and includes no breaking changes.
Confidence Score: 5/5
This PR is safe to merge with no issues found.
The implementation correctly addresses the stated problem with well-tested, production-ready code. The makeReadOnly implementation is faithfully adapted from the existing make-read-only-util package, shouldInstrument is correctly exported as a boolean constant, and useContext_withSelector provides a semantically correct fallback. Comprehensive tests verify all exports and prevent regression. No breaking changes, security issues, or logical errors were found.
Implements three missing runtime helpers (makeReadOnly, shouldInstrument, useContext_withSelector) that fix compiler/runtime contract mismatch. Implementation is correct and well-documented.
Comprehensive regression tests verify all required exports exist and function correctly. Tests prevent future contract drift between compiler and runtime.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mirror of facebook/react#35773
Original author: itsnothuy
Summary
This PR resolves a compiler/runtime contract mismatch where
react-compiler-runtimewas missing exports that the React Compiler emits in compiled code when certain features are enabled.Problem: The compiler's test/playground configuration (
testComplexConfigDefaultsinTestUtils.ts) enables three features that generate imports fromreact-compiler-runtime:enableEmitFreeze→ importsmakeReadOnlyenableEmitInstrumentForget.gating→ importsshouldInstrumentlowerContextAccess→ importsuseContext_withSelectorHowever, the runtime package did not export these helpers. The existing
$makeReadOnlythrew a TODO error, causing compiled code to crash at runtime.Solution: This PR implements and exports the three missing helpers with correct semantics:
makeReadOnly(val, source)— Mutation-tracking proxy for dev-mode debugging. Implementation inlined from the existingmake-read-only-utilpackage (to avoid adding dependencies). Logsconsole.errorwhen values the compiler treats as immutable are mutated. Also aliases$makeReadOnlyto this implementation.shouldInstrument— Exported asconst shouldInstrument: boolean = true. The compiler emits this as a bare identifier inif (DEV && shouldInstrument), not as a function call. Value istruesince theDEVglobal already provides the dev/prod gate.useContext_withSelector(context, selector)— Correctness-first fallback that delegates toReact.useContext(context)(ignoring the selector). The selector enables future optimizations; this implementation is semantically correct for React 17/18/19.This PR also adds Jest test infrastructure and comprehensive export surface tests to prevent future drift.
How did you test this change?
1. New Unit Tests
Result: [x] All 14 tests passed
Test Coverage:
makeReadOnlyhandles primitives, objects, and logs mutationsshouldInstrumentis a boolean (not a function)$makeReadOnlyno longer throws TODO erroruseContext_withSelectoris callableOutput:
2. Lint Checks
cd /Users/huy/Desktop/react yarn lincResult: [x] Lint passed for changed files
3. Manual Verification
Verify exports are present:
Output:
Verify $makeReadOnly no longer throws:
node -e "require('./compiler/packages/react-compiler-runtime/dist/index.js').\$makeReadOnly('test', 'source')"Result: [x] No error (previously threw: "TODO: implement $makeReadOnly")
4. Before/After Comparison
Before this PR:
makeReadOnlywasundefinedshouldInstrumentwasundefineduseContext_withSelectorwasundefined$makeReadOnly()threw error:"TODO: implement $makeReadOnly in react-compiler-runtime"After this PR:
$makeReadOnlyis now a working alias formakeReadOnly5. Files Changed
Total changes: 4 files changed, 275 insertions(+), 3 deletions(-)
Miscellaneous
No breaking changes: No existing public API behavior is modified (except
$makeReadOnlywhich was non-functional and threw an error)Backward compatible: Works with React 17/18/19 (the full peer dependency range:
^17.0.0 || ^18.0.0 || ^19.0.0)Consistent semantics: The
makeReadOnlyimplementation is inlined from the repo's existingmake-read-only-utilpackage, ensuring consistencySafe fallback:
useContext_withSelectorreturns semantically correct values (full context object). Future optimizations can be added without breaking the contractZero new dependencies: Implementation is self-contained, no new packages added to
react-compiler-runtimeTest coverage: Comprehensive tests prevent future regression