{"id":"s6d80yfccq5fjjs","title":"Why simplicity wins and vanilla JavaScript still reigns supreme","slug":"why-simplicity-wins-and-vanilla-javascript-still-reigns-supreme","summary":"Vanilla JavaScript still earns its place when the job is small and speed matters. Not every interaction needs a framework, build system, and dependency chain.","imageUrl":"https://briancrabtree.me/images/journal-why-simplicity-wins-and-vanilla-javascript-still-reigns-supreme.webp","category":"Web Development","date":"12/03/2025","featured":true,"likes":46,"author":"Brian Crabtree","content":"<h2>The Architecture of Sanity</h2>\n\n<p>Building a robust application requires more than just npm installing the top five packages from a \"Best of 2024\" list and stitching them together with hope and prayers. It demands a rigorous understanding of how the browser paints pixels and handles memory. When you choose a framework, you are buying into a philosophy that dictates your rendering pipeline, often inserting a massive abstraction layer between your logic and the user. By opting for Vanilla JavaScript, you are choosing a direct line to the metal. You strip away the virtual DOM diffing engines, the synthetic event systems, and the complex lifecycle hooks that burn CPU cycles trying to figure out if a variable changed. This isn't just about raw speed, though the performance gains are often significant; it is about predictability. When you own the architecture, you understand exactly why a reflow happened. You know exactly why memory usage spiked. You are not debugging a black box; you are debugging your own code.</p>\n\n<p>This approach naturally enforces a progressive enhancement strategy that seems to have been forgotten in the era of single-page applications. When you work close to the browser, you tend to build things that work because of the platform, not in spite of it. We can deliver core functionality through semantic HTML and CSS, layering JavaScript on top solely to improve interactivity rather than to generate the entire interface from a JSON blob. This ensures that the application remains usable on low-bandwidth connections or on low-powered devices, which is a non-negotiable requirement for any piece of software claiming to be accessible. We stop treating the user's CPU as an infinite resource and start respecting the constraints of the medium. We build systems that degrade gracefully rather than crashing white screens the moment a script fails to load.</p>\n\n<p>Furthermore, the shift toward micro-frontends and distributed architectures makes the case for native standards even stronger. In a polyglot environment where different teams might be tempted to use different stacks, Vanilla JavaScript—particularly when leveraged through Web Components—becomes the universal language. It allows us to create agnostic components that do not carry the baggage of a specific framework runtime. We can drop a native module into a React application, an Angular dashboard, or a static HTML page without worrying about hydration mismatches or version conflicts. This interoperability drastically reduces the technical debt that accumulates when you try to bridge five different versions of a framework across an enterprise ecosystem. It simplifies long-term maintenance because the browser standards are backward compatible in a way that open-source libraries never will be.</p>\n\n<h2>Executing with Precision</h2>\n\n<p>Implementing solutions without a safety net demands discipline, but it yields a caliber of engineer who truly understands their craft. We need to dispel the myth that direct DOM manipulation is inherently messy or slow. That was true in 2008; it is not true today. The native APIs available to us now are ergonomic and incredibly performant. When we bypass the framework's generalized rendering cycle, we gain granular control over exactly when and how the interface updates. We can perform surgical strikes on the DOM, updating only the specific text node that changed, rather than re-rendering a whole component tree. We can utilize `requestAnimationFrame` to orchestrate animations that lock perfectly to the monitor's refresh rate, and we can use `IntersectionObserver` to handle lazy loading without dragging in a third-party library. These are tools that allow us to reduce Time to Interactive and First Input Delay metrics, not by tweaking a config file, but by fundamentally writing better code.</p>\n\n<p>Security and dependency management also benefit from this austere approach. Every external package you add to your `package.json` is a potential vector for a supply chain attack. We have seen it happen repeatedly, where a benign utility library is hijacked to inject malicious code into thousands of applications. An architecture built on Vanilla JavaScript intrinsically possesses a smaller attack surface. We are not pulling in a dependency tree that looks like a fractal; we are writing the code we need, and nothing more. This pragmatic reduction is a massive win for maintainability. When you open a project five years from now, you won't be greeted by a screen full of deprecated warnings and broken peer dependencies. You will see standard JavaScript that the browser still understands perfectly.</p>\n\n<h2>The Long Game</h2>\n\n<p>The argument often levied against this approach is that it takes too long to write \"boilerplate\" code that frameworks provide out of the box. I reject that premise. The time you \"save\" initially with a framework is almost always paid back with interest during the maintenance phase. You spend hours fighting the framework's opinion on state management, or debugging why a hook is firing twice, or rewriting the entire frontend because the framework authors decided to change the API in version 3.0. Writing Vanilla JavaScript is an investment in stability. The code you write today using ES6 modules and standard browser APIs will run a decade from now. Can you say the same for your current framework of choice?</p>\n\n<p>We need to stop hiring developers who are experts in a specific tool and start hiring engineers who are experts in the web platform. The frameworks will come and go. The patterns will shift. But the fundamental reality of the DOM, the event loop, and the network stack remains. By stripping away the bloat and focusing on the native capabilities of the browser, we build software that is faster, more secure, and infinitely more maintainable. It is time to stop hiding behind abstractions and start acting like architects. For a related angle I keep coming back to, see <a href=\"/journal/when-frameworks-are-worth-it/\">When Frameworks Are Worth It: My Decision Framework</a>.</p>","tags":["Next.js App Router","TypeScript Generics","Kubernetes Helm Charts","GraphQL Subscriptions","AWS Lambda Cold Starts"],"views":115}