Hexo filter: embed intrinsic width/height for remote <img> at build time to reduce CLS.
npm install hexo-imagesize-intrinsicA Hexo plugin that writes intrinsic width/height attributes for remote tags at build time.
This reduces Cumulative Layout Shift (CLS) and improves visual stability.
Before (raw post content):
``html`

The image has no intrinsic size.
When the browser loads, the layout may jump (CLS).
After (generated HTML by Hexo):
`html`

The plugin probed the remote image, detected its intrinsic size (1280x720),
and wrote width/height attributes into the .
👉 Result: The page reserves space before the image is loaded, avoiding layout shift.
- ✅ Automatically detects remote images in posts/pages (layout: post or page) width
- ✅ Writes intrinsic and height attributes into .cache/hexo-imgsize.json
- ✅ Supports non-ASCII filenames (Chinese, spaces, etc.)
- ✅ Caches probed sizes in .cache/imgsize-run-report.json
- ✅ Writes per-run report (grouped by page, with url/status/reason) off | summary | verbose
- ✅ Configurable concurrency, timeout, retry, headers, referer
- ✅ Optional progress bar (on stderr)
- ✅ Three log levels:
- ✅ Optional cache cleanup (remove unused or TTL-expired entries)
`bash`
npm install hexo-imagesize-intrinsic --save
Hexo will automatically load it.
In your site _config.yml, add:
`yml`
imagesize_intrinsic:
enabled: true
log_level: summary # off | summary | verbose
progress: true # show progress bar
This is usually enough for most sites.
| true | Master switch for the plugin |
| log_level | summary | off = no logs; summary = only totals; verbose = per page & per image |
| progress | true | Show progress bar on stderr |
| concurrency | 8 | Number of concurrent probes (increase for faster builds if network allows) |
| timeout_ms | 8000 | Timeout for each probe in milliseconds |
| retry | 1 | Retry count after a failed probe |
| strip_query | false | Drop ?query part of URL when caching size (useful if query doesn’t change pixels) |
| referer | "" | Optional Referer header for anti-hotlinking hosts |
| headers | {} | Extra request headers (merged with defaults) |
| whitelist | [] | List of hostnames to process; empty = all remote images |
| cache_present_with_size | true | Cache images that already have width/height, so other pages can reuse |
| cleanup_unused | false | Enable cache cleanup after generate; when true, removes unused or expired entries |
| cleanup_ttl_days | 0 | TTL for cache entries in days; > 0 removes entries not seen within TTL; 0 removes entries unused in the current run |Output
- Cache file:
.cache/hexo-imgsize.json
Stores probed sizes for reuse across builds.
- Run report:
.cache/imgsize-run-report.json
Example:
`json
{
"pages": [
{
"page": "posts/hello-world.md",
"images": [
{"url":"https://cdn.example.com/a.png","status":"wrote"},
{"url":"https://cdn.example.com/b.png","status":"cached"},
{"url":"https://cdn.example.com/c.png","status":"failed","reason":"timeout"},
{"url":"https://cdn.example.com/d.png","status":"skipped","reason":"already-has-size"}
]
}
]
}
`- Logs:
- summary → only final two lines:
`log
[imgsize] [total] pages=23 imgs=157 wrote=100 cached=50 failed=5 skipped=2 cleaned=12
[imgsize] run report -> .cache/imgsize-run-report.json
`
- verbose → per-page + per-image detail.Notes
- If your site already has a large number of images, the first run may take a long time because all image sizes need to be probed. Subsequent runs will be much faster thanks to the cache in
.cache/hexo-imgsize.json.
- Works only for remote images (http/https). Local source/ images are skipped.
- Progress bar prints to stderr; Hexo’s INFO logs remain in stdout.
- If you had a theme script doing similar work, remove it to avoid duplication.
- You can increase concurrency (e.g. 12–16) to speed up builds, depending on your network and image host.
- timeout_ms and retry can be tuned for stability.
- Cache stores a last_seen timestamp per URL; when cleanup_unused is enabled, cleanup runs in Hexo’s after_generate phase using cleanup_ttl_days` (TTL-based) or current-run usage (TTL = 0).MIT © Keldos Li