---
title: "02 — Frontend Performance: The Medium Tier (Asset Discipline & The Repeat Visit)"
uid: frontend-performance-medium-priority
tags: ["cdn", "service-workers", "lazy-loading", "roadmap:frontend-performance", "frontend", "images", "performance"]
excerpt: "The 13 Medium Priority items assume the High baseline is handled, then tighten images, sit close to users, and gift the repeat visit."
date: 2026-08-13T04:50:28+0000
source: https://www.aveshina.my.id/en/blog/frontend-performance-medium-priority
---

Picking up from the High Priority notes, the 13 items roadmap.sh ranks **Medium Priority** all assume the baseline tier is handled [1]. Once pages are under ~1.5 MB, scripts are deferred, and the critical CSS is inlined, the question changes: where do the next wins come from? My shorthand for the whole tier is **asset discipline and gift the repeat visit** — three sub-themes that run through the 13 items.

- **Tighten the images** (#22-26) — five items, all on the same asset.
- **Sit close and ship less, again** (#20, #21, #27, #30) — four items on the shape of the page and the network hop.
- **Maintenance and payload hygiene** (#28, #29, #31, #32) — the long tail: deps, JS self-audit, cookies.

## Tighten the images

Images got their own line in the High Priority tier (compress, choose format). The medium tier is where the on-page _mechanics_ of images land, and five of the 13 items live here.

- **Prefer vector image rather than bitmap images** — SVG for logos, icons, illustrations, anything that's actually a shape. Vectors scale without artifacts and weigh bytes, not megabytes. The failure mode is a designer handing you a PNG of a logo where an SVG would do, then shipping 80 KB per DPI breakpoint for retina sharpness. Convert once, lose bytes forever.
- **Set width and height attributes on images (aspect ratio)** — the modern reason is layout shift, not just sizing. With explicit dimensions the browser reserves the box in the layout _before_ the image bytes arrive, so the page doesn't reflow when it loads. CLS (Cumulative Layout Shift) is a Core Web Vital (one of Google's page-experience scores); unreserved images are its biggest cause.
- **Avoid using Base64 images** — base64-inlined images bloat HTML, can't be cached separately, and the encoded form is ~33% larger than the binary on the wire. The one exception roadmap.sh notes elsewhere is inlining a tiny above-the-fold image inside critical CSS for one fewer request — even then, weigh the bytes. For anything larger, an external <img> with loading="lazy" (see next) wins on every metric that matters.
- **Offscreen images are loaded lazily** — loading="lazy" on <img>, or use the Intersection Observer directly for finer control. The browser skips the network round trip until the image approaches the viewport. On a long page with a dozen images this is the single biggest transfer-size win below the High Priority baseline, and it's a one-attribute change.
- **Serve images that are close to your display size** — no point shipping a 2400px JPG to a phone that renders it at 320px. The mechanism is srcset/<picture> or a server-side resize (or a CDN transform). The mental check: every pixel above the display size is wasted bytes; every breakpoint should ship the closest available variant.

Five moves on one asset. The thread: bytes that the user can't see right now (off-screen, over-resolution, base64-inlined duplicates) cost the same as useful ones.

## Sit close, ship less, again

Four items that rode the High Priority ideas ("ship it faster" and "don't block") into a slightly different shape.

- **Minified HTML — remove comments and whitespace** — usually a server/CDN/SSR framework setting rather than a build step. The savings are smaller per page than minified JS/CSS, but they apply to _every_ response including the first byte: there's no cache to amortize them across. Turn it on in production.
- **Use Content Delivery Network** — the High Priority tier had TTFB < 1.3s and cache headers; the medium tier moves the origin out of the equation entirely. A CDN sits the static assets (and ideally the HTML, via ISR or full static) next to the user, collapsing round trips from intercontinental to local. This is the move that converts a 1.5s origin TTFB into a 150ms edge TTFB without touching code.
- **Avoid multiple inline JavaScript snippets <script>** — the parser-blocking risk of inline scripts is the small part of the problem; the bigger part is that inline scripts can't be cached, can't be deferred by an HTTP header, and accumulate invisibly as one-off "just one line" patches throughout a template. Move them to an external deferred bundle; if a page truly needs one snippet, isolate it.
- **Service Workers for caching / performing heavy tasks** — unlike Cache-Control, a Service Worker is programmable caching: you decide what's served from cache, what gets a network-first strategy, what runs in the background. This is where the "gift the repeat visit" idea lands. A SW with a decent cache strategy makes the second navigation instantaneous, with the trade-off being cache invalidation logic you now own. For the heavy-task side: don't put crypto or image processing in the SW; the request thread is the user's. Use a Web Worker instead, leave the SW to caching.

## Maintenance and payload hygiene

The last four items are about _keeping_ the gains, because entropy eats unattended performance within a quarter.

- **Keep your dependencies up to date** — two reasons corner this one. First, modern packages (frameworks, bundlers, runtime) ship meaningful performance fixes in minors and patches — three minor versions behind is a real, measurable regression. Second, security. npm outdated once a sprint, npm audit in CI, and Dependabot/Renovate for the long tail.
- **Check for performance problems in your JavaScript files** — the High Priority tier said "minify and defer"; the medium tier says "audit what's left." Lighthouse, Chrome DevTools Performance panel, and Bundlephobia on the entry bundle are the trio I use. The recurring offenders: unused exports tree-shaking didn't catch, large libraries imported for one method, and re-renders from poorly memoized components.
- **Cookie size should be less than 4096 bytes** — every byte in a cookie rides along on _every_ same-origin request, including static assets (if they share the domain). Most of the size bloat I've seen is from storing entire JSON blobs in cookies — push that to a server-side session keyed by an ID instead. 4096 is the spec limit; aim for "small enough you forget it's there."
- **Keep the cookie count less than 20** — the count matters because browsers cap cookies per domain (often 50-ish), but also because every cookie appends to every request line on the wire. Tracking pixels, third-party analytics cookies, and "remember my theme" cookies stack up. Audit quarterly; the ones you forgot about are the ones killing you.

## The two-and-two close

Thirteen items, three sub-themes, and a pattern: the Medium tier isn't where the spectacular wins are, it's where you stop the slow bleed. The High Priority tier sets the floor; the Medium tier keeps the floor from sagging. Two image attributes (width, loading) and srcset, plus a CDN, plus a one-attribute switch on defer, will together claw back most of this tier for almost any page that's never been audited. The hard part isn't implementing them — it's keeping them in place six months later, which is exactly why "keep your dependencies up to date" lives here too.

The Low Priority tier that follows is the finishing polish: fonts and preload. Different flavor of work — more byte-tuning than structure — but the same habit of measurement.

## References

- [1] roadmap.sh, "Frontend Performance Best Practices — Medium Priority," roadmap.sh, 2024. [Online]. Available: [https://roadmap.sh/frontend-performance-best-practices](https://roadmap.sh/frontend-performance-best-practices)
- [2] MDN, "loading attribute," Mozilla, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading)
- [3] web.dev, "Use a CDN," Google, 2024. [Online]. Available: [https://web.dev/articles/content-delivery-networks](https://web.dev/articles/content-delivery-networks)
- [4] MDN, "Service Worker API," Mozilla, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
