惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
T
Tenable Blog
Webroot Blog
Webroot Blog
L
Lohrmann on Cybersecurity
S
Securelist
S
Schneier on Security
NISL@THU
NISL@THU
Know Your Adversary
Know Your Adversary
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
C
CXSECURITY Database RSS Feed - CXSecurity.com
O
OpenAI News
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
S
Secure Thoughts
Application and Cybersecurity Blog
Application and Cybersecurity Blog
P
Privacy International News Feed
H
Hacker News: Front Page
N
Netflix TechBlog - Medium
M
MIT News - Artificial intelligence
博客园 - Franky
PCI Perspectives
PCI Perspectives
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Azure Blog
Microsoft Azure Blog
MongoDB | Blog
MongoDB | Blog
L
LangChain Blog
P
Proofpoint News Feed
S
Security Affairs
WordPress大学
WordPress大学
The Last Watchdog
The Last Watchdog
S
SegmentFault 最新的问题
小众软件
小众软件
F
Full Disclosure
博客园 - 叶小钗
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
The Blog of Author Tim Ferriss
Simon Willison's Weblog
Simon Willison's Weblog
P
Palo Alto Networks Blog
Security Latest
Security Latest
P
Proofpoint News Feed
月光博客
月光博客
T
Tailwind CSS Blog
Scott Helme
Scott Helme
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
T
Threat Research - Cisco Blogs
Help Net Security
Help Net Security
Project Zero
Project Zero

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Why We Render Everything in the Browser
Vivian Voss · 2026-05-10 · via DEV Community

Editorial illustration in hand-drawn ink style. On the left, a quote in serif type:

On Second Thought — Episode 07

Open any modern site. The utility provider's login, the restaurant booking, the parcel tracker. The laptop fan spins up to render text. The median page in 2025 ships 697 KB of JavaScript before a single character of content is visible. The browser, meanwhile, is asked to do the work that a server in 1996 already did, and to do it on a battery, on a metered connection, on a chassis warm enough to taste.

This is the post about that.

The Axiom

The reflex is universal. Every new web project begins with a frontend framework, a build pipeline, a bundler, a hydration strategy. The server, where the data already lives, has been reduced to a JSON tap. Rendering is the browser's problem now. Nobody quite remembers when this was decided.

It was not decided in any single meeting, or with any single argument. It compounded. Each project chose the framework because the previous project had; each developer learned the framework because that was the job posting. By the time anyone thought to question the assumption, the assumption had become the architecture, the curriculum, the conference circuit, the hiring funnel. Reaching for a server-rendered page in 2026 feels, to many engineers, like reaching for COBOL: technically defensible, professionally suspect.

That feeling is the topic.

The Origin

AJAX, 2005. Jesse James Garrett gave the pattern its name in his now-famous essay, describing how Gmail and Google Maps used asynchronous XMLHttpRequest to update parts of a page without a full reload. The technique was real, the gain was real, the use cases were narrow: applications in which a user lived for hours and interacted hundreds of times per session.

Backbone arrived in 2010 (Jeremy Ashkenas), Angular the same year (Misko Hevery, Adam Abrons), Ember in 2011, React in 2013 (Jordan Walke at Facebook). Each was a sincere response to a real problem: the desktop-application-in-a-browser, an experience that genuinely required client-side state management, view diffing, and offline tolerance. Gmail, Google Maps, Figma. Real applications, real argument.

The pattern then spread to every site that was not Gmail. Marketing pages, brochure sites, restaurant menus, government forms, regional rail booking, doctor's-surgery appointments. The argument that justified Gmail's architecture was never re-examined for the brochure, because re-examining the argument required a different skill set than building the brochure had required. By 2018, the SPA was treated as the default architecture of the web. By 2020, "I'll just spin up a Next.js project" was the unexamined first move for static content.

The shift was not theoretical; it was a hiring problem. A generation of frontend developers learned React in a bootcamp, then a job, then another job, and never learned a server language. The job market rewarded React on the CV; nobody was hiring for "knows what a session cookie is". TypeScript arrived as the local repair: a build-time wrapper meant to compensate for the deficiencies of the language the team had chosen because it was the only one anyone knew. The fix was added before the question was asked.

Episode 02 of this series left this question open: what happens when a profession trains on tools instead of foundations? This is its first practical consequence. The architecture follows the curriculum. The web becomes a thing that requires a 700 KB bundle to display a heading because the people who build it cannot, professionally, build it any other way.

The Cost

Median page weight in 2025, per the HTTP Archive Web Almanac: 697 KB of JavaScript on home pages, 632 KB on inner pages. The 90th percentile: 1,979 KB on home pages. The 10th percentile: 87 KB. The lower bound is, demonstrably, achievable. Most teams are nowhere near it.

The first cost is paid downstream, on the device, in electricity. On a mid-range Android over 4G, those numbers translate into eight seconds to Time to Interactive on a representative page, and more on a slow connection. Mobile data, in EU roaming, is not free. The cost that is harder to name on an invoice is the wattage. Each page load now drives the client CPU and GPU as if it were running a workload, not displaying text. Frameworks parse, hydrate, diff, reconcile, and re-render; the silicon spins; the fan, on a quiet office, becomes audible. Battery sensors register the drain in measurable single-digit percentages per twenty minutes of casual reading. The user is, in literal terms, paying for the rendering with their own battery and their own data plan, on hardware they bought, for content the server already had. There is no return on the spending, because the page was a printed leaflet at heart.

Multiplied across a billion daily web sessions, the unnecessary draw climbs into terawatt-hours per year, a figure documented in the Sustainable Web Manifesto's reference dataset and the W3C Web Sustainability Guidelines. The electricity is only the easiest column to count. Beneath it sits the hardware that consumed it: the lithium for the laptop battery that drains faster, the rare earths in the radio that keeps the data flowing, the cobalt in the datacentre's storage, the copper in the racks, the cooling water that the racks then warm. Megatons of natural resources, quietly enlisted on the side of a marketing page that did not need any of them. There is, here, an inconvenient observation. The same conferences that run sustainability tracks ship frameworks of half a megabyte per visit; the same engineer who publishes a sustainability-conscious LinkedIn post will, on Monday morning, push a pull request that adds 200 KB of JavaScript to a marketing page. The contradiction holds itself politely apart, and is, on close inspection, untenable. One cannot ship the bundle and lecture on pollution in the same conversation.

Accessibility collapses without JavaScript. Screen readers must wait for the framework to construct the DOM before they can announce anything; if the JavaScript fails to load, the page is empty. Crawlers must execute the JavaScript to index the content, which means search-engine indexing has become a secondary industry of headless browsers, and the cost of that industry is borne by datacentres no one sees on the invoice.

The browser tab is now the heaviest process on the average laptop. Most of what it computes is layout for content that the server already had, in a format the server could already serve. The Senior Engineer's day, when she debugs why the search bar takes eight hundred milliseconds to respond, walks through a stack of seven layers between the user and the database, finds at the bottom a query that wants for an index, and notes that the layer above it could have been a single server-rendered HTML response. The HTML response would have been forty kilobytes. The current implementation is six hundred and ninety-seven.

Then, having pacified the client, the same language was asked to manage the server. Node.js, originally an event-driven runtime for I/O-bound real-time workloads (which it does competently), was deployed in whole cohorts of new projects to do work that PHP, Ruby, Python and Go had been doing efficiently for decades. The reason was not technical. Node.js is not faster than Go (it is not), not smaller than Rust (it is not), not safer than Python (it is not). It was deployed because the team knew only the one language and could not, professionally, choose another. The build pipeline that wraps the language to compensate for its deficiencies on the client was duplicated on the server. Every architectural decision compounds. The bill is paid twice: once at the client, once at the rack. The rack pays in CPU cycles and in megawatt-hours; the client pays in milliseconds and in power. Neither user signed up for either.

Around all of it, the dependency cloud, and a quietly inconvenient truth at the bottom of it. JavaScript was shipped, in 1995, without a standard library worthy of the name; npm appeared in 2010 to fill the vacuum, and the vacuum filled, in turn, with hundreds of transitive packages from strangers, then thousands. It is, by some distance, the public software repository most reliably compromised in routine use. The 2024 Sonatype State of the Software Supply Chain report counted more than half a million malicious packages across public registries; npm carried the bulk of them. left-pad in 2016, event-stream in 2018, ua-parser-js in 2021, and the September 2025 incident in which eighteen packages with 2.6 billion weekly downloads were compromised in a single coordinated attack, are the headlines a Senior Engineer can name. The thousand smaller incidents are the ones nobody tracks.

The maintenance of the dependency cloud is then outsourced to a second cloud, the supervisory cloud: Dependabot, Snyk, Renovate, GitHub Advanced Security, the long tail of supply-chain-monitoring SaaS. Each one runs on servers, consumes electricity, opens pull requests for other servers to review, sends Slack notifications for engineers to triage, and produces dashboards for managers to look at. The supervisory cloud has, in turn, its own dependencies, its own build pipelines, its own pricing tiers. The wrappers wrap the wrappers. One does, at some point, lose count of the clouds.

The question that closes this section is the obvious one, and the one that the industry has spent fifteen years pretending not to ask. If the answer to a security failure in your dependencies is to add another vendor, another runtime, another monitoring service, and another bill, you have not solved the problem. You have rented a louder version of it. None of this would exist in a language whose standard library could carry the weight of a real application. Rust, Go, Python, Ruby, even PHP all ship with first-party batteries that npm has spent a decade and a half badly approximating, with the supply chain to match. The vacuum was self-inflicted, in the choice of the language at the bottom of the stack.

The Question

The proofs are not theoretical. They are in production, and they have been for years.

Wikipedia: 60 million articles, MediaWiki on PHP 8.3 with MySQL/MariaDB and an aggressive caching layer, server-rendered, faster on a budget Android over a coffee-shop wireless than most marketing single-page applications. The Wikimedia infrastructure handles hundreds of thousands of views per second, and it does so by caching server-rendered HTML, not by shipping a runtime to the client.

GOV.UK: 67 million citizens, designed by the Government Digital Service from 2012 onward, with progressive enhancement mandated by the GOV.UK service manual for every government service. HTML first, CSS second, JavaScript only as enhancement. The principle is documented, the policy is enforced, the result is a public-sector portal that opens on a Nokia from 2007 and an iPhone from 2024 alike. It is not glamorous. It is, demonstrably, robust.

Hacker News: server-rendered, written in Arc (a Common Lisp dialect) by Paul Graham and Robert Morris from 2007, opens before the loading spinner of any modern dashboard. The site is famously austere, deliberately so. It is also, after eighteen years, still online and still fast.

HEY and Basecamp, the products of 37signals: server-rendered with Hotwire (a Ruby on Rails extension that DHH and his team published in 2020), fully interactive, no client-side framework. The interactive elements arrive over the wire as HTML fragments, swapped into place by a tiny client-side library. The model is older than the SPA, applied to a modern email client, and it works.

HTMX, by Carson Gross at Big Sky Software (2020): 14 KB minified, around 5 KB gzipped, doing what JavaScript frameworks an order of magnitude larger claim to do. Carson Gross's argument is the simplest version of the case in this post: most of what we want a SPA for can be done with attributes on plain HTML, and the rest can wait.

Netflix's logged-out homepage, 2017: the team removed client-side React entirely from the landing page and rebuilt the language switcher in fewer than 300 lines of vanilla JavaScript. Time to Interactive improved by more than 50%, and Jake Archibald's writeup of the change remains one of the canonical case studies for the cost of unnecessary client-side rendering. Netflix did not abandon React; it kept it server-side, where the value is, and removed it from the client, where the cost is.

Cloudflare Pingora, 2022: Cloudflare published a blog post describing how their nginx-and-Lua proxy, after years of scaling, had hit the limits of its architecture, and was replaced with a Rust-based proxy of their own design. The new proxy serves over a trillion requests per day, with about 70% less CPU and 67% less memory than the old one. The lesson is not "Rust beats Lua" in any tribal sense; it is "a small, focused, efficient server kernel beats a tower of accreted layers, and the savings show up on the electricity bill the same week".

A word on the standard objection, before it appears. The reflexive defence of the SPA is "but we need reactivity". Reactivity has not been an obstacle to server-rendered architectures for at least a decade. Hotwire's Turbo Streams, HTMX's hx-swap and hx-trigger attributes, Phoenix LiveView's WebSocket-driven HTML diffs, Laravel Livewire, ASP.NET Blazor Server: all of them deliver partial updates, optimistic UI, two-way binding, even real-time collaborative behaviour, by sending small HTML fragments over the wire instead of shipping a runtime to interpret JSON. The total client-side weight, in every one of these patterns, is in single-digit kilobytes. Reactivity is a solved problem. The framework industry sells it back as if it were not.

Each of these stacks chose a different server language: PHP for MediaWiki, Ruby for Rails and Hotwire, Common Lisp for Hacker News, Python for Django sites in the same family, Go for many modern static-content tools, Rust for Pingora and the modern wave. On a FreeBSD server, any of these is a single pkg install away, with one service manager and one configuration tree. The language is the smaller question; what matters is that the rendering happens on the server, where the data and the session already live, in a runtime that does not have to be re-shipped to every visitor.

Rust is, for the modern build, particularly hard to argue against. The combination of a single static binary, no garbage collector, native concurrency, and the kind of compile-time safety that removes whole classes of runtime error is, today, the easiest case to make. But the case is not "use Rust". The case is "render where the data is".

The larger question is this. What if rendering happened where the data already lived, and the data did not need to be guarded from a thousand strangers we never invited into the project? Most of the cost of the modern web, paid in milliseconds, in power, in megabytes, in accessibility, in indexability, in carbon, in security incidents, in supervisory SaaS, would simply not exist. The fastest bundle is the one that is never shipped. The safest dependency is the one that was never installed.

Read the full article on vivianvoss.net →


By Vivian Voss — System Architect & Software Developer. Follow me on LinkedIn for daily technical writing.