Skip to content

Commit f86c684

Browse files
justin808claude
andcommitted
Add comprehensive React 19 upgrade documentation
Created detailed documentation to help users upgrade from React 18 to React 19: 1. **react-19-upgrade-guide.md** - Complete upgrade guide covering: - Breaking changes and their impact - Step-by-step upgrade instructions - TypeScript configuration options - React Server Components considerations - Common issues and solutions - Testing and rollback procedures 2. **react-19-quick-reference.md** - Quick reference cheat sheet with: - Pre-flight checklist - Common import fix patterns - Build verification steps - Troubleshooting table - Rollback commands 3. **upgrading-react-on-rails.md** - Updated main upgrade doc with: - Link to React 19 upgrade guide - Summary of key React 19 changes Key topics covered: - Conditional package exports in React 19 - TypeScript esModuleInterop configuration - Named vs namespace imports - RSC (React Server Components) requirements - Build troubleshooting This documentation addresses the React 19 compatibility issues we fixed in the previous commit and provides users with clear guidance for their own upgrades. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent f9f791b commit f86c684

File tree

4 files changed

+753
-0
lines changed

4 files changed

+753
-0
lines changed

PR_SUMMARY_REACT_19_FIX.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# React 19 Compatibility Fix - PR Summary
2+
3+
## Branch
4+
5+
`justin808/shakapacker-9.3.0`
6+
7+
## Status
8+
9+
**READY TO MERGE**
10+
11+
## What Changed
12+
13+
Master now has **Shakapacker 9.2.0**, so the only remaining issue is React 19 import compatibility.
14+
15+
### The Problem
16+
17+
React 19 introduced conditional package exports:
18+
19+
- `react.react-server.js` - Server-only build (no hooks, Context, Component)
20+
- `index.js` - Full React with all APIs
21+
22+
Our TypeScript configuration (`esModuleInterop: false`) was compiling:
23+
24+
```typescript
25+
import * as React from 'react';
26+
```
27+
28+
Into invalid JavaScript:
29+
30+
```javascript
31+
import ReactClient from 'react/index.js';
32+
```
33+
34+
This tried to access a non-existent default export, causing webpack errors:
35+
36+
- `export 'createContext' was not found in 'react'`
37+
- `export 'useContext' was not found in 'react'`
38+
- `export 'Component' was not found in 'react'`
39+
40+
### The Solution
41+
42+
Use named imports directly:
43+
44+
```typescript
45+
// RSCProvider.tsx
46+
import { createContext, useContext, type ReactNode } from 'react';
47+
48+
// RSCRoute.tsx
49+
import { Component, use, type ReactNode } from 'react';
50+
```
51+
52+
This generates proper ES module imports that work with React 19's export structure.
53+
54+
## Commits on This Branch
55+
56+
1. **c1a8229d** - Fix React 19 server bundle errors by using named imports (WORKING FIX)
57+
2. **7a9f5397** - Fix React 18.0.0 compatibility by using React namespace imports (BROKE IT)
58+
3. **f9f791bf** - Revert "Fix React 18.0.0 compatibility..." (RESTORED WORKING FIX)
59+
60+
## Files Changed
61+
62+
- `packages/react-on-rails-pro/src/RSCProvider.tsx` - Changed to named imports
63+
- `packages/react-on-rails-pro/src/RSCRoute.tsx` - Changed to named imports
64+
- `packages/react-on-rails-pro/lib/*.js` - Compiled output (correct after rebuild)
65+
66+
## Testing Done
67+
68+
✅ RuboCop passes with zero offenses
69+
✅ Webpack build completes successfully
70+
✅ No React import errors in webpack output
71+
✅ Pro package rebuilt and pushed to yalc
72+
✅ Dummy app builds without RSC import errors
73+
74+
## PR Title
75+
76+
```
77+
Fix React 19 compatibility with named imports in RSC components
78+
```
79+
80+
## PR Description
81+
82+
```markdown
83+
## Problem
84+
85+
React 19 introduced conditional package exports that broke our TypeScript compilation. With `esModuleInterop: false`, namespace imports (`import * as React`) were being compiled to invalid default imports (`import ReactClient from 'react/index.js'`), causing webpack to fail with:
86+
87+
- `export 'createContext' was not found in 'react'`
88+
- `export 'useContext' was not found in 'react'`
89+
- `export 'Component' was not found in 'react'`
90+
91+
## Solution
92+
93+
Changed to named imports in RSCProvider and RSCRoute:
94+
95+
- `import { createContext, useContext, type ReactNode } from 'react'`
96+
- `import { Component, use, type ReactNode } from 'react'`
97+
98+
This generates proper ES module imports that work with React 19's package.json exports.
99+
100+
## Testing
101+
102+
- ✅ Webpack builds complete without React import errors
103+
- ✅ RuboCop passes
104+
- ✅ Pro dummy app builds successfully
105+
- ✅ RSC components compile correctly
106+
107+
## Context
108+
109+
Master now has Shakapacker 9.2.0 (#1931), so this is the final piece needed for React 19 compatibility.
110+
111+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
112+
113+
Co-Authored-By: Claude <[email protected]>
114+
```
115+
116+
## Next Steps
117+
118+
1. **Check CI status** after push:
119+
120+
```bash
121+
gh pr view --json statusCheckRollup
122+
```
123+
124+
2. **If PR doesn't exist**, create it:
125+
126+
```bash
127+
gh pr create --title "Fix React 19 compatibility with named imports in RSC components" \
128+
--body "See PR_SUMMARY_REACT_19_FIX.md for details" \
129+
--base master
130+
```
131+
132+
3. **If PR exists**, it will automatically update with the new commits
133+
134+
## Impact
135+
136+
This is a **critical fix** that unblocks:
137+
138+
- Using React 19 with React on Rails Pro
139+
- Server-side rendering of RSC components
140+
- Proper TypeScript compilation without import errors
141+
142+
## Breaking Changes
143+
144+
None - this is a fix that restores functionality.
145+
146+
## Related Issues
147+
148+
- React 19 conditional exports: https://react.dev/blog/2024/04/25/react-19-upgrade-guide
149+
- TypeScript esModuleInterop: https://www.typescriptlang.org/tsconfig#esModuleInterop
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# React 19 Quick Reference
2+
3+
> For the complete guide, see [React 19 Upgrade Guide](./react-19-upgrade-guide.md)
4+
5+
## Pre-Flight Checklist
6+
7+
```bash
8+
# ✅ Check current versions
9+
node --version # Should be 18+
10+
ruby --version # Should be 3.2+
11+
12+
# ✅ Check dependencies
13+
bundle info react_on_rails # Should be 16.1.1+
14+
bundle info shakapacker # Should be 9.0+
15+
```
16+
17+
## Upgrade Commands
18+
19+
```bash
20+
# 1. Update React
21+
22+
yarn add -D @types/react@19 @types/react-dom@19
23+
24+
# 2. Update React on Rails (if needed)
25+
bundle update react_on_rails
26+
27+
# 3. Rebuild
28+
rm -rf public/packs node_modules/.cache
29+
yarn install
30+
bin/rails assets:precompile
31+
```
32+
33+
## Common Import Fixes
34+
35+
### ❌ BROKEN (with esModuleInterop: false)
36+
37+
```typescript
38+
import * as React from 'react';
39+
40+
class MyComponent extends React.Component {}
41+
const [count, setCount] = React.useState(0);
42+
const context = React.createContext(null);
43+
```
44+
45+
**Error**: `export 'createContext' was not found in 'react'`
46+
47+
### ✅ FIXED - Option A: Enable esModuleInterop
48+
49+
```json
50+
{
51+
"compilerOptions": {
52+
"esModuleInterop": true,
53+
"allowSyntheticDefaultImports": true
54+
}
55+
}
56+
```
57+
58+
```typescript
59+
import React, { useState, createContext } from 'react';
60+
61+
class MyComponent extends React.Component {}
62+
const [count, setCount] = useState(0);
63+
const context = createContext(null);
64+
```
65+
66+
### ✅ FIXED - Option B: Use Named Imports
67+
68+
```typescript
69+
import { Component, useState, createContext } from 'react';
70+
71+
class MyComponent extends Component {}
72+
const [count, setCount] = useState(0);
73+
const context = createContext(null);
74+
```
75+
76+
## RSC Components (Pro)
77+
78+
```typescript
79+
// ✅ Server Component - NO 'use client'
80+
export default async function ServerComponent() {
81+
const data = await fetchData();
82+
return <div>{data}</div>;
83+
}
84+
85+
// ✅ Client Component - HAS 'use client'
86+
'use client';
87+
88+
import { useState } from 'react';
89+
90+
export default function ClientComponent() {
91+
const [count, setCount] = useState(0);
92+
return <button onClick={() => setCount(count + 1)}>{count}</button>;
93+
}
94+
95+
// ✅ RSC Provider/Route - MUST use named imports
96+
'use client';
97+
98+
import { createContext, useContext } from 'react';
99+
100+
const MyContext = createContext(null);
101+
export const useMyContext = () => useContext(MyContext);
102+
```
103+
104+
## Build Verification
105+
106+
```bash
107+
# Should complete without React import errors
108+
bin/shakapacker
109+
110+
# Check for these errors (should be NONE):
111+
# ❌ export 'createContext' was not found
112+
# ❌ export 'useContext' was not found
113+
# ❌ export 'Component' was not found
114+
```
115+
116+
## Troubleshooting
117+
118+
| Error | Quick Fix |
119+
| ------------------------------------------ | ------------------------------------------------------ |
120+
| `export 'X' was not found in 'react'` | Use named imports or enable `esModuleInterop` |
121+
| `Objects are not valid as a React child` | Add second param to render function |
122+
| `Functions are not valid as a React child` | Return React element, not function |
123+
| Build fails in production | Clear cache: `rm -rf node_modules/.cache public/packs` |
124+
125+
## TypeScript Config
126+
127+
### Recommended (Easy Mode)
128+
129+
```json
130+
{
131+
"compilerOptions": {
132+
"target": "ES2020",
133+
"lib": ["ES2020", "DOM"],
134+
"jsx": "react-jsx",
135+
"esModuleInterop": true,
136+
"allowSyntheticDefaultImports": true,
137+
"moduleResolution": "bundler"
138+
}
139+
}
140+
```
141+
142+
### Advanced (esModuleInterop: false)
143+
144+
```json
145+
{
146+
"compilerOptions": {
147+
"target": "ES2020",
148+
"lib": ["ES2020", "DOM"],
149+
"jsx": "react-jsx",
150+
"esModuleInterop": false,
151+
"moduleResolution": "bundler"
152+
}
153+
}
154+
```
155+
156+
**MUST use named imports everywhere!**
157+
158+
## Rollback
159+
160+
```bash
161+
162+
yarn add -D @types/react@18 @types/react-dom@18
163+
rm -rf public/packs
164+
bin/rails assets:precompile
165+
```
166+
167+
## Need Help?
168+
169+
- [Full React 19 Upgrade Guide](./react-19-upgrade-guide.md)
170+
- [React on Rails Issues](https://github.com/shakacode/react_on_rails/issues)
171+
- [ShakaCode Forum](https://forum.shakacode.com)
172+
- [Commercial Support](https://www.shakacode.com/contact)

0 commit comments

Comments
 (0)