compare-erb-js
About
This skill compares ERB and JavaScript template outputs to ensure parity during ERB-to-JS conversion for the offline scoring SPA. It's used for debugging template differences and verifying view changes work correctly in both rendering modes. Developers run a provided Ruby script to generate and compare outputs for specific heats or views.
Quick Install
Claude Code
Recommended/plugin add https://github.com/majiayu000/claude-skill-registrygit clone https://github.com/majiayu000/claude-skill-registry.git ~/.claude/skills/compare-erb-jsCopy and paste this command in Claude Code to install this skill
Documentation
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
# 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:
RAILS_APP_DB=2025-barcelona-november bundle exec ruby scripts/render_erb_and_js.rb 83 1
What It Does
- Renders the ERB template via Rails routing (extracts
<main>content) - Fetches converted JavaScript templates from
/templates/scoring.js - Fetches normalized data from
/scores/:judge/heats/data - Hydrates the data using
heat_hydrator.js(for individual heats) - Renders using the JavaScript template
- 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
# 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
"while JS uses" - link_to blocks: Block form of
link_tomay 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.jsjoins normalized data by resolving IDs - Templates: ERB and JS templates filter/format data identically
Key Source Files
Server-side (Rails)
-
app/controllers/scores_controller.rbheats_dataaction: Returns normalized JSON data for SPAheataction: Sets instance variables for ERB templates- Computes
paths:hash with server-computed URLs
-
app/controllers/templates_controller.rbscoringaction: Converts ERB templates to JavaScript on-the-fly- Defines path helper stubs for JS templates
- Uses
ErbPrismConverterfor 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.jsbuildLookupTables(): Creates Maps for O(1) entity lookuphydrateHeat(): Resolves IDs to full objectsbuildHeatTemplateData(): 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 viewapp/views/scores/heatlist.html.erb- Heat list viewapp/views/scores/_heat_header.html.erb- Heat header partialapp/views/scores/_info_box.html.erb- Info box with feedback errorsapp/views/scores/_navigation_footer.html.erb- Prev/next navigationapp/views/scores/_table_heat.html.erb- Standard heat tableapp/views/scores/_rank_heat.html.erb- Finals ranking viewapp/views/scores/_solo_heat.html.erb- Solo heat viewapp/views/scores/_cards_heat.html.erb- Card-based scoring view
Scripts
scripts/render_erb_and_js.rb- This comparison toolscripts/hydrate_heats.mjs- Node.js script for hydrating data (used by comparison tool)
GitHub Repository
Related Skills
algorithmic-art
MetaThis Claude Skill creates original algorithmic art using p5.js with seeded randomness and interactive parameters. It generates .md files for algorithmic philosophies, plus .html and .js files for interactive generative art implementations. Use it when developers need to create flow fields, particle systems, or other computational art while avoiding copyright issues.
subagent-driven-development
DevelopmentThis skill executes implementation plans by dispatching a fresh subagent for each independent task, with code review between tasks. It enables fast iteration while maintaining quality gates through this review process. Use it when working on mostly independent tasks within the same session to ensure continuous progress with built-in quality checks.
executing-plans
DesignUse the executing-plans skill when you have a complete implementation plan to execute in controlled batches with review checkpoints. It loads and critically reviews the plan, then executes tasks in small batches (default 3 tasks) while reporting progress between each batch for architect review. This ensures systematic implementation with built-in quality control checkpoints.
cost-optimization
OtherThis Claude Skill helps developers optimize cloud costs through resource rightsizing, tagging strategies, and spending analysis. It provides a framework for reducing cloud expenses and implementing cost governance across AWS, Azure, and GCP. Use it when you need to analyze infrastructure costs, right-size resources, or meet budget constraints.
