Skip to content

RSCWebpackPlugin defaults to scanning project root and can bundle vendor gem templates #3201

@justin808

Description

@justin808

Problem

While fixing CI for the Hacker News RSC demo, the webpack build failed only on GitHub Actions because RSCWebpackPlugin defaults clientReferences to { directory: ".", recursive: true, include: /\.(js|ts|jsx|tsx)$/ }.

In CI, ruby/setup-ruby installs gems under vendor/bundle. That means the RSC plugin scans the vendored react_on_rails gem, sees "use client" example/template files under lib/generators/react_on_rails/templates/rsc/base/..., and adds them as client references for the app bundle. Webpack then tries to compile generator template files as application modules.

Evidence

Demo PR: shakacode/react-on-rails-demo-hacker-news-rsc#13

Failed CI run: https://github.com/shakacode/react-on-rails-demo-hacker-news-rsc/actions/runs/24822632175

Earlier failing logs showed imports from:

./vendor/bundle/ruby/3.4.0/gems/react_on_rails-16.4.0.rc.5/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.jsx
./vendor/bundle/ruby/3.4.0/gems/react_on_rails-16.4.0.rc.5/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.tsx

Import trace went through react-on-rails-pro/registerServerComponent/client and react-on-rails-rsc/dist/react-server-dom-webpack/client.browser.js, then into generated packs such as app/javascript/packs/generated/HNItemPage.js.

Local workaround

The demo fixes this by explicitly scoping client-reference discovery to Shakapacker application source:

const { config } = require("shakapacker");
const { resolve } = require("path");

const rscClientReferences = {
  directory: resolve(config.source_path),
  recursive: true,
  include: /\.(js|ts|jsx|tsx)$/,
};

new RSCWebpackPlugin({ isServer: false, clientReferences: rscClientReferences });
new RSCWebpackPlugin({ isServer: true, clientReferences: rscClientReferences });

A targeted guard check also passed locally: adding a temporary "use client" JSX file outside app/javascript no longer affects the app webpack build once the plugin is scoped.

Suggested product improvement

React on Rails / React on Rails Pro should avoid requiring every app to know about this footgun. Possible fixes:

  • Default generated RSC webpack config to clientReferences: { directory: resolve(config.source_path), recursive: true, include: /\.(js|ts|jsx|tsx)$/ } instead of relying on the plugin root default.
  • Document the required clientReferences scoping in the RSC setup guide.
  • Consider wrapping RSCWebpackPlugin with a React on Rails helper that uses Shakapacker source_path automatically.

Why it matters

This failure is CI-specific for many Rails apps because local development often uses globally installed gems, while GitHub Actions commonly installs bundled gems into vendor/bundle. That makes the default behavior hard to reproduce locally and confusing for demo users.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions