Skip to content

Commit de5af5c

Browse files
committed
Merge remote-tracking branch 'origin/main' into jg-conductor/lisbon-v2
Brings in #3408 (Pro Gemfile.lock sync, fixes benchmark CI), #3410 (tanstack-router StrictMode dedupe), and #3395 (changelog docs). Conflict in packages/react-on-rails-pro/src/tanstack-router/clientHydrate.ts resolved by taking origin/main's version: #3410 is a more recent reimplementation by the same author of the StrictMode-replay dedup done on this branch (commits 4eee58e, 1b6ef61, 9309155). The branch's per-route preloadRouteChunk cache is superseded by main's unified sharedHydrationInitStates per-router state.
2 parents 7ad0323 + d054765 commit de5af5c

38 files changed

Lines changed: 3019 additions & 213 deletions

.claude/commands/update-changelog.md

Lines changed: 46 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -356,19 +356,55 @@ When the user passes `rc` or `beta` as an argument:
356356

357357
### For Prerelease to Stable Version Release
358358

359-
When releasing from prerelease to a stable version (e.g., `v16.5.0.rc.1` -> `v16.5.0`):
359+
When releasing from prerelease to a stable version (e.g., `v16.5.0.rc.1` -> `v16.5.0`), this is where the accumulated prerelease sections get coalesced into one stable section. **Curate carefully** — users landing on the stable version don't care about intermediate prerelease state, and noise here makes the upgrade story harder to read.
360360

361-
1. **Remove all prerelease version labels** from the changelog:
362-
- Change `### [16.5.0.rc.0]`, `### [16.5.0.rc.1]`, etc. to a single `### [16.5.0]` section
363-
- Also handle beta versions: `### [16.5.0.beta.1]` etc.
364-
- Combine all prerelease entries into the stable release section
361+
#### Step 1: Coalesce all prerelease sections into one stable section
365362

366-
2. **Consolidate duplicate entries**:
367-
- If bug fixes or changes were made to features introduced in earlier prereleases, keep only the final state
368-
- Remove redundant changelog entries for fixes to prerelease features
369-
- Keep the most recent/accurate description of each change
363+
- Replace `### [16.5.0.rc.0]`, `### [16.5.0.rc.1]`, `### [16.5.0.beta.1]`, etc. (however many exist) with a single `### [16.5.0] - YYYY-MM-DD` section
364+
- **Move any remaining entries from `### [Unreleased]` into the new stable section** — anything still under `[Unreleased]` at stable-release time is shipping in this stable version. Leave `### [Unreleased]` with only its header (no entries).
365+
- Combine entries from all prerelease sections and the moved `[Unreleased]` entries, consolidating duplicate category headings (e.g., merge multiple `#### Fixed` sections into one under the preferred order from "Category Organization")
366+
- Remove the orphaned compare links at the bottom of the file for the coalesced prerelease versions
367+
- Add the `[16.5.0]` compare link pointing from the **previous stable tag** (e.g., `v16.4.0`) to `v16.5.0`**not** from the latest RC tag
368+
- Update the `[unreleased]:` compare link to point from `v16.5.0` to `main`
369+
- **Before committing**, spot-check the compare-link updates above: orphaned RC compare links removed, the new `[16.5.0]` link anchored at the previous stable tag (e.g., `v16.4.0...v16.5.0`) — not the latest RC tag — and `[unreleased]` pointing from `v16.5.0` to `main`. When `bundle exec rake "update_changelog[release]"` does the coalesce, this is handled automatically; still verify the result before pushing.
370370

371-
3. **Update version diff links** at the bottom to point to the stable version
371+
#### Step 2: Curate the entries — REMOVE these
372+
373+
1. **Prerelease-only fixes** — bugs introduced during the prerelease cycle and fixed in a later RC. If the bug never shipped in a stable release, the fix is noise to stable users.
374+
- Investigate when a bug was introduced: `git log --oneline v<last_stable>..v<rc_containing_the_fix>` — search this range for the commit that introduced the bug. If the range is large and you know which files are relevant, scope it with `-- path/to/file` to cut noise. If you **find it** in this range, the bug was introduced during the RC cycle and never shipped in stable — apply the merge-or-drop rules below. If you **don't find it**, the bug predates the RC cycle and existed in `<last_stable>` — keep the fix as its own entry.
375+
- Check the PR description for what was broken and when
376+
- For RC-only regression fixes where the fix **changed user-visible behavior** of the original feature (e.g., extended an option's accepted values, adjusted a default, broadened a path matcher), **merge** the fix into the original PR's entry: credit both PRs and rewrite the description so it reflects the final shipped state. Don't drop these — stable consumers see the merged behavior, not the intermediate regression.
377+
- **Pure-restore** fixes (the fix only restores prior behavior without changing the original entry's description) can be dropped.
378+
379+
2. **Refinements to prerelease-only features** — if a new feature was introduced in `rc.0` and then iterated in `rc.1`/`rc.2`, keep only the final description and drop the iteration history
380+
381+
3. **Internal/contributor-only tooling** — yalc publish fixes, git dependency support, CI/build script changes, generator handling of prerelease version formats, local-dev tooling fixes. These don't belong in a user-facing changelog.
382+
383+
#### Step 3: Curate the entries — KEEP these
384+
385+
1. **User-facing fixes for bugs that existed in the previous stable** — if `rc.2` fixes a bug that was in `16.4.0`, that fix matters to stable users upgrading
386+
387+
2. **Compatibility fixes** — Ruby/Rails version support, dependency relaxations, etc.
388+
389+
3. **All breaking changes** — API/CLI changes, removed methods, configuration changes, generator output changes. Even if a breaking change was introduced and refined across multiple prereleases, the final breaking change description belongs in stable.
390+
391+
4. **Performance/security improvements affecting all users**
392+
393+
**Pro tagging:** Pro-specific changes stay in the changelog tagged inline with `**[Pro]**` — do NOT drop them just because they're Pro-only. Apply the same REMOVE/KEEP rules above based on whether they're prerelease-only iteration vs user-facing changes that ship to Pro users.
394+
395+
#### Step 4: Investigation process for each entry
396+
397+
For each entry that doesn't obviously fall into a REMOVE or KEEP category above, ask:
398+
399+
- Was this bug present in the last stable release? If no, drop.
400+
- Was this feature introduced in an earlier prerelease and then iterated/refined across later RCs? If yes, keep only the final description and drop the intermediate history.
401+
- Does this matter to someone upgrading from the last stable to this stable? If no, drop.
402+
403+
#### Step 5: Final read-through
404+
405+
Read the resulting stable section as if you're a user upgrading from the previous stable. Every entry should be something you'd want to know about. If an entry only makes sense to someone who tracked the RC cycle, drop it.
406+
407+
**Example reference:** See [PR 2072](https://github.com/shakacode/react_on_rails/pull/2072) for a complete example of prerelease changelog curation with detailed investigation notes.
372408

373409
## Examples
374410

@@ -418,51 +454,6 @@ To migrate to React on Rails Pro:
418454
import ReactOnRails from 'react-on-rails-pro';
419455
```
420456

421-
## Prerelease Changelog Curation
422-
423-
When consolidating prerelease versions (beta, RC) into a stable release, carefully curate entries to include only user-facing changes:
424-
425-
**Remove these types of entries:**
426-
427-
1. **Developer-only tooling**:
428-
- yalc publish fixes (local development tool)
429-
- Git dependency support (contributor workflow)
430-
- CI/build script improvements
431-
- Internal tooling changes
432-
433-
2. **Prerelease-specific fixes**:
434-
- Bugs introduced during the prerelease cycle (not present in last stable)
435-
- Fixes for new prerelease-only features
436-
- Generator handling of prerelease version formats
437-
438-
3. **Pro-specific features** (tag with `**[Pro]**` inline):
439-
- Node renderer fixes/improvements
440-
- Streaming-related changes
441-
- Async loading features (Pro-exclusive)
442-
443-
**Keep these types of entries:**
444-
445-
1. **User-facing fixes**:
446-
- Bugs that existed in previous stable release (e.g., 16.1.x)
447-
- Compatibility fixes (Rails version support, etc.)
448-
- Performance improvements affecting all users
449-
450-
2. **Breaking changes**:
451-
- API changes requiring migration
452-
- Removed methods/features
453-
- Configuration changes
454-
455-
**Investigation process:**
456-
457-
For each suspicious entry:
458-
459-
1. Check git history: `git log --oneline <last_stable>..<current_prerelease> -- <file>`
460-
2. Determine when bug was introduced (stable vs prerelease cycle)
461-
3. Verify whether fix applies to stable users or only prerelease users
462-
4. Check PR description for context about what was broken
463-
464-
**Example reference:** See [PR 2072](https://github.com/shakacode/react_on_rails/pull/2072) for a complete example of prerelease changelog curation with detailed investigation notes.
465-
466457
## Additional Notes
467458

468459
- Keep descriptions concise but informative

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ After a release, run `/update-changelog` in Claude Code to analyze commits, writ
3535

3636
#### Fixed
3737

38+
- **[Pro]** Streaming server-render responses now raise `ReactOnRailsPro::Error` when the stream response status is unavailable or the renderer delivers a readable HTTP error status as a streaming body, instead of silently returning no chunks. This is a user-visible behavior change for callers that do not already rescue `ReactOnRailsPro::Error` from `each_chunk`. [PR 3383](https://github.com/shakacode/react_on_rails/pull/3383).
39+
- **[Pro]** **TanStack Router hydration no longer double-calls `loadRouteChunk` under React 18 StrictMode**: React 18's StrictMode double-renders components with fresh hook state on each pass, so the `routerRef.current === null` guard in `clientHydrate.ts` fired twice when `options.createRouter` returned the same router instance, re-running `loadRouteChunk`, `__store.setState`, and the user-defined `hydrate` callback. The render-phase init is now memoized via a module-level `WeakMap` keyed on the router instance, dedup'ing per-router side effects across mount cycles. Production behavior is unchanged because each mount creates a fresh router. Fixes [Issue 3405](https://github.com/shakacode/react_on_rails/issues/3405). [PR 3410](https://github.com/shakacode/react_on_rails/pull/3410) by [justin808](https://github.com/justin808).
3840
- **[Pro]** **Benchmark CI starts the production dummy app on the expected port**: `react_on_rails_pro/spec/dummy/bin/prod` now sets `PORT=3001` by default before launching Foreman, preventing Foreman's default `PORT=5000` from making the Rails server miss the benchmark workflow readiness check on `localhost:3001`. Both `react_on_rails/spec/dummy/bin/prod` and `react_on_rails_pro/spec/dummy/bin/prod` respect `PORT` when it's set. [PR 3403](https://github.com/shakacode/react_on_rails/pull/3403) by [alexeyr-ci2](https://github.com/alexeyr-ci2).
3941

4042
### [16.7.0.rc.2] - 2026-05-24

docs/pro/streaming-ssr.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ end
122122

123123
You can test your application by running `rails server` and navigating to the appropriate route.
124124

125+
### Error Handling Note for React on Rails Pro 16.7
126+
127+
React on Rails Pro 16.7 reports streaming renderer failures as `ReactOnRailsPro::Error` during chunk iteration.
128+
That includes unreadable response statuses and readable HTTP error statuses delivered as streaming bodies. If
129+
your code directly iterates a stream from `render_code_as_stream`, wrap `each_chunk` in normal error handling and
130+
treat that exception as a renderer failure. Older releases could return no chunks for these responses, so custom
131+
callers should not use an empty stream as a success signal.
132+
125133
### 6. What Happens During Streaming
126134

127135
When a user visits the page, they'll experience the following sequence:

0 commit comments

Comments
 (0)