|
2 | 2 |
|
3 | 3 | A React on Rails demo application showcasing **TanStack Router** integration with **Rspack** and **server-side rendering (SSR)**. |
4 | 4 |
|
| 5 | +> **⚠️ React on Rails Pro Required**: This demo requires [React on Rails Pro](https://www.shakacode.com/react-on-rails-pro/) with its **Node server renderer**. TanStack Router uses Node.js APIs (`setTimeout`, `clearTimeout`, etc.) that are not available in the default ExecJS environment. The Node renderer provides a proper Node.js runtime for SSR. |
| 6 | +
|
5 | 7 | ## Gem Versions |
6 | 8 |
|
7 | 9 | This demo uses: |
@@ -105,14 +107,39 @@ The following directories contain generated files and are **gitignored**: |
105 | 107 |
|
106 | 108 | ### SSR Configuration |
107 | 109 |
|
108 | | -The SSR bundle output path is configured in `config/shakapacker.yml`: |
| 110 | +This demo requires **React on Rails Pro's Node server renderer** because TanStack Router uses Node.js APIs (`setTimeout`, `clearTimeout`, etc.) internally for route loading. These APIs are not available in the default ExecJS environment used by the open-source React on Rails gem. |
109 | 111 |
|
110 | | -```yaml |
111 | | -default: |
112 | | - private_output_path: ssr-generated |
113 | | -``` |
| 112 | +#### Why Node Renderer? |
| 113 | + |
| 114 | +The default ExecJS-based SSR in React on Rails runs JavaScript in a limited environment (typically via MiniRacer or ExecJS) that lacks: |
| 115 | + |
| 116 | +- Timer functions (`setTimeout`, `clearTimeout`, `setInterval`, `clearInterval`) |
| 117 | +- Full `console` API |
| 118 | +- Other Node.js built-in modules |
| 119 | + |
| 120 | +TanStack Router's internal implementation relies on these APIs, making the Node renderer essential. |
| 121 | + |
| 122 | +#### Configuration |
114 | 123 |
|
115 | | -The server bundle configuration in `config/webpack/serverWebpackConfig.js` automatically uses this path. |
| 124 | +1. **Configure React on Rails Pro** in `config/initializers/react_on_rails.rb`: |
| 125 | + |
| 126 | + ```ruby |
| 127 | + ReactOnRails.configure do |config| |
| 128 | + config.server_render_method = "NodeJS" |
| 129 | + # ... other configuration |
| 130 | + end |
| 131 | + ``` |
| 132 | + |
| 133 | +2. **Webpack/Rspack target**: The server bundle is configured with `target: 'node'` in `config/webpack/serverWebpackConfig.js` |
| 134 | + |
| 135 | +3. **Output path**: Configured in `config/shakapacker.yml`: |
| 136 | + |
| 137 | + ```yaml |
| 138 | + default: |
| 139 | + private_output_path: ssr-generated |
| 140 | + ``` |
| 141 | +
|
| 142 | +For more information on React on Rails Pro and the Node renderer, see the [React on Rails Pro documentation](https://www.shakacode.com/react-on-rails-pro/). |
116 | 143 |
|
117 | 144 | ## Scripts |
118 | 145 |
|
@@ -144,16 +171,44 @@ npm run test:headed |
144 | 171 | SKIP_WEB_SERVER=true npm test |
145 | 172 | ``` |
146 | 173 |
|
147 | | -## SSR Limitations |
| 174 | +## Limitations |
| 175 | + |
| 176 | +### Route Synchronization |
148 | 177 |
|
149 | | -This demo uses synchronous SSR compatible with React on Rails. **Async route loaders are not supported** in this configuration. The `router.load()` call happens synchronously. |
| 178 | +Each TanStack Router route that requires SSR must have a corresponding Rails route defined in `config/routes.rb`. This ensures the Rails server can handle direct URL requests and render the correct initial HTML. |
| 179 | + |
| 180 | +```ruby |
| 181 | +# config/routes.rb |
| 182 | +get "about", to: "tanstack_app#index" |
| 183 | +get "users/:userId", to: "tanstack_app#index" |
| 184 | +# ... add routes for each TanStack route |
| 185 | +``` |
| 186 | + |
| 187 | +For production apps with many routes, consider a catch-all route (with API route exclusions): |
| 188 | + |
| 189 | +```ruby |
| 190 | +get '*path', to: 'tanstack_app#index', constraints: ->(req) { !req.path.start_with?('/api') } |
| 191 | +``` |
| 192 | + |
| 193 | +### React on Rails Pro Required |
| 194 | + |
| 195 | +This demo **requires React on Rails Pro** with the Node server renderer. The open-source ExecJS-based renderer cannot run TanStack Router due to missing Node.js APIs. |
| 196 | + |
| 197 | +### Synchronous SSR Only |
| 198 | + |
| 199 | +This demo uses synchronous SSR. **Async route loaders are not supported** in this configuration. The `router.load()` call happens synchronously. |
150 | 200 |
|
151 | 201 | For async data fetching, consider: |
152 | 202 |
|
153 | 203 | 1. Passing data as props from the Rails controller |
154 | | -2. Using React on Rails' `renderFunction` pattern for async support |
| 204 | +2. Using React on Rails Pro's streaming SSR for async support |
155 | 205 | 3. Using client-side data fetching with loading states |
156 | 206 |
|
| 207 | +### Development-Only Features |
| 208 | + |
| 209 | +- **TanStack Router DevTools** are only available in development mode |
| 210 | +- **React Fast Refresh** (HMR) is only active when running `bin/dev` |
| 211 | + |
157 | 212 | ## Deployment |
158 | 213 |
|
159 | 214 | For deployment, ensure you run the asset precompilation step: |
|
0 commit comments