Skip to content

Docs: Clarify .client/.server suffixes vs 'use client' RSC directive#2406

Open
AbanoubGhadban wants to merge 10 commits intomasterfrom
2405-clarify-client-server-suffix-vs-rsc
Open

Docs: Clarify .client/.server suffixes vs 'use client' RSC directive#2406
AbanoubGhadban wants to merge 10 commits intomasterfrom
2405-clarify-client-server-suffix-vs-rsc

Conversation

@AbanoubGhadban
Copy link
Collaborator

@AbanoubGhadban AbanoubGhadban commented Feb 13, 2026

Clarify across docs and code that .client./.server. file suffixes (bundle placement) and 'use client' directive (RSC classification) are independent concepts. The main goal is avoiding LLM misconception about auto-bundling postfixes and React Server Components — LLMs consistently confuse .server.jsx files with React Server Components.

Closes #2405

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Clarified distinction between file-suffix-based bundling and React Server Components (RSC): suffixes control bundle placement while RSC status is set by the "use client" directive.
    • Added an explanatory section on the orthogonality of the two systems, guidance for paired client/server files and hydration, examples mapping file types to behavior, and glossary/core-concepts updates.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Documentation updates across multiple files clarify that file suffix-based bundling (.client. / .server.) is distinct from React Server Components (RSC) classification via the 'use client' directive; the changes explain their orthogonality, interactions, and bundle/registration implications.

Changes

Cohort / File(s) Summary
Core Concepts & Getting Started
docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md, docs/getting-started/project-structure.md
Added notes clarifying .client./.server. suffixes control webpack bundle placement, are unrelated to RSC classification, and guidance to remove generalized files when using paired client/server files.
Agent & Architecture Docs
.claude/docs/project-architecture.md, AGENTS.md
Inserted a new section explaining two independent systems: bundle placement via suffixes and RSC classification via 'use client'; documented interaction rules, compatibility notes, and mapping of registration/bundle behavior. (AGENTS.md shows duplicate insertion in diff.)
Code Comment / Generator
react_on_rails/lib/react_on_rails/packs_generator.rb
Added a top-of-file comment block describing the orthogonal concepts, listing related methods/code paths, and clarifying naming/registration distinctions. No functional changes.
Pro RSC Docs
react_on_rails_pro/docs/react-server-components/glossary.md
Added a note that .client./.server. suffixes affect bundling only and do not determine RSC status; included examples and cross-references.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hopped through docs with a bright little nudge,
Suffixes choose bundles, directives choose judge.
.client. and .server. find webpack their way,
'use client' tells RSC how to play.
I twitched my whiskers — clarity saved the day!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: clarifying the distinction between .client/.server suffixes and the 'use client' RSC directive across documentation.
Linked Issues check ✅ Passed All coding requirements from #2405 are met: documentation clarification in four key files, code comments in packs_generator.rb, and distinction between bundle placement, RSC classification, and rendering location is explicitly established.
Out of Scope Changes check ✅ Passed All changes are directly aligned with #2405 objectives—clarifying the distinction between suffixes and RSC directives through documentation and code comments without functional changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 2405-clarify-client-server-suffix-vs-rsc

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AbanoubGhadban AbanoubGhadban requested review from alexeyr-ci2, ihabadham and justin808 and removed request for justin808 February 13, 2026 11:32
@greptile-apps
Copy link

greptile-apps bot commented Feb 13, 2026

Greptile Overview

Greptile Summary

Clarifies the distinction between .client./.server. file suffixes (bundle placement) and the 'use client' RSC directive (React Server Component classification) across documentation and code comments to prevent LLM and developer confusion.

Major changes:

  • Added comprehensive sections to .claude/docs/project-architecture.md and AGENTS.md explaining these are two independent, orthogonal systems
  • Enhanced docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md with prominent warning box and RSC glossary cross-reference
  • Added class-level documentation to packs_generator.rb clearly separating the two classification systems
  • Updated RSC glossary to clarify file suffixes are unrelated to RSC component types

Issues found:

  • Minor inconsistency: .claude/docs/project-architecture.md and AGENTS.md state .server.jsx goes to "server bundle only", but the more accurate description (from glossary) is "server bundle and RSC bundle" when RSC is enabled. This may confuse users about RSC behavior.

Confidence Score: 4/5

  • Safe to merge with minor documentation inconsistency that should be addressed
  • Documentation-only PR that successfully addresses the stated goal of clarifying two independent concepts. Found one technical inconsistency about where .server.jsx files are bundled (stated as "server bundle only" in two files vs "server and RSC bundle" in the glossary). The glossary is more accurate for RSC-enabled scenarios. Otherwise, changes are well-structured, comprehensive, and correctly explain the orthogonal nature of the two systems.
  • .claude/docs/project-architecture.md and AGENTS.md need minor correction to align with glossary regarding .server.jsx bundle destinations

Important Files Changed

Filename Overview
.claude/docs/project-architecture.md Added comprehensive section explaining the distinction between bundle placement suffixes and RSC directives with examples and code references
AGENTS.md Added "Key Concept" section clarifying the orthogonal nature of file suffixes vs RSC classification to prevent agent confusion
docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md Added important note box with cross-reference to RSC glossary, clearly distinguishing auto-bundling suffixes from RSC concepts
docs/getting-started/project-structure.md Added inline clarification with link to RSC glossary explaining that file suffixes control bundle placement, not RSC classification
react_on_rails/lib/react_on_rails/packs_generator.rb Added detailed class-level comment documenting the two independent classification systems with examples
react_on_rails_pro/docs/react-server-components/glossary.md Added prominent section at the top clarifying that file suffixes are unrelated to RSC classification with cross-reference to auto-bundling docs

Last reviewed commit: c138ab3

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

A React on Rails auto-bundling feature that controls which **webpack bundle** imports a file. This exists independently of React Server Components and is used with or without RSC:

- `Component.client.jsx` → client bundle only (browser)
- `Component.server.jsx` → server bundle only (Node.js SSR). Must have a paired `.client.` file.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent with glossary: the glossary correctly states .server.jsx goes into "server and the RSC bundle" (line 17 of react_on_rails_pro/docs/react-server-components/glossary.md), but here it says "server bundle only". When RSC is enabled, .server.jsx files are included in both bundles.

Suggested change
- `Component.server.jsx` → server bundle only (Node.js SSR). Must have a paired `.client.` file.
- `Component.server.jsx` → server bundle (and RSC bundle when RSC enabled). Must have a paired `.client.` file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — updated to "server bundle (and RSC bundle when RSC enabled)" to match the glossary. Also updated the table rows for consistency.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed. .server.jsx now correctly says "server bundle (and RSC bundle when RSC enabled)" in both the bullet point and the table.

AGENTS.md Outdated
A React on Rails auto-bundling feature that controls which webpack bundle imports a file. This exists independently of React Server Components and is used with or without RSC:

- `Component.client.jsx` → imported only in the **client bundle** (browser)
- `Component.server.jsx` → imported only in the **server bundle** (Node.js SSR)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same inconsistency: should clarify that .server.jsx files go into server bundle AND RSC bundle (when RSC is enabled), not just "server bundle"

