Articles

Why not build frontend frameworks on raw HTML, CSS or JS?

It's possible: No endless dependencies, no dev environment setup, no build step, no Web Components required, minimal boilerplate, minimal lock-in.

Raw HTML, CSS and JS have everything needed and are web standards, unlike custom syntaxes.

Some of the benefits include:

  • Bundle size proportional to the logic.
  • Consistent hydration.
  • No unnecessary breaking changes.
  • Much less black-box reactivity.
  • Lower risk of supply chain attacks.
  • Native semantic accessibility.
  • SEO-friendly and better indexing.
  • No niches, transferable web standards learned.

This article is not: A call to switch your framework or dismiss other techniques—after all, today's custom syntaxes may be tomorrow's standards. It also doesn't ignore the massive challenges, serious business and enterprise needs, or the real value of today's tools or methods.

This article's perspective is shaped by this: Having written code close to the metal (XDP, shared memory, C), delved into low-level systems (protocol flows, RAM interactions, Go), focused on optimizing core operations and identifying high-performance algorithms (BM25, djb2, HNSW), and compared the performance of various runtimes (PHP, Lua, Node, Wasm, Rust)—I analyzed some modern frontend principles through the same lens.

From this viewpoint, to put it simply: What was mentioned in the first line (regarding what is possible) could be solved if most modern browsers or JavaScript engines updated to a recent ECMAScript specification with native TypeScript and backward compatibility support.
But the proprietary or custom syntaxes that have been invented are not standard JS or TS; they require transpilers, optimizers, compilers, bundlers, and so on (understanding their inner workings and mechanisms is indeed fascinating).

Proposition: There are several steps that can be bypassed—between the scripting language, the framework, development, bundling, the interpreter, and the end user—without requiring any updates to ES/TS specifications.

The focus will be on these key points:

  • Point 1: JavaScript/TypeScript as the scripting language that does the actual work and creates the upper framework.
  • Point 2: The framework, which helps avoid repetitive boilerplate, making the work with the scripting language easier and more efficient.
  • Point 3: Developing interrelated or independent components using the framework to further abstract logic, reduce repetitive code, and reuse processes.

Steps that can be bypassed between:

  • Context:
    For a framework to build dynamic, real-time, or interconnected frontends and UIs, it requires state, reactivity, components, routing, event handling, DOM manipulation, HTTP capabilities, and so on. To achieve this, ECMAScript and Web APIs already provide these features out of the box since ES5, ES6, and ES2016+.
  • Bypass:
    Advanced usage of native primitives, baseline widely available features/functions, and APIs, such as the following.
    • State & Reactivity:
      Implemented in Reactive (ES6+), using:
      Proxy, Object.defineProperty, Map, Set, WeakMap, ...
    • DOM, Events & Templating:
      Implemented in DOM, Events & Handlers (ES5, ES6+), using:
      MutationObserver, IntersectionObserver, document.querySelector, document.createTreeWalker, NodeFilter, HTMLTemplateElement, DocumentFragment, document.createComment, Node.prototype.cloneNode, addEventListener, window.getComputedStyle, ...
    • Routing & Navigation:
      Implemented in Routing (ES6+), using:
      history.pushState, history.replaceState, window.onpopstate, URL, window.location, structuredClone, ...
    • Asynchronous & Orchestration:
      Implemented in HTTP & Components (ES3, ES6+), using:
      queueMicrotask, Promise, XMLHttpRequest, fetch, Blob, URL.createObjectURL, URL.revokeObjectURL, ...

Coming soon...