Skip to content

Serve the page stylesheet as one shared file instead of 5,060 bytes on every page #95

Description

@ChelseaKR

What

Every published page carries the whole stylesheet inline (render.py:1009,
f"<style>\n{STYLESHEET}</style>\n"). Measured on the committed tree today, not
estimated: 23,305 HTML files carry 118,166,787 bytes of <style> between
them — 13.62% of the 867,639,523-byte tree — in four distinct blocks:

Block Bytes Pages Total
school page 5,060 21,068 106,604,080
county / district page 5,168 2,234 11,545,312
landing page 5,249 1 5,249
ask page 6,073 2 12,146

Lifting the first three into shared files under site/ and linking them, at
roughly 45 bytes of <link> per page, recovers about 117 MB.

Why it matters

The byte budget is now the thing deciding what Homeroom may publish. The tree is
at 86.8% of the 1 GB GitHub Pages allows; D5 on the school pages is a measured
+184 MB and does not fit (#82);
D4, D6 and one copied column per prior year
(#83) each land on all 21,068
school pages the same way.

Stated honestly, because the arithmetic matters more than the enthusiasm: this
does not on its own put a D5 republish under the repository's own 90% budget.
867.6 − 117.1 + 184 ≈ 934.5 MB, which is 93.5% of the ceiling and over the
900 MB budget tests/test_published_limits.py holds. What it does is move the
next publish from undeployable at any price (105% of the ceiling) to inside
the host's ceiling
, and it is the largest saving available that takes nothing
off the page. #82's option 3 says "184 MB is more than county/ and district/ put
together (19.5 MB), so what is on the table is a whole existing section". This is
a fourth option that option list does not consider, and it is 6× the size of the
one it does.

The README rules the equivalent saving out for the ask pages, and rightly:
"those bytes being inline is exactly what makes tools/ask-optin.mjs's
zero-requests-on-load assertion true." That argument is about the ask page. It
does not reach the school, county, district and landing pages, which carry no
script, make no request today, and would be linking one same-origin static file
this build wrote — not a third party, not a tracker, and nothing a reader's
browser reports anywhere.

Scope

  • src/homeroom/render.pySTYLESHEET stops being emitted inline and becomes
    a named asset; the school/browse/landing variants become two or three files
    rather than one, since they are already three distinct blocks.
  • src/homeroom/site.py — it already copies package assets to the output tree
    (ASSETS_DIR, shutil.copyfile, _publish_social_cards), so the emit path
    exists. The <link> uses the relative form the pages already use across
    directories (../district/…, ../index.html), so a county page references
    ../homeroom.css.
  • The palette stays in Python. render.py's LIGHT/DARK dicts exist
    precisely so tests/test_pages.py can do contrast arithmetic without a
    browser; that test reads the dicts, not the CSS string, and is unaffected.
    Keep it that way.
  • src/homeroom/publish_limits.py and tests/test_published_limits.py — the
    measured tree figure and the ROADMAP metrics-ledger row are restated from a
    re-measurement, never edited to the expected number.
  • tests/test_published_site.py and tools/verify_live_site.py — the stylesheet
    is a published file: the walk has to know about it and the daily sentinel has
    to be able to fetch it, or a 404 stylesheet becomes an invisible failure.
  • The ask pages keep their inline block, untouched, and a test asserts it.
  • README "Status" and the "no script, no external asset" line, plus
    docs/adr/0001-render-pages-in-python-and-gate-them-outside-it.md, need
    restating rather than quietly contradicting.

The property that makes the trade safe, and it should be a test

A page whose stylesheet fails to load must still be honest. It already is, by
design: the four cell states are kept apart by words as well as colour — a
withheld figure renders "withheld to protect privacy" and never a digit. So an
unstyled page loses the visual separation and keeps the factual one. That is the
argument for the change and it should be asserted (render a page, strip the
stylesheet, assert no withheld or unpublished cell renders a digit) rather than
believed.

What has to be decided first

  1. Whether a linked same-origin stylesheet is compatible with the property the
    README states as "no script, no external asset". It is a change to something
    the site says about itself, so it is yours.
  2. Cache behaviour across a republish. A fixed filename can serve a stale
    stylesheet against new markup for a reader with it cached; a filename carrying
    its own content hash avoids that and changes on every publish, which the
    publish diff (#84) would
    then see every time.

Roughly how big

Multi-session. The emit is small; the gates, the re-measurement, the document
restatements and a republish are not, and the republish itself is yours.

Proposed with AI assistance.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfeatureMajor new capability proposal

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions