DEV Community

Cover image for I built a 1.7kb VDOM-less framework, it went "viral", and Reddit banned me 🤣
Murillo Brandão
Murillo Brandão

Posted on

I built a 1.7kb VDOM-less framework, it went "viral", and Reddit banned me 🤣

Have you ever spent days crafting an open-source project, finally launched it, watched it get 20K views in just a few hours... and then had a robot permanently ban your account?

Well, that was my Tuesday.

I recently open-sourced Sigwork, a 1.7kb fine-grained reactive frontend framework. The launch on r/javascript exploded so fast that Reddit's automated spam filters panicked, assumed I was a bot farm, and shadowbanned my brand-new account. (I appealed, and thankfully, a human moderator unbanned me 🙌).

But the wild launch day isn't the point of this article. The real story is why I built a fully functional VDOM-less framework under 2kb.

The Problem: Frontend Bloat

Nowadays, web development has become incredibly complex. We have multiple build steps and massive frameworks packed with features we might never even use. It’s not uncommon to add React and a few libraries to a project and suddenly be pushing hundreds kbs of JavaScript to the client. Why did we normalize this? Is it really necessary?

The ergonomics of a modern frontend framework are amazing, they allow us to abstract the hard parts and focus on what actually matters. But at what cost?

I'm working on a zero-friction, local-first ecosystem of productivity tools. For the UI, I wanted the beautiful ergonomics of Vue and React (JSX, components, state management), but I refused to carry "Mount Everest" on my back for that. I also want it to load fast (inspired by the 14kb TCP trick article).

Enters Sigwork.

With that in mind, I started developing my own framework that met those requirements. I tried a bunch of different approaches and failed multiple times, always starting from scratch when I had a new idea.

The goal was to have signals as the base of the reactivity engine. And get as close as possible to the Vue ergonomics and features (hich is the framework I've used and liked the most over my years of development). All that while having the smallest possible size.

In the end, I finally got what I was looking for. I managed to condense the absolute core of modern reactivity into exactly 1.7kb. It has:

  • No VDOM: When a signal changes, it updates only the affected node or DOM attribute. The components runs exactly once.
  • JSX compatibility: It has an h(tag, {attrs}, ...children) function that renders nodes.
  • Buildless-ready: You can use it directly in the browser via CDN (you can pair with htm for better ergonomic).

And it has these main features:

  • Reactive primitives: signal, computed, reactive, effect, watch.
  • If (for conditional rendering with smart node caching).
  • For (with real DOM key-cached diffing).
  • Built-in components: <Transition> and <Component>.
  • provide/inject for context injection.
  • Lifecycle hooks: onMount/onUnmount.
  • Props, emits and slots.

I had to make some hard decisions about ergonomics and accept a few compromises to reach that size, alongside doing some heavy minification and code golfing (gzip is very counter-intuitive in terms of what code changes actually reduce the output, by the way).

If you are a fan of minimalist engineering, performance, or just want to check it out:

📖 Docs & Interactive Demos: framework.thatjust.works
🐙 GitHub Repository: thatjustworks/sigwork

If you find the code interesting or useful, dropping a ⭐️ on GitHub would mean a lot to me. I'd love to hear your thoughts on all this!

Top comments (2)

Collapse
 
trinhcuong-ast profile image
Kai Alder

The "buildless-ready" angle is what really caught my eye here. I've been working on a few internal tools recently where adding a build step felt like total overkill — just needed some reactive UI without the whole webpack/vite ceremony. Ended up rolling my own thing with vanilla JS and it was painful.

Curious about one thing though: how does the For component handle large lists? Like 1000+ items with frequent updates — does the key-cached diffing hold up perf-wise compared to something like Solid's approach? Would love to see some benchmarks if you've run any.

Also the Reddit ban story is hilarious. The irony of getting flagged as a bot for having actual humans engage with your work 😂

Collapse
 
murillobrand profile image
Murillo Brandão

I totally understand you! That's why being able to use it without a build step was a must.
The rendering engine has a clever algorithm to handle the most common operations on lists (insert, remove, move, and swapping 2 itens), so it does it efficiently, touching the DOM minimally. But it's not optimal for all cases (like a shuffle for example).

Solid is a hard one to beat, because it compiles the code it can perform more heavy optimizations. Also, size was my priority so I had to find a perfect balance between size and perfomance. I think the result is pretty good. I benchmarked it against js-framework-benchmark, in local results it was more performant than Vue, but less than Solid. Although, not too far behind. My PR was just merged, when they run the official tests I tell you.