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.
Problem
While fixing CI for the Hacker News RSC demo, the webpack build failed only on GitHub Actions because
RSCWebpackPlugindefaultsclientReferencesto{ directory: ".", recursive: true, include: /\.(js|ts|jsx|tsx)$/ }.In CI,
ruby/setup-rubyinstalls gems undervendor/bundle. That means the RSC plugin scans the vendoredreact_on_railsgem, sees"use client"example/template files underlib/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:
Import trace went through
react-on-rails-pro/registerServerComponent/clientandreact-on-rails-rsc/dist/react-server-dom-webpack/client.browser.js, then into generated packs such asapp/javascript/packs/generated/HNItemPage.js.Local workaround
The demo fixes this by explicitly scoping client-reference discovery to Shakapacker application source:
A targeted guard check also passed locally: adding a temporary
"use client"JSX file outsideapp/javascriptno 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:
clientReferences: { directory: resolve(config.source_path), recursive: true, include: /\.(js|ts|jsx|tsx)$/ }instead of relying on the plugin root default.clientReferencesscoping in the RSC setup guide.RSCWebpackPluginwith a React on Rails helper that uses Shakapackersource_pathautomatically.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.