Suggested change
- `Component.server.jsx` → imported only in the **server bundle** (Node.js SSR)
- `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — same correction applied here.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.claude/docs/project-architecture.md:
- Around line 108-114: The documentation block contains fragile, stale
line-number references that will drift; remove all the approximate line
references and leave only the stable method identifiers (e.g.,
common_component_to_path, client_component_to_path, server_component_to_path,
client_entrypoint?, pack_file_contents) and brief descriptions so readers can
grep by name instead of relying on line numbers.
🧹 Nitpick comments (1)
react_on_rails_pro/docs/react-server-components/glossary.md (1)

12-12: Heading level is higher than preceding glossary entry.

The first entry "RSC (React Server Component)" at line 3 uses ### (H3), but this new section uses ## (H2). This is intentional for visual prominence as a callout, but it breaks the glossary's heading hierarchy — a reader might expect entries to be at consistent levels under the H1 title.

the exception silently stops working. CI guards (`script/check-react-major-version.mjs`)
will catch version mismatches.

## File Suffixes vs. RSC Directive (Important Distinction)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## File Suffixes vs. RSC Directive (Important Distinction)
## `.client` and `.server` File Suffixes vs. RSC Directive (Important Distinction)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, thanks!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, thanks!

- **Registration**: Components with `'use client'` are registered via `ReactOnRails.register()`. Components without it are registered via `registerServerComponent()`.
- **RSC bundling**: The RSC webpack loader uses this directive to decide whether a component is included in the RSC bundle or replaced with a client reference in that bundle.

Checked by `client_entrypoint?` in `packs_generator.rb`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'''s a cross-reference to the implementation — helps agents (and developers) know which method in packs_generator.rb handles the '\''use client'\'' detection. Reworded it to read more clearly as a full sentence instead of a terse note.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a cross-reference to the implementation — helps agents (and developers) know which method in packs_generator.rb handles the 'use client' detection. Reworded it to read more clearly as a full sentence.


### How They Interact

These are orthogonal. The suffix controls which bundle, the directive controls RSC registration:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
These are orthogonal. The suffix controls which bundle, the directive controls RSC registration:
These are orthogonal concerns. The file suffix controls which bundle, and the directive controls RSC registration:

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, thanks!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, thanks!

- Each component gets its own webpack bundle for optimal code splitting
- No manual `ReactOnRails.register()` calls needed
- Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic
- Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic (these control **bundle placement**, not [React Server Components](../../react_on_rails_pro/docs/react-server-components/glossary.md))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic (these control **bundle placement**, not [React Server Components](../../react_on_rails_pro/docs/react-server-components/glossary.md))
- Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic (these control **client versus server bundle placement**, not [React Server Components](../../react_on_rails_pro/docs/react-server-components/glossary.md))

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, thanks!

@justin808
Copy link
Member

Heads-up for merge sequencing with the docs cleanup work:

I opened #2414 to move internal-only docs out of published trees:

  • docs/contributor-info/ -> internal/contributor-info/
  • docs/planning/ -> internal/planning/
  • react_on_rails_pro/docs/contributors-info/ -> internal/react_on_rails_pro/contributors-info/

Since #2406 already edits AGENTS.md, it would be ideal to include (or follow with) the path guidance update there as well:

  • replace docs/contributor-info/ references with internal/contributor-info/
  • remove contributor-info from the allowed user-docs subdirectory list

That keeps agent guidance consistent immediately after the docs move.

@AbanoubGhadban
Copy link
Collaborator Author

Thanks for the heads-up on #2414. Happy to rebase after it merges and update the AGENTS.md path references (docs/contributor-info/internal/contributor-info/ etc.), or include the path changes here if this PR waits. Let me know your preferred merge order.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.claude/docs/project-architecture.md (1)

97-105: Consider scoping the "Registered as" column to RSC-enabled mode

The table is conceptually correct, but the "Registered as" column only reflects RSC-enabled behavior (i.e., registerServerComponent() is called instead of ReactOnRails.register() for components without 'use client'). In non-RSC configurations the 'use client' directive has no effect on registration — all components go through ReactOnRails.register(). A reader who skims the table without reading the preceding RSC-Classification prose (lines 86–90) could wrongly conclude, for example, that Foo.client.jsx without 'use client' is always registered as a "Server component".

Adding a brief scope note to the table makes this self-contained:

✏️ Proposed clarification
-### How They Interact
+### How They Interact (RSC-enabled mode)
 
 These are orthogonal concerns. The file suffix controls which bundle, and the directive controls RSC registration:
 
+> **Note**: The "Registered as" column applies only when RSC support is enabled (Pro feature).
+> Without RSC, all components are registered via `ReactOnRails.register()` regardless of the `'use client'` directive.
+
 | File | `'use client'`? | Goes into | Registered as |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/docs/project-architecture.md around lines 97 - 105, Add a short
scope note above or below the table clarifying that the "Registered as" column
reflects RSC-enabled mode only: in RSC-enabled builds components without the
'use client' directive are registered via registerServerComponent(), whereas in
non-RSC configurations all files (e.g., Foo.jsx, Foo.client.jsx, Foo.server.jsx)
are registered with ReactOnRails.register() and the 'use client' directive does
not affect registration; update the table caption or add a one-line footnote to
that effect so readers don’t misinterpret the entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/docs/project-architecture.md:
- Line 112: Edit the documentation text for the symbol
`server_component_to_path` to fix the grammar: change the phrase "requires
paired `.client.`" to "requires a paired `.client.`" so the line reads
"`server_component_to_path` — finds `.server.` files (requires a paired
`.client.`)"; no code changes required, just update the doc string/text entry
where `server_component_to_path` is documented.

---

Nitpick comments:
In @.claude/docs/project-architecture.md:
- Around line 97-105: Add a short scope note above or below the table clarifying
that the "Registered as" column reflects RSC-enabled mode only: in RSC-enabled
builds components without the 'use client' directive are registered via
registerServerComponent(), whereas in non-RSC configurations all files (e.g.,
Foo.jsx, Foo.client.jsx, Foo.server.jsx) are registered with
ReactOnRails.register() and the 'use client' directive does not affect
registration; update the table caption or add a one-line footnote to that effect
so readers don’t misinterpret the entries.

@claude
Copy link

claude bot commented Feb 19, 2026

PR Review: Docs — Clarify .client/.server suffixes vs 'use client' RSC directive

Overall this is a well-structured, clearly motivated documentation PR. The intent (preventing LLM and developer confusion about two independent systems) is sound, and the core explanations are accurate. A few issues worth addressing before merge:

Issues

1. packs_generator.rb comment contradicts the rest of the docs
The inline Ruby comment says Component.server.jsx → server bundle only, but every other file in this PR (including project-architecture.md and glossary.md) correctly says it goes into the server bundle and the RSC bundle when RSC is enabled. This inconsistency in the authoritative source file is confusing for developers reading the code.

2. Table "Registered as" column is RSC-mode-only
The interaction table in .claude/docs/project-architecture.md has a "Registered as" column that implies components are always registered as "Server component" or "Client component". This is only true when RSC support is enabled (Pro). Without RSC, all components go through ReactOnRails.register() regardless of 'use client'. A reader skimming the table without reading the preceding prose could draw the wrong conclusion. A brief scope note (e.g., renaming the heading to "How They Interact (RSC-enabled mode)" or adding a callout below the table) would prevent misinterpretation.

3. Heading hierarchy in glossary
The new ## Important section (H2) is inserted after the existing ### RSC entry (H3), creating an inverted heading hierarchy at the top of the file. The pre-existing ### RSC entry is an H3 with no parent H2, which compounds the issue. Either promote the section heading to H3 or move it before the first glossary entry.

4. Minor grammar
server_component_to_path — finds .server. files (requires paired .client.) → should be "requires a paired .client." (see .claude/docs/project-architecture.md line 112).

5. Cross-package relative links
docs/getting-started/project-structure.md and docs/core-concepts/auto-bundling-*.md both link to ../../react_on_rails_pro/docs/react-server-components/glossary.md. If the published docs site serves the docs/ tree without react_on_rails_pro/docs/ alongside it, these links will break. Worth verifying that the build/deploy pipeline resolves these correctly.

6. Merge sequencing note (from @justin808)
Since this PR already touches AGENTS.md, it is probably worth waiting for #2414 to merge first (or including the path changes here) so that docs/contributor-info/ references are updated to internal/contributor-info/ at the same time, keeping agent guidance consistent.

@claude
Copy link

claude bot commented Feb 19, 2026

PR Review: Docs — Clarify .client/.server suffixes vs 'use client' RSC directive

Overall this is a well-structured, clearly motivated documentation PR. The intent (preventing LLM and developer confusion about two independent systems) is sound, and the core explanations are accurate. A few issues worth addressing before merge:

Issues

1. AGENTS.md 'only in the server bundle' phrasing contradicts earlier sentence
Line 176 says .server.jsx is "just a file that webpack includes only in the server bundle", but line 173 of the same section already correctly qualifies that it also goes into the RSC bundle when RSC is enabled. The summary sentence should match.

2. Table "Registered as" column is RSC-mode-only
The interaction table in .claude/docs/project-architecture.md has a "Registered as" column implying components are always registered as "Server component" or "Client component". This is only true when RSC support is enabled (Pro). Without RSC, all components go through ReactOnRails.register() regardless of 'use client'. Scoping the heading (e.g., "How They Interact (RSC-enabled mode)") or adding a note below the table would prevent misreading.

3. Inverted heading hierarchy in the glossary
The new ## Important section (H2) is inserted after ### RSC (H3), creating an inverted H3 → H2 hierarchy. Either make the new section ### or restructure so H2 always precedes H3.

4. Cross-package relative links
docs/getting-started/project-structure.md and docs/core-concepts/auto-bundling-*.md both link to ../../react_on_rails_pro/docs/react-server-components/glossary.md. If the published docs site serves the docs/ tree without react_on_rails_pro/docs/ alongside it, these links will 404. Worth verifying that the build/deploy pipeline resolves these correctly.

5. Merge sequencing note (from @justin808)
Since this PR already touches AGENTS.md, it is probably worth waiting for #2414 to merge first (or including the path changes here) so that docs/contributor-info/ references are updated to internal/contributor-info/ at the same time, keeping agent guidance consistent.

@claude
Copy link

claude bot commented Feb 19, 2026

Review: Docs clarification for .client/.server suffixes vs 'use client' RSC directive

The intent is solid and the core explanation is accurate. A few issues worth addressing before merging:

Substantive: RSC-only context missing from the table/prose

The "Registered as" column in the table in .claude/docs/project-architecture.md (and the corresponding prose in AGENTS.md) implies this registration behaviour applies universally. It only applies in RSC-enabled mode (Pro feature). In a non-RSC project, every component goes through ReactOnRails.register() regardless of the 'use client' directive. A reader who skims the table without reading the RSC-Classification section could conclude that a Foo.client.jsx file without 'use client' is always "registered as a Server component" — which is wrong for the majority of non-Pro installs.

Suggested fix: rename "### How They Interact" → "### How They Interact (RSC-enabled mode)" and add a one-sentence note that without RSC all files use ReactOnRails.register().

Heading hierarchy break in glossary.md

The new "Important" section uses ## (H2), but the existing first entry "RSC (React Server Component)" uses ### (H3). This inverts the expected nesting — a callout uses a higher-level heading than the entries below it. The note could use ### with a bold prefix, or the existing glossary entries could be promoted to ##.

Content duplication

The same explanation appears nearly verbatim in both AGENTS.md and .claude/docs/project-architecture.md. Since CLAUDE.md directs readers to project-architecture.md for architecture details, keeping the AGENTS.md entry as a brief summary with a link to the architecture doc would reduce future drift risk.

Minor

  • project-architecture.md line 112: "requires paired .client." → "requires a paired .client." (missing article).

justin808 and others added 5 commits February 19, 2026 11:31
…s, apply maintainer suggestions

- Fix .server.jsx bundle destination to include RSC bundle when RSC enabled
- Remove fragile line-number references from code paths section
- Apply heading, wording, and cross-reference improvements from review

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…undle

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The explanatory sentence on line 176 said "only in the server bundle"
contradicting line 173 which correctly includes the RSC bundle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AbanoubGhadban AbanoubGhadban force-pushed the 2405-clarify-client-server-suffix-vs-rsc branch from 05415a9 to e2658e6 Compare February 19, 2026 09:31
# These are orthogonal. A .client.jsx file can be a React Server Component (if it lacks
# 'use client'), and a .server.jsx file can be a React Client Component (if it has 'use client').
#
class PacksGenerator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class-level documentation block is sandwiched between the # rubocop:disable directive and class PacksGenerator. In Ruby, YARD/RDoc convention is to place the documentation comment block immediately above the class keyword. The standard approach would be:

module ReactOnRails
  # This class handles two INDEPENDENT classification systems:
  # ...
  # rubocop:disable Metrics/ClassLength
  class PacksGenerator

Or, if the rubocop directive must come first (to suppress a lint warning that might fire on the comment itself), at minimum a blank line between the rubocop comment and the documentation would make it clearer the documentation block belongs to the class below it.

As written, a reader quickly scanning the file sees # rubocop:disable as the only thing "above" the class, and has to look further to find the actual class doc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The placement works fine here — the rubocop directive must come before the class definition to suppress the lint warning. The comment block is immediately above the class keyword and reads clearly.

@claude
Copy link

claude bot commented Feb 19, 2026

Review: Docs clarifying .client/.server suffixes vs. 'use client' directive

Overall: This is a well-targeted, technically accurate documentation PR. All claims were verified against the source code (packs_generator.rb):

  • server_component_to_path does require a paired .client. file (confirmed at line 482)
  • client_entrypoint? correctly detects the 'use client' directive
  • pack_file_contents branches on client_entrypoint? to call registerServerComponent() vs. ReactOnRails.register() (confirmed at lines 154–169)
  • The anchor #server-rendering-and-client-rendering-components in the glossary link resolves correctly (line 493 of the auto-bundling doc)

The core message — that .server.jsx is about bundle placement and has nothing to do with RSC classification — is accurate and genuinely useful for both human readers and LLMs.

Issues found

Style (minor): The class-level comment block in packs_generator.rb is placed after the # rubocop:disable directive and before class PacksGenerator, which is non-standard Ruby doc placement. See inline comment.

Heading hierarchy (minor): The new ## Important: section in glossary.md is at H2 while the existing ### RSC opening entry is at H3. This makes the hierarchy uneven. See inline comment.

Slight imprecision in user-facing doc: The [!IMPORTANT] callout in the auto-bundling doc says a .server.jsx file is "included only in the server bundle", omitting the RSC bundle case. The internal docs and Ruby comment are more precise. See inline comment.

Completeness note: When a .server.jsx file does have 'use client', the RSC webpack loader replaces it with a client reference stub in the RSC bundle — it doesn't include the full module. The table in project-architecture.md could note this distinction. See inline comment.

Maintenance consideration

The same concept is now documented in 6 different files (AGENTS.md, .claude/docs/project-architecture.md, 2 user docs, a Ruby comment, and the Pro glossary). This is intentional for discoverability, but it's worth noting: if the bundle-placement behavior ever changes (e.g., RSC enabling changes which suffixes go where), all six locations will need updating. A brief cross-reference comment like "See also: [auto-bundling doc]" from each location pointing to the canonical explanation would help future maintainers find all the places that need updating.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md`:
- Around line 497-501: The admonition block contains a blank quote line (the
standalone ">" at the end) which triggers markdownlint rule MD028; to fix either
remove the blank blockquote line by merging the admonition into a single
paragraph (update the text inside the block that begins with "[!IMPORTANT]" so
it has no empty ">" line) or disable the rule globally by adding
"no-blanks-blockquote": false to coderabbit.markdownlint-cli2.jsonc; update the
admonition in
docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md
(the [!IMPORTANT] block) or adjust the linter config accordingly.

In `@react_on_rails/lib/react_on_rails/packs_generator.rb`:
- Line 14: The comment string "Component.server.jsx → server bundle (and RSC
bundle when RSC enabled; requires paired .client. file)" is missing the article
"a"; update the comment in react_on_rails::packs_generator.rb (the line
containing that string) to read "...requires a paired .client. file" so the
grammar is correct (apply same change where similar text appears, e.g.,
.claude/docs/project-architecture.md).

…mmar in packs_generator

- auto-bundling doc: "only in the server bundle" → include RSC bundle qualifier
- packs_generator.rb: "requires paired" → "requires a paired"
- Collapse multi-paragraph blockquote into single paragraph

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md`:
- Around line 497-499: The blockquote admonition starting with "[!IMPORTANT]"
contains a trailing empty blockquote marker (a lone ">" line) that triggers
MD028; remove the stray blank blockquote marker so the admonition is a
contiguous block (ensure there is no standalone ">" on the following line after
the paragraph that ends with the RSC glossary link), leaving the multi-line
admonition intact without any blank blockquote lines.

@claude
Copy link

claude bot commented Feb 19, 2026

Review: HEAD commit e05ef9c

The documentation intent and core technical claims are accurate — this is a genuinely useful clarification of two orthogonal systems. Verified against source:

  • Method names in the packs_generator.rb comment all exist and match their descriptions
  • client_entrypoint? correctly detects the 'use client' directive
  • server_component_to_path does require a paired .client. file
  • The anchor in the cross-link to #server-rendering-and-client-rendering-components resolves correctly

Three items remain open at HEAD that have been flagged in prior review threads:

1. Table scope note (blocking — factual gap)
The "Registered as" column in the "How They Interact" table in .claude/docs/project-architecture.md implies that components are registered as "Server component" / "Client component" universally. This is only true in RSC-enabled (Pro) mode. Without RSC, all components go through ReactOnRails.register() regardless of the 'use client' directive. A developer running a non-Pro setup who reads only the table could draw the wrong conclusion. See inline comment.

2. Heading hierarchy in glossary.md (blocking — structure)
The new section uses ## (H2), which appears after the existing ### RSC entry (H3). This inverts the expected heading nesting. The fix is either changing the new section to ### or restructuring the preceding entry. See inline comment.

3. Blank-line between blockquotes in auto-bundling doc (style)
Lines 497–501 have two consecutive > blocks separated by a blank line. No .markdownlint.json exists in the repo so this won't fail CI, but CodeRabbit flagged it as MD028. Merging the two blocks (or separating with a non-blockquote line) would make the intent clearer and keep tools happy. See inline comment.


The `client_entrypoint?` method in `packs_generator.rb` is what detects this directive during auto-bundling.

### How They Interact
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Registered as" column only applies when RSC support is enabled (Pro feature). Without RSC, all components — regardless of file suffix or 'use client' directive — are registered via ReactOnRails.register(). A reader who skims this table without reading the preceding prose could conclude that Foo.client.jsx without 'use client' is "always registered as a Server component", which is wrong for non-Pro installs.

Suggested fix: rename the section heading and add a scope note:

Suggested change
### How They Interact
### How They Interact (RSC-enabled mode)
These are orthogonal concerns. The file suffix controls which bundle, and the directive controls RSC registration:
> **Note**: The "Registered as" column applies only when RSC support is enabled (Pro feature).
> Without RSC, all components are registered via `ReactOnRails.register()` regardless of the `'use client'` directive.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — renamed heading to "How They Interact (RSC-enabled mode)" and added a note that without RSC all components use ReactOnRails.register().

- Improved initial page load
- Better SEO

## Important: `.client.` / `.server.` File Suffixes Are Unrelated
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new ## Important: section (H2) is inserted after the existing ### RSC (React Server Component) entry (H3). This inverts the expected heading hierarchy — a callout uses a higher-level heading than the preceding glossary entries.

Two clean options:

  1. Change this heading to ### so it matches the other entries, e.g.:
    ### Note: `.client.` / `.server.` File Suffixes Are Unrelated to RSC
    
  2. Promote the existing ### RSC entry to ## so the glossary has consistent H2 top-level entries.

The content itself is correct and well-placed; it's purely a heading-level issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an HTML comment explaining the intentional H2 heading. The callout must visually stand out above the H3 glossary entries to prevent the exact confusion this PR addresses.

Comment on lines +497 to 500
> [!IMPORTANT]
> **Not related to React Server Components.** The `.client.` and `.server.` file suffixes control **which webpack bundle** imports the file (client bundle vs. server bundle for SSR) — a React on Rails auto-bundling concept that predates React Server Components. If you are using React Server Components (Pro feature), RSC classification is controlled separately by the `'use client'` directive; a `.server.jsx` file is NOT automatically a React Server Component. See the [RSC glossary](../../react_on_rails_pro/docs/react-server-components/glossary.md) for details.

> Example (dummy app): paired files such as [`ReduxApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx) and [`ReduxApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx), and [`RouterApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.client.jsx) and [`RouterApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.server.jsx).
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two consecutive blockquote blocks separated by a blank line (lines 497–498 = the [!IMPORTANT] block; line 500 = the > Example block). No markdownlint config is present in the repo so this won't fail CI, but it can trigger MD028 in external tools. Merging the blank line with a bare > continuation keeps both visually separate while avoiding the issue:

Suggested change
> [!IMPORTANT]
> **Not related to React Server Components.** The `.client.` and `.server.` file suffixes control **which webpack bundle** imports the file (client bundle vs. server bundle for SSR) — a React on Rails auto-bundling concept that predates React Server Components. If you are using React Server Components (Pro feature), RSC classification is controlled separately by the `'use client'` directive; a `.server.jsx` file is NOT automatically a React Server Component. See the [RSC glossary](../../react_on_rails_pro/docs/react-server-components/glossary.md) for details.
> Example (dummy app): paired files such as [`ReduxApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx) and [`ReduxApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx), and [`RouterApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.client.jsx) and [`RouterApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.server.jsx).
> [!IMPORTANT]
> **Not related to React Server Components.** The `.client.` and `.server.` file suffixes control **which webpack bundle** imports the file (client bundle vs. server bundle for SSR) — a React on Rails auto-bundling concept that predates React Server Components. If you are using React Server Components (Pro feature), RSC classification is controlled separately by the `'use client'` directive; a `.server.jsx` file is NOT automatically a React Server Component. See the [RSC glossary](../../react_on_rails_pro/docs/react-server-components/glossary.md) for details.
>
> Example (dummy app): paired files such as [`ReduxApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx) and [`ReduxApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx), and [`RouterApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.client.jsx) and [`RouterApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.server.jsx).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — added an HTML comment between the two blockquotes to avoid MD028.

…ading intent comment

- Add note that "Registered as" column applies only in RSC-enabled mode
- Separate consecutive blockquotes with HTML comment to avoid MD028
- Add comment explaining intentional H2 heading in glossary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Feb 19, 2026

Review: Docs — Clarify .client/.server suffixes vs 'use client' RSC directive

This is a well-targeted PR. The confusion between .server.jsx bundle-placement suffixes and React Server Components is genuinely common (especially with LLMs), and documenting the distinction across AGENTS.md, user-facing docs, the RSC glossary, and source code comments is a solid approach.

A few issues to address before merging:

1. Heading hierarchy break in glossary.md

The glossary currently has # React Server Components Glossary (H1) followed immediately by ### RSC (React Server Component) (H3) — which is a pre-existing skip. The new section adds ## Important: … (H2) after that H3, producing a document order of H1 → H3 → H2. That's a non-monotonic heading tree, which confuses navigation tools, screen readers, and markdownlint's MD001 rule. The comment justifies it for visual standout, but a [!WARNING] or [!IMPORTANT] callout block would achieve the same standout without breaking structure. Alternatively, promote the existing ### RSC entry to ## RSC to restore a valid hierarchy.

2. Missing .server.jsx pairing constraint

Three of the changed locations document .server.jsx behaviour but omit a critical enforcement rule: server_component_to_path raises raise_missing_client_component if a .server.jsx file exists without a matching .client.jsx file. The interaction table in .claude/docs/project-architecture.md and the bullet in AGENTS.md both show Foo.server.jsx / Component.server.jsx as standalone valid configurations, which they are not — they always require a paired .client.jsx. An agent or developer reading these without prior context will hit a confusing runtime error. See inline comments for specific locations.

Minor

  • The <!-- MD028: intentional separate blockquote --> comment between the [!IMPORTANT] and example blockquotes in the auto-bundling doc is correct lint-suppression technique; nothing to fix there.
  • The class-level comment block in packs_generator.rb being placed between the # rubocop:disable pragma and class PacksGenerator is unconventional (the pragma is no longer directly adjacent to the class keyword), but rubocop disable-to-end-of-file semantics make it functionally harmless.

- Better SEO

<!-- H2 is intentional here: this callout must stand out above the H3 glossary entries to prevent confusion -->
## Important: `.client.` / `.server.` File Suffixes Are Unrelated
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The heading level here creates a non-monotonic structure: the document goes # React Server Components Glossary (H1) → ### RSC (React Server Component) (H3, skipping H2) → ## Important: … (H2, coming after an H3). MD001 will flag this, and navigation tools/screen readers will present a confusing outline.

Two options:

  1. Fix the existing hierarchy: change ### RSC (React Server Component) to ## RSC (React Server Component) — then this H2 fits naturally before the ## Types of Components section.
  2. Keep H3 entries as-is, use a callout instead: replace the ## heading with a [!IMPORTANT] or [!WARNING] callout block, which provides visual standout without affecting heading structure.
Suggested change
## Important: `.client.` / `.server.` File Suffixes Are Unrelated
> [!IMPORTANT]
> **`.client.` / `.server.` File Suffixes Are Unrelated to React Server Components**

A React on Rails auto-bundling feature that controls which webpack bundle imports a file. This exists independently of React Server Components and is used with or without RSC:

- `Component.client.jsx` → imported only in the **client bundle** (browser)
- `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing pairing constraint. server_component_to_path calls raise_missing_client_component for every .server.jsx that has no matching .client.jsx, so a standalone .server.jsx is a hard error at pack-generation time. An agent reading only this bullet will generate invalid scaffolding.

Suggested change
- `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled)
- `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled). **Must be paired with a `Component.client.jsx` file** — a `.server.jsx` without a matching `.client.jsx` raises an error during pack generation.

Comment on lines +105 to +106
| `Foo.server.jsx` | Yes | Server bundle (+ RSC bundle) | Client component |
| `Foo.server.jsx` | No | Server bundle (+ RSC bundle) | Server component |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table presents Foo.server.jsx rows as standalone valid configurations, but server_component_to_path enforces that every .server.jsx must have a paired .client.jsx — omitting the pair raises raise_missing_client_component at pack generation time. Foo.client.jsx has no such pairing requirement.

Consider adding a footnote or a ‡ marker on both Foo.server.jsx rows with a note like: "‡ Requires a paired Foo.client.jsx; a .server.jsx without a matching .client.jsx raises an error." This is important context for agents using this table when scaffolding components.

Pre-existing formatting issues unrelated to this PR's changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

size-limit report 📦

Path Size
react-on-rails/client bundled (gzip) 62.5 KB (0%)
react-on-rails/client bundled (gzip) (time) 62.5 KB (0%)
react-on-rails/client bundled (brotli) 53.71 KB (0%)
react-on-rails/client bundled (brotli) (time) 53.71 KB (0%)
react-on-rails-pro/client bundled (gzip) 63.5 KB (0%)
react-on-rails-pro/client bundled (gzip) (time) 63.5 KB (0%)
react-on-rails-pro/client bundled (brotli) 54.67 KB (0%)
react-on-rails-pro/client bundled (brotli) (time) 54.67 KB (0%)
registerServerComponent/client bundled (gzip) 127.11 KB (0%)
registerServerComponent/client bundled (gzip) (time) 127.11 KB (0%)
registerServerComponent/client bundled (brotli) 61.54 KB (0%)
registerServerComponent/client bundled (brotli) (time) 61.54 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 121.61 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) (time) 121.61 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 56.58 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) (time) 56.64 KB (+0.12% 🔺)

@claude
Copy link

claude bot commented Feb 19, 2026

PR Review: Docs - Clarify .client/.server suffixes vs 'use client' RSC directive

The documentation intent here is solid and addresses a real source of confusion. A few issues worth addressing:

Heading hierarchy regression in glossary.md

The new ## Important: section is inserted after the first ### RSC entry, creating an H1 → H3 → H2 heading sequence. Markdown heading levels should not decrease (going from H3 back to H2 is semantically reversed). This will likely trigger markdownlint MD001. The <!-- H2 is intentional here --> comment documents the intent but doesn't resolve the linting issue.

The pre-existing jump from H1 directly to H3 on the first entry is also non-standard. A cleaner fix would be to introduce an H2 wrapper for the glossary terms (e.g., ## Glossary or ## Component Types) so the document has consistent H1 → H2 → H3 nesting.

Test file formatting changes belong in a separate commit/PR

RSCRequestTracker.test.ts and streamBackpressure.e2e.test.tsx contain Prettier-formatting-only changes that are unrelated to the documentation clarification. While both changes appear to correctly match the printWidth: 110 Prettier config, mixing formatting churn into a docs PR makes the diff harder to review and could surface unexpected CI side-effects. These should be a separate commit or PR.

Content duplication maintenance risk

The same orthogonality explanation now appears in five places:

  • .claude/docs/project-architecture.md
  • AGENTS.md
  • docs/core-concepts/auto-bundling-...md
  • docs/getting-started/project-structure.md
  • react_on_rails_pro/docs/react-server-components/glossary.md

This is intentionally strategic (for LLM context injection), but if implementation details change (e.g., a .server.jsx file no longer requiring a paired .client. file), all five locations need to be updated in sync. Consider whether 2–3 canonical references plus lightweight cross-links would be easier to maintain.

Documentation accuracy

The core content is accurate:

  • The "paired .client. file required" assertion for .server.jsx files is confirmed by packs_generator.rb:482
  • The client_entrypoint? method description is correct
  • The relative paths in cross-reference links are all correct (verified)
  • The printWidth-110 Prettier config means the RSCRequestTracker.test.ts single-line form (105 chars) is within limits

collectStreamData(stream1),
collectStreamData(stream2),
]);
const [data1, data2] = await Promise.all([collectStreamData(stream1), collectStreamData(stream2)]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This formatting change (collapsing to one line) is not related to the docs clarification goal of this PR. While 105 chars is within the printWidth: 110 Prettier config and the format is valid, mixing formatting churn into a docs PR complicates review. Consider moving this to a separate formatting commit or PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docs: Clarify distinction between .client/.server file suffixes and 'use client' RSC directive

2 participants