skillby rubys

compare-erb-js

Compare ERB and JavaScript template outputs for the offline scoring SPA. Use when working on ERB-to-JS conversion, debugging template parity issues, or verifying that changes to scoring views work correctly in both ERB and SPA modes.

Installs: 0
Used in: 1 repos
Updated: 1d ago
$npx ai-builder add skill rubys/compare-erb-js

Installs to .claude/skills/compare-erb-js/

# Compare ERB vs JavaScript Template Output

Use `scripts/render_erb_and_js.rb` to verify that ERB templates and their JavaScript-converted equivalents produce matching output. This is essential for the offline scoring SPA which uses auto-converted ERB templates.

## Basic Usage

```bash
# Compare heat list
bundle exec ruby scripts/render_erb_and_js.rb db/2025-barcelona-november.sqlite3 83

# Compare individual heat
bundle exec ruby scripts/render_erb_and_js.rb db/2025-barcelona-november.sqlite3 83 1

# With style parameter
bundle exec ruby scripts/render_erb_and_js.rb db/2025-barcelona-november.sqlite3 83 1 radio
```

Or using environment variable:
```bash
RAILS_APP_DB=2025-barcelona-november bundle exec ruby scripts/render_erb_and_js.rb 83 1
```

## What It Does

1. Renders the ERB template via Rails routing (extracts `<main>` content)
2. Fetches converted JavaScript templates from `/templates/scoring.js`
3. Fetches normalized data from `/scores/:judge/heats/data`
4. Hydrates the data using `heat_hydrator.js` (for individual heats)
5. Renders using the JavaScript template
6. Compares row counts and saves both outputs for diff analysis

## Output Files

All files are saved to `/tmp/` for analysis:

- `/tmp/erb_rendered.html` - ERB template output (main content only)
- `/tmp/js_rendered.html` - JavaScript template output
- `/tmp/scoring_templates.js` - Converted templates from `/templates/scoring.js`
- `/tmp/heats_data.json` - Raw normalized data from server
- `/tmp/js_template_data.json` - Hydrated data passed to JS template

## Analyzing Differences

```bash
# Quick diff
diff /tmp/erb_rendered.html /tmp/js_rendered.html

# Side-by-side comparison
diff -y /tmp/erb_rendered.html /tmp/js_rendered.html | less

# Compare specific attributes
diff <(grep -o 'href="[^"]*"' /tmp/erb_rendered.html | sort) \
     <(grep -o 'href="[^"]*"' /tmp/js_rendered.html | sort)
```

## Common Differences

Some differences are expected due to ERB-to-JS conversion limitations:

- **HTML entity encoding**: ERB uses `&quot;` while JS uses `"`
- **link_to blocks**: Block form of `link_to` may render differently
- **Whitespace**: Minor whitespace differences are normal

## Architecture

This tool supports the "Server computes, hydration joins, templates filter" principle:

- **Server**: Computes derived values and paths (respects RAILS_APP_SCOPE)
- **Hydration**: `heat_hydrator.js` joins normalized data by resolving IDs
- **Templates**: ERB and JS templates filter/format data identically

## Key Source Files

### Server-side (Rails)

- `app/controllers/scores_controller.rb`
  - `heats_data` action: Returns normalized JSON data for SPA
  - `heat` action: Sets instance variables for ERB templates
  - Computes `paths:` hash with server-computed URLs

- `app/controllers/templates_controller.rb`
  - `scoring` action: Converts ERB templates to JavaScript on-the-fly
  - Defines path helper stubs for JS templates
  - Uses `ErbPrismConverter` for conversion

- `lib/erb_prism_converter.rb`
  - Converts ERB templates to JavaScript functions using Ruby's Prism parser
  - Handles Ruby-to-JS translation (loops, conditionals, method calls)

### Client-side (JavaScript)

- `app/javascript/lib/heat_hydrator.js`
  - `buildLookupTables()`: Creates Maps for O(1) entity lookup
  - `hydrateHeat()`: Resolves IDs to full objects
  - `buildHeatTemplateData()`: Prepares complete data for templates

- `app/javascript/controllers/heat_app_controller.js`
  - Main Stimulus controller for the offline scoring SPA
  - Loads templates and data, handles navigation
  - Manages offline/online state transitions

### ERB Templates (source of truth)

- `app/views/scores/heat.html.erb` - Main heat view
- `app/views/scores/heatlist.html.erb` - Heat list view
- `app/views/scores/_heat_header.html.erb` - Heat header partial
- `app/views/scores/_info_box.html.erb` - Info box with feedback errors
- `app/views/scores/_navigation_footer.html.erb` - Prev/next navigation
- `app/views/scores/_table_heat.html.erb` - Standard heat table
- `app/views/scores/_rank_heat.html.erb` - Finals ranking view
- `app/views/scores/_solo_heat.html.erb` - Solo heat view
- `app/views/scores/_cards_heat.html.erb` - Card-based scoring view

### Scripts

- `scripts/render_erb_and_js.rb` - This comparison tool
- `scripts/hydrate_heats.mjs` - Node.js script for hydrating data (used by comparison tool)

Quick Install

$npx ai-builder add skill rubys/compare-erb-js

Details

Type
skill
Author
rubys
Slug
rubys/compare-erb-js
Created
4d ago