HarperFast / HarperFast/prerender-plugin
Byte attribution of a served product snapshot: inlined CSS is 13%, attributes are 75%
- Ngôn ngữ chính
- JavaScript
- Star
- 0
- Fork
- 0
- Merge trung bình
- 9 giờ 39 phút
- Pull request đã merge (30 ngày)
- 39
Mô tả
## Summary
A served product snapshot was reported as having a low text-to-HTML ratio, attributed to the CSS `flattenShadowDom` inlines for the review widget. Measured against a real served page, that attribution is wrong: **inlined CSS is 13.4% of the document and attributes are 74.7%.** Deleting every byte of injected styling moves the ratio 2.66% → 3.07%.
This issue records the byte attribution so the numbers aren't re-derived, and separates the levers that are provably safe from the one that isn't.
## Method
One review-heavy product page (desktop), read from the serving cache via `/prerender_admin/page-content`, so these are the bytes a crawler receives. Rendered by browser **v1.21.0** with `flattenShadowDom`, `pruneUnmatchedCss` and `minifyInlineCss` all on — i.e. the CSS below is already the residue after ~74% of style rules were pruned and the rest CSSOM-minified.
Class-token reference counts were computed against the inline `` blocks **and the four external stylesheets the snapshot still links**. Measuring against inline CSS alone overstates the unreferenced total by ~6× (359 KB vs the true 61 KB) — the page keeps a 588 KB external utility stylesheet, so most tokens are referenced from a sheet that is not in the document.
## Where 1,468,123 bytes go
| | bytes | % of doc |
| --- | ---: | ---: |
| `class` attributes | 451,713 | 30.8% |
| inlined `<style>` CSS | 197,160 | 13.4% |
| `style=` attributes | 140,957 | 9.6% |
| `href` / `src` / `srcset` | 214,751 | 14.6% |
| SVG `d` path data | 81,344 | 5.5% |
| `aria-label` | 52,604 | 3.6% |
| tag names + brackets | 55,700 | 3.8% |
| ld+json | 17,486 | 1.2% |
| **visible text** | **39,078** | **2.66%** |
10,137 elements. **74.7% of the document is HTML attributes.**
## The review widget
The flattened review container is **385,482 B — 26.3% of the page — carrying 7,707 B of review text (2.0% of itself)**. Eight review cards; one card is **22,446 B / 235 elements for 956 B of text**.
| inside the review container | bytes | % of block |
| --- | ---: | ---: |
| inlined `<style>` (host sheet + nested shadow hosts) | 152,624 | 39.6% |
| SVG markup (`d` alone = 62,473) | 108,954 | 28.3% |
| `class` | 60,930 | 15.8% |
| review text | 7,707 | 2.0% |
## Two candidates measured and rejected
- **Deduplicating identical shadow stylesheets across hosts.** 9 distinct sheets across 10 hosts; total bytes sitting in duplicate copies: **196 B**. Not a lever.
- **`minifyInlineCss` on the flattened blocks.** Already CSSOM output, so re-emission is a no-op — consistent with the existing docstring.
## Levers that remain, with sizes
1. **Repeated SVG path data — ~64,093 B (4.4% of the document), concentrated in the review block.** 193 `d` occurrences, only 61 distinct; a single 1,033-byte path appears **45 times** (46,485 B). Hoisting exact-duplicate path data into `<defs><symbol>` + `<use>` renders identically. No such pass exists in `postProcess` today.
2. **Class tokens no surviving rule references — 61,277 B page-wide, 34,467 B inside the review block.** Same soundness argument that already licenses `pruneUnmatchedCss`: with `stripScripts` on, nothing can add a class after serialization, so a token no sheet mentions is inert. Must be evaluated against external sheets, not just inline ones.
3. **A repeated background-image URL in `style=` attributes — ~93,000 B.** One sprite URL repeated 489 times across `style=` attributes. Origin-authored, not introduced by post-processing.
## Cloaking: what actually carries risk here
Worth stating explicitly, because "fidelity" has been used to decline byte-cutting levers that do not actually implicate it.
Cloaking is **presenting different content to users and crawlers in order to manipulate rankings**. The unit is content — text, links, images, prices, availability, structured data — not markup. Removing an attribute no rule reads, deduplicating identical SVG path data, or pruning a rule that matches nothing changes zero content: a user and a crawler still perceive the same page. Levers 1–3 are outside the policy, and rendering-fidelity checks (`paintParity`, geometry) are the right bar for them for a *different* reason — Google indexes the rendered DOM and devalues content it determines is not visible, so a layout regression costs indexing quality on its own merits.
The risk is **asymmetric, and it runs the other way**: *revealing* content to a crawler that a user does not see is the cloaking-shaped move. That is exactly what dropping the review widget's CSS would do — the widget's own rules hold collapsed panels, modals and secondary UI at `display:none`, and stripping them injects text into the indexable page that no user is shown. It would also reintroduce the inbound-encapsulation defects fixed across v1.19–v1.21. **Do not pursue "just drop the review CSS" for byte savings.**
## Note for answer/generative engines
Structured data carries `aggregateRating` (`ratingValue`, `ratingCount`) but **no individual `review` objects**. So the 385 KB review DOM is the only place individual review content exists in the snapshot — it is load-bearing for extraction, not redundant with the JSON-LD, and should not be treated as trimmable content. Emitting `review` items into the JSON-LD would serve extraction far better per byte than the DOM does, but that is an origin change, not a post-processing one.
Separately: text-to-HTML ratio is not a documented ranking signal — it is a third-party audit-tool metric. The documented hard constraint is the 1 MB soft cap a crawler applies to a document, and this page is at 1.47 MB. Sizing work against "get under 1 MB" is better defined than "raise a ratio", and levers 1–3 together are ~218 KB of the ~470 KB needed.
Hướng dẫn đóng góp
Hướng nghiên cứu
Start by reading the postProcess path and the existing pruneUnmatchedCss and minifyInlineCss behavior, then reproduce the byte breakdown from /prerender_admin/page-content with the stated browser v1.21.0 options. Compare the SVG, class-token, and repeated style-URL levers against external stylesheets and paint or geometry parity; do not remove the review widget CSS. Done requires a selected, measured optimization with unchanged rendered content and a clear path toward the 1 MB cap.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- javascript
- Lĩnh vực
- performance
- Loại issue
- Tính năng
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Cần làm rõ
- Mức phù hợp với người mới
- 35/100