|
| 1 | +# WARP.md |
| 2 | + |
| 3 | +This file provides guidance to WARP (warp.dev) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +React on Rails is a Ruby gem and NPM package that seamlessly integrates React components into Rails applications with server-side rendering, hot module replacement, and automatic bundle optimization. This is a **dual-package project** maintaining both a Ruby gem (for Rails integration) and an NPM package (for React client-side functionality). |
| 8 | + |
| 9 | +## Essential Development Commands |
| 10 | + |
| 11 | +### Setup |
| 12 | +```bash |
| 13 | +# Initial setup for gem development |
| 14 | +bundle && yarn |
| 15 | + |
| 16 | +# Full setup including examples |
| 17 | +bundle && yarn && rake shakapacker_examples:gen_all && rake node_package && rake |
| 18 | + |
| 19 | +# Install git hooks (automatic on setup) |
| 20 | +bundle exec lefthook install |
| 21 | +``` |
| 22 | + |
| 23 | +### Testing |
| 24 | +```bash |
| 25 | +# All tests (excluding examples) - recommended for local development |
| 26 | +rake all_but_examples |
| 27 | + |
| 28 | +# Run specific test suites |
| 29 | +bundle exec rspec # All Ruby tests from project root |
| 30 | +rake run_rspec:gem # Top-level gem tests only |
| 31 | +rake run_rspec:dummy # Dummy app tests with turbolinks |
| 32 | +rake run_rspec:dummy_no_turbolinks # Dummy app tests without turbolinks |
| 33 | +yarn run test # JavaScript tests (Jest) |
| 34 | + |
| 35 | +# Run single example test |
| 36 | +rake run_rspec:shakapacker_examples_basic |
| 37 | + |
| 38 | +# Test environment diagnosis |
| 39 | +rake react_on_rails:doctor |
| 40 | +VERBOSE=true rake react_on_rails:doctor # Detailed output |
| 41 | +``` |
| 42 | + |
| 43 | +### Linting & Formatting (CRITICAL BEFORE EVERY COMMIT) |
| 44 | +```bash |
| 45 | +# Auto-fix all violations (RECOMMENDED workflow) |
| 46 | +rake autofix # Runs eslint --fix, prettier --write, and rubocop -A |
| 47 | + |
| 48 | +# Manual linting |
| 49 | +bundle exec rubocop # Ruby - MUST pass before commit |
| 50 | +rake lint # All linters (ESLint + RuboCop) |
| 51 | +yarn run lint # ESLint only |
| 52 | +rake lint:rubocop # RuboCop only |
| 53 | + |
| 54 | +# Check formatting without fixing |
| 55 | +yarn start format.listDifferent |
| 56 | +``` |
| 57 | + |
| 58 | +### Building |
| 59 | +```bash |
| 60 | +# Build NPM package (TypeScript → JavaScript) |
| 61 | +yarn run build # One-time build |
| 62 | +yarn run build-watch # Watch mode for development |
| 63 | + |
| 64 | +# Type checking |
| 65 | +yarn run type-check |
| 66 | +``` |
| 67 | + |
| 68 | +### Development Server (Dummy App) |
| 69 | +```bash |
| 70 | +cd spec/dummy |
| 71 | + |
| 72 | +# Start development with HMR |
| 73 | +foreman start # Uses Procfile.dev (default) |
| 74 | +bin/dev # Alternative |
| 75 | + |
| 76 | +# Other modes |
| 77 | +bin/dev static # Static assets |
| 78 | +bin/dev prod # Production-like environment |
| 79 | +``` |
| 80 | + |
| 81 | +### Local Testing with Yalc |
| 82 | +```bash |
| 83 | +# In react_on_rails directory |
| 84 | +yarn run build |
| 85 | +yalc publish |
| 86 | + |
| 87 | +# In test app directory |
| 88 | +yalc add react-on-rails |
| 89 | + |
| 90 | +# After making changes (CRITICAL STEP) |
| 91 | +cd /path/to/react_on_rails |
| 92 | +yalc push # Push updates to all linked apps |
| 93 | + |
| 94 | +cd /path/to/test_app |
| 95 | +yarn # Update dependencies |
| 96 | +``` |
| 97 | + |
| 98 | +## Critical Pre-Commit Requirements |
| 99 | + |
| 100 | +**⚠️ MANDATORY BEFORE EVERY COMMIT:** |
| 101 | + |
| 102 | +1. **Run `bundle exec rubocop` and fix ALL violations** |
| 103 | +2. **Ensure all files end with a newline character** |
| 104 | +3. **Use `rake autofix` to auto-fix formatting issues** |
| 105 | +4. **NEVER manually format code** - let Prettier and RuboCop handle it |
| 106 | + |
| 107 | +**Note:** Git hooks (via Lefthook) run automatically and check all changed files (staged + unstaged + untracked). |
| 108 | + |
| 109 | +## Architecture Overview |
| 110 | + |
| 111 | +### Dual Package Structure |
| 112 | + |
| 113 | +This project maintains two distinct but integrated packages: |
| 114 | + |
| 115 | +#### Ruby Gem (`lib/`) |
| 116 | +- **Purpose:** Rails integration and server-side rendering |
| 117 | +- **Key Components:** |
| 118 | + - `helper.rb` - Rails view helpers (`react_component`, etc.) |
| 119 | + - `server_rendering_pool.rb` - Manages Node.js processes for SSR |
| 120 | + - `configuration.rb` - Global configuration management |
| 121 | + - `packs_generator.rb` - Auto-bundling and pack generation |
| 122 | + - `engine.rb` - Rails engine integration |
| 123 | + - Generators in `lib/generators/react_on_rails/` |
| 124 | + |
| 125 | +#### NPM Package (`node_package/src/`) |
| 126 | +- **Purpose:** Client-side React integration |
| 127 | +- **Key Components:** |
| 128 | + - `ReactOnRails.ts` - Main entry point for client-side functionality |
| 129 | + - `serverRenderReactComponent.ts` - Server-side rendering logic |
| 130 | + - `clientStartup.ts` - Client-side component mounting |
| 131 | + - `pro/` - React on Rails Pro features (React Server Components, etc.) |
| 132 | + |
| 133 | +### Data Flow |
| 134 | + |
| 135 | +1. Rails view calls `react_component` helper |
| 136 | +2. Helper generates HTML markup with props |
| 137 | +3. Server-side rendering (if enabled) runs component in Node.js |
| 138 | +4. Client-side JavaScript hydrates/renders component in browser |
| 139 | +5. Auto-bundling system dynamically generates packs based on file structure |
| 140 | + |
| 141 | +### Build System |
| 142 | + |
| 143 | +- **Ruby:** Standard gemspec-based build → published as `react_on_rails` gem |
| 144 | +- **JavaScript:** TypeScript compilation (`node_package/src/` → `node_package/lib/`) |
| 145 | +- **Testing:** RSpec for Ruby, Jest for JavaScript |
| 146 | +- **Linting:** ESLint (JS/TS), RuboCop (Ruby), Prettier (formatting) |
| 147 | + |
| 148 | +### Key Architectural Patterns |
| 149 | + |
| 150 | +#### Server-Side Rendering |
| 151 | +- Uses isolated Node.js processes via `connection_pool` |
| 152 | +- Separate server bundles can be configured for SSR-specific code |
| 153 | +- React Server Components (RSC) support in Pro version |
| 154 | + |
| 155 | +#### Auto-Bundling |
| 156 | +- File-system-based automatic bundle generation |
| 157 | +- Components in designated directories are auto-discovered |
| 158 | +- Eliminates manual `javascript_pack_tags` configuration |
| 159 | +- See `packs_generator.rb` for implementation |
| 160 | + |
| 161 | +#### Component Registration |
| 162 | +- Manual: `ReactOnRails.register({ ComponentName })` in pack files |
| 163 | +- Auto: Components auto-registered via `auto_load_bundle: true` option |
| 164 | + |
| 165 | +## Testing & Examples |
| 166 | + |
| 167 | +### Dummy App (`spec/dummy/`) |
| 168 | +- Full Rails app for integration testing |
| 169 | +- Examples of various React on Rails features |
| 170 | +- Uses Shakapacker for webpack configuration |
| 171 | +- Includes SSR, Redux, React Router examples |
| 172 | + |
| 173 | +### Generated Examples (`gen-examples/`) |
| 174 | +- Created via `rake shakapacker_examples:gen_all` |
| 175 | +- Ignored by git |
| 176 | +- Used for comprehensive generator testing |
| 177 | +- Should be excluded from IDE to prevent slowdown |
| 178 | + |
| 179 | +### Important Test Patterns |
| 180 | +- Use `yalc` for local package testing, not `npm link` |
| 181 | +- Always run `yalc push` after changes to see updates in test apps |
| 182 | +- Test both with/without Shakapacker pre-installed |
| 183 | +- Verify React components are interactive, not just rendering |
| 184 | + |
| 185 | +## Common Development Workflows |
| 186 | + |
| 187 | +### Making Code Changes |
| 188 | +1. Make changes to Ruby or TypeScript code |
| 189 | +2. For NPM changes: `yarn run build` or `yarn run build-watch` |
| 190 | +3. For Yalc testing: `yalc push` |
| 191 | +4. Run relevant tests |
| 192 | +5. **Run `rake autofix`** to fix all linting |
| 193 | +6. Commit changes |
| 194 | + |
| 195 | +### Fixing Bugs |
| 196 | +1. Create failing test that reproduces issue |
| 197 | +2. Implement minimal fix |
| 198 | +3. Ensure all tests pass |
| 199 | +4. Run linting: `bundle exec rubocop` and `yarn run lint` |
| 200 | +5. Update documentation if needed |
| 201 | + |
| 202 | +### Adding Features |
| 203 | +1. Plan implementation (use TODO list for complex tasks) |
| 204 | +2. Write tests first (TDD) |
| 205 | +3. Implement feature |
| 206 | +4. Test with dummy app or examples |
| 207 | +5. Run full test suite: `rake all_but_examples` |
| 208 | +6. Update relevant documentation |
| 209 | + |
| 210 | +### Testing Generator Changes |
| 211 | +```bash |
| 212 | +# Create test Rails app |
| 213 | +rails new test-app --skip-javascript |
| 214 | +cd test-app |
| 215 | +echo 'gem "react_on_rails", path: "../react_on_rails"' >> Gemfile |
| 216 | +bundle install |
| 217 | + |
| 218 | +# Run generator |
| 219 | +./bin/rails generate react_on_rails:install |
| 220 | + |
| 221 | +# Test with yalc for full functionality |
| 222 | +cd /path/to/react_on_rails |
| 223 | +yalc publish |
| 224 | +yalc push |
| 225 | + |
| 226 | +cd /path/to/test-app |
| 227 | +yarn install |
| 228 | +bin/dev |
| 229 | +``` |
| 230 | + |
| 231 | +## Formatting Rules |
| 232 | + |
| 233 | +**Prettier is the SOLE authority for non-Ruby files. RuboCop is the SOLE authority for Ruby files.** |
| 234 | + |
| 235 | +### Standard Workflow |
| 236 | +1. Make code changes |
| 237 | +2. Run `rake autofix` |
| 238 | +3. Commit |
| 239 | + |
| 240 | +### Merge Conflict Resolution |
| 241 | +1. Resolve logical conflicts only (don't manually format) |
| 242 | +2. `git add .` |
| 243 | +3. `rake autofix` |
| 244 | +4. `git add .` |
| 245 | +5. `git rebase --continue` or `git commit` |
| 246 | + |
| 247 | +**NEVER manually format during conflict resolution** - this causes formatting wars. |
| 248 | + |
| 249 | +## RuboCop Common Issues |
| 250 | + |
| 251 | +### Trailing Whitespace |
| 252 | +Remove all trailing whitespace from lines |
| 253 | + |
| 254 | +### Line Length (120 chars max) |
| 255 | +Break long lines into multiple lines using proper indentation |
| 256 | + |
| 257 | +### Named Subjects (RSpec) |
| 258 | +```ruby |
| 259 | +# Good |
| 260 | +subject(:method_result) { instance.method_name(arg) } |
| 261 | +``` |
| 262 | + |
| 263 | +### Security/Eval Violations |
| 264 | +```ruby |
| 265 | +# rubocop:disable Security/Eval |
| 266 | +# ... code with eval |
| 267 | +# rubocop:enable Security/Eval |
| 268 | +``` |
| 269 | + |
| 270 | +## IDE Configuration |
| 271 | + |
| 272 | +**Exclude these directories to prevent IDE slowdowns:** |
| 273 | +- `/coverage`, `/tmp`, `/gen-examples` |
| 274 | +- `/node_package/lib`, `/node_modules` |
| 275 | +- `/spec/dummy/app/assets/webpack` |
| 276 | +- `/spec/dummy/log`, `/spec/dummy/node_modules`, `/spec/dummy/tmp` |
| 277 | +- `/spec/react_on_rails/dummy-for-generators` |
| 278 | + |
| 279 | +## Important Constraints |
| 280 | + |
| 281 | +### Package Manager |
| 282 | +- **ONLY use Yarn Classic (1.x)** - never use npm |
| 283 | +- Package manager enforced via `packageManager` field in package.json |
| 284 | + |
| 285 | +### Dependencies |
| 286 | +- Shakapacker >= 6.0 required (v16+ drops Webpacker support) |
| 287 | +- Ruby >= 3.0 |
| 288 | +- Node.js >= 18 (tested: 18-22) |
| 289 | +- Rails >= 5.2 |
| 290 | + |
| 291 | +### Pro Features |
| 292 | +- React Server Components (RSC) |
| 293 | +- Streaming SSR |
| 294 | +- Loadable Components |
| 295 | +- Code splitting with React Router |
| 296 | +- Requires separate Pro subscription |
| 297 | + |
| 298 | +## Troubleshooting |
| 299 | + |
| 300 | +### React Components Not Rendering |
| 301 | +- Ensure yalc setup is complete |
| 302 | +- Run `yalc push` after changes |
| 303 | +- Check browser console for errors |
| 304 | +- Verify component is registered correctly |
| 305 | + |
| 306 | +### Generator Issues |
| 307 | +- Run `rake react_on_rails:doctor` |
| 308 | +- Check Shakapacker is properly installed |
| 309 | +- Ensure package.json exists |
| 310 | +- Test with `bin/dev kill` to stop conflicting processes |
| 311 | + |
| 312 | +### Test Failures |
| 313 | +- Run tests from correct directory (project root vs spec/dummy) |
| 314 | +- Check that `bundle install` and `yarn install` are current |
| 315 | +- Verify git hooks are installed: `bundle exec lefthook install` |
| 316 | + |
| 317 | +### Linting Failures |
| 318 | +- **Always run `bundle exec rubocop` before pushing** |
| 319 | +- Use `rake autofix` to fix most issues automatically |
| 320 | +- Check `.rubocop.yml` for project-specific rules |
| 321 | + |
| 322 | +## Monorepo Merger (In Progress) |
| 323 | + |
| 324 | +The project is merging `react_on_rails` and `react_on_rails_pro` into a unified monorepo. During this transition: |
| 325 | +- Continue contributing to current structure |
| 326 | +- License compliance is critical (no Pro code in MIT areas) |
| 327 | +- See `docs/MONOREPO_MERGER_PLAN_REF.md` for details |
| 328 | + |
| 329 | +## Additional Resources |
| 330 | + |
| 331 | +- [CONTRIBUTING.md](./CONTRIBUTING.md) - Comprehensive contributor guide |
| 332 | +- [CODING_AGENTS.md](./CODING_AGENTS.md) - AI-specific development patterns |
| 333 | +- [CLAUDE.md](./CLAUDE.md) - Claude Code specific guidance |
| 334 | +- [docs/](./docs/) - Full documentation |
| 335 | +- [Shakapacker](https://github.com/shakacode/shakapacker) - Webpack integration |
0 commit comments