You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Optimize simplecov-html for large coverage reports
A real-world coverage report with 1705 source files produces a **41MB
HTML file** (~1.9M lines) that causes significant browser slowdown:
- 96% of the file is the source files section (~41.3MB)
- 51% of that section is whitespace from ERB template formatting (~21MB)
- 142,254 `<li>` elements rendered into the DOM at page load (hidden)
- 142K event handlers individually bound to line number elements
- An unnecessary `<div>` wrapper around each `<li>` adds 142K extra DOM nodes
**ERB whitespace trimming** (`lib/simplecov-html.rb`, all `.erb` views)
- Add `trim_mode: '-'` to the ERB constructor
- Add `<%-` / `-%>` trim markers to control flow tags in all templates
- Eliminates ~21MB of blank lines produced by ERB conditionals/loops
**Remove `<div>` wrapper around `<li>`** (`views/source_file.erb`)
- These were semantically invalid inside `<ol>` and unnecessary
- Saves ~2.8MB and 142K DOM nodes
**Conditional `data-hits` attribute** (`views/source_file.erb`)
- Only emit `data-hits="N"` when `line.coverage` is truthy
- Previously emitted `data-hits=""` for ~83K "never" lines with no
JS/CSS referencing the empty attribute
**Compact `covered_percent.erb`**
- Single-line template avoids multi-line whitespace across ~3,400 calls
**`<template>` tags for source files** (`views/layout.erb`)
- Each source file is wrapped in `<template id="tmpl-SHA1">`
- `<template>` content is parsed but NOT rendered into the DOM until
explicitly activated — removes ~500K DOM nodes from initial page load
**Template materialization on demand** (`assets/javascripts/application.js`)
- New `materializeSourceFile()` function clones template content into
the `.source_files` container when a file is first viewed
- Syntax highlighting applied on materialization (same deferred approach)
- All code paths updated: click, colorbox onLoad, popstate, deep links
**Event delegation for line number clicks** (`assets/javascripts/application.js`)
- Replaced direct binding on 142K elements with a single delegated
event handler on `document`
- Required for `<template>` approach and eliminates 142K event bindings
Tested against a real coverage report with 1705 source files:
| Metric | Before | After | Change |
|---------------------|-------------|-----------|--------------|
| File size | 41 MB | 25 MB | **-39%** |
| Lines | 1,944,847 | 573,916 | **-70%** |
| Blank lines | 1,090,596 | 3,578 | **-99.7%** |
| `<div>` wrappers | 142,255 | 2 | **-142,253** |
| `data-hits` attrs | 142,253 | 59,101 | **-83,152** |
| DOM nodes at load | ~500K+ | ~few K | deferred via `<template>` |
| Event bindings | 142K | 1 | delegated |
The remaining 25MB is predominantly the actual source code content
inside `<li>` elements, which is irreducible.
| File | Changes |
|---|---|
| `lib/simplecov-html.rb` | `trim_mode: '-'` on ERB constructor |
| `views/source_file.erb` | Trim markers, remove `<div>`, conditional `data-hits` |
| `views/layout.erb` | Trim markers, `<template>` tags around source files |
| `views/file_list.erb` | Trim markers on control flow tags |
| `views/covered_percent.erb` | Single-line template |
| `assets/javascripts/application.js` | Template materialization, event delegation |
| `public/application.js` | Re-compiled asset |
- [x] `bundle exec rake test` passes
- [x] Generate a coverage report against a test project and compare HTML file size
- [x] Open in browser: file list loads, clicking a file shows source in modal
- [x] Line numbers are clickable and scroll to correct position
- [x] Syntax highlighting works on opened files
- [x] Back/forward navigation works correctly
- [x] Deep-linking to a specific file/line via URL hash works
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0 commit comments