Performance & Infrastructure
Design & UX

The JavaScript Your Users Pay For

A number is circulating from Addy Osmani’s analysis of what JavaScript actually costs, and we would like it read before the framework debates of 2018 convene. Byte for byte, JavaScript is vastly more expensive to the browser than an image of the same size.

The image decodes and paints. The script must be downloaded, then parsed, then compiled, then run. Every one of those stages runs on whatever CPU actually shows up, single-threaded, on the main thread that everything else is waiting behind.

On the developer’s machine, the current MacBook on office wifi, all of this is imperceptible, which is precisely the trap. The median phone that shows up in real analytics is a mid-range Android device, several years of Moore’s-law distance from the demo hardware, on a network with real latency. On that device, the same bundle that felt free in development costs seconds of frozen interface.

Osmani’s data puts numbers on the gap. Parse-and-compile alone for a large bundle can cost more time on a median phone than the entire download took, before a single line runs. ‘Fast on my MacBook’ is the most expensive sentence in front-end development, and this year it finally comes with a bill itemized well enough to show the finance committee.

Why the SPA pattern concentrates the cost

The single-page-app architecture, the framework-rendered app we have covered since JavaScript ate the page, front-loads exactly the expensive resource. The user requests a page and receives, first, the application. The bundle that must be fully downloaded, parsed, compiled, and booted before real content appears.

The pattern’s benefits are real where the page genuinely is an application. The interactive tools, the editors, the dashboards we build and defends.

But applied to content (the program page, the article, the department site) it reverses the web’s oldest performance virtue. The document that could have streamed its first paragraph in the first round trip instead ships a runtime and renders itself afterward. Every visitor pays an app boot fee to read a page.

Our own field numbers this year, on inherited SPA sites, match Osmani’s curves. Time-to-interactive on median mobile hardware routinely runs several times what the same content costs as a server-rendered document. The difference is not the network. It is the main thread, doing framework work the content never asked for.

Hence the question we now ask at every architecture review, and commend to yours. Is this page an application, or a document dressed up as one? Most institutional pages are documents. Ship them as documents, and pocket the speed.

The equity framing, which is not rhetorical

For this readership specifically (the campuses, hospitals, and public agencies whose sites exist to serve broadly) the device-cost math carries a weight the industry discourse underplays.

Your analytics’ device mix is not a market outcome to shrug at. It is your service population. The visitors on the most modest hardware are, far out of proportion, the ones with the fewest alternatives to your website. The applicant without a laptop whose entire college process runs through a phone. The patient looking up the clinic on a prepaid Android. The family on a shared device applying for aid.

A script-heavy architecture is, functionally, a decision about who waits and who leaves. Made silently by a build pipeline, and paid by exactly the people the institution’s mission names.

That connects this month’s performance piece to the accessibility work we have covered for a decade. Both are the same commitment, the site serves the people who actually arrive, on the means they actually have, enforced at different layers. The mobile-performance sermons of 2013 made this argument on network weight. Osmani’s data reissues it on CPU cost, and the gap widens as bundles grow faster than median hardware improves.

An institution that would never post a stairs-only entrance should not ship a flagship-only website, and the second is now measurable.

The practices that follow

  • Extend the performance budget to script, explicitly. The budget practice we installed in 2013 gains its newest line item. A JavaScript weight ceiling per page template. Tested on real-world hardware, the affordable-Android test device our mobile pieces prescribe. Enforced in the build, with time-to-interactive joining page weight in the definition of done.

  • Code splitting as default, not optimization. Ship each page the script it needs. Load the rest on demand. The bundlers have made this routine, and the monolithic bundle is now a choice, not a constraint.

  • Server-render the document tier. Content pages arrive as HTML, enhanced afterward where enhancement earns its cost, per the progressive-enhancement rule we have followed since 2006.

  • Audit the inherited sites. The framework-era builds of 2014-2016 deserve a script-cost review against real-device timings. Practitioner reports this year describe double-digit abandonment improvements available from splitting and deferral alone. No rebuild required.

The year’s single argument

As 2017 closes, the year reads as a single argument assembled from independent directions. The browser vendors priced tracking, in September. The regulators priced data hoarding, in June. The platforms priced interstitials and insecurity, the January label, the year’s search enforcement. And now the performance community has priced the script itself, in milliseconds, on the hardware your actual visitors carry.

The common thread is the one we have pulled since our first year. Everything you ship has a cost. The cost lands on someone. The era of shipping it unmeasured is ending, surface by surface.

The budget question for 2018 planning is therefore not whether your organization can afford performance work. It is whether your architecture is charging your least-resourced visitors an unexamined tax, and what it would cost you, usually a build-config change and a habit, to stop.

Weigh the script. Test on the phone your visitors own, not the one your developers do. And let the framework debates of 2018 begin from Osmani’s number, because every argument that ignores it is being conducted on a MacBook, and the users we serve do not get a vote in those rooms unless someone brings the timings.