Tiny JS frameworks: Preact and Svelte

Chris Davies
4 min readDec 2, 2016

--

This week, I found out about Svelte, a teensy front-end UI framework. I’m a fan of Preact, and I wondered how big a real application with Svelte would be compared to Preact.

Short answer: a simple CRU (no D) app for creating, listing, updating a users list, complete with client-side routing using rlite-router and JS-manipulated CSS weighs in at:

  • Preact 6.2KB (min + gzip)
  • Svelte 4.8KB (min + gzip)

Without JS-based styling (e.g. with external CSS), the Svelte app came in at exactly 4KB.

Pretty sweet. That’s an entire application with front-end routing, in a much smaller than react-router alone.

How it grows

Svelte is different than any other UI framework I’ve seen, in that it precompiles down to basic DOM manipulations. Not to a virtualized abstraction over the DOM, but to direct, plain basic JS.

What this means, however, is that a Svelte application’s growth characteristics will be different (e.g. it will grow faster) than the characteristics of a typical framework.

Just how fast does a Svelte application’s final bundle size grow? To answer this, I built a dummy app that allows you to create a user and list all users. I built it in Preact and in Svelte. Then, I measured the bundle size of each. Next, I added the “Edit User” feature, and compared the bundle size of each.

Here’s what I found.

Before “Edit User”

  • Preact: 14.9KB minified, 5.9KB Gzipped
  • Svelte: 16.5KB minified, 4.0KB Gzipped

After implementing “Edit User”

  • Preact: 15.8KB minified, 6.2KB Gzipped
  • Svelte: 23KB minified, 4.8KB Gzipped

So, Svelte’s rate of growth is faster than Preact’s.

Svelte’s unzipped size grew 1.39x. It’s min+gzip grew 1.2x.
Preact’s unzipped size grew 1.06x. It’s min+gzip grew 1.05x.

For an app of real-world complexity, the final Svelte output would be bigger than the final Preact output. I suspect a real-world Svelte app would still be significantly smaller than the equivalent React app’s size (React + Redux + React-Router + ImmutableJS, etc).

Fixing Svelte’s growth characteristics

I did a bit of tinkering with Svelte’s output. By changing all of Svelte’s DOM calls to use helper functions, the bundle size (gzipped and ungzipped alike) shrank by 20%.

For example, I added these (and many other) helpers.

var doc = typeof document === ‘undefined’ ? undefined : document;
function createTextNode(txt) {
return doc.createTextNode(txt);
}

Every un-minifiable call to document.createTextNode(‘hello’) became createTextnode(‘hello’). Which, when minified became this: n(‘hello’).

So, I have no doubt that the smart fellers developing Svelte will be able to tackle its growth characteristics.

Aesthetics and being in a bind

The Svelte development experience was really quite nice.

I love JSX, so I didn’t expect to like Svelte’s templating system. It’s more like Angular 1.x than like React… And I really didn’t like working with Angular 1.x. I didn’t like writing vanilla HTML with custom/proprietary additions.

But somehow, I did like Svelte. In fact, I liked it a whole lot more than JSX. I like the first-class support for CSS. I liked the breakout of the JS from the HTML. I liked that the whole thing could be written in a .html file so my editor intelligently helped me with everything.

In today’s front-end world, two-way binding is a cardinal sin. Svelte is unapologetic about its two-way binding. And that’s just fine with me. Svelte works fine with unidirectional dataflow, but there are also cases where two-way binding greatly simplifies things. With Svelte, you can have both.

Svelte in production?

It’s currently (December 2016) a bit too early for me to fully recommend it for production, though. It’d probably work out just fine. But, there were times when it would just silently fail. No console error, just a failure to render properly.

The two primary missing pieces, as far as I’m concerned are these:

Svelte doesn’t support the React {children} feature, though it’s high on the todo list:

https://github.com/sveltejs/svelte/issues/5

Svelte doesn’t use keys to optimize re-rendering of lists, though it’s on the todo list, too:

https://github.com/sveltejs/svelte/issues/81

One other nitpick, is how events bubble or don’t bubble. Svelte allows components to communicate via events. This is natural, and fits nicely into a DOM-based UI. The problem is, as far as I can tell, custom events don’t bubble up past the parent component. So if you’ve got a nested hierarchy and want to handle, say, the “save” event up at the root level, you’ve got to explicitly pass it up from the child through all intermediate components. I think it would be nice if the events bubbled up automatically, but could be stopped via e.stopPropagation() or something similar.

Conclusions

Preact is solid, tiny, and production ready. Svelte is solid, tiny, and *almost* production ready. Both are great. Both are pretty different. Preact’s big strength is how nicely it fits into the existing, broad React mindshare.

I’ll end with a note about JS fatigue. I love that Preact, Svelte, Mithril, and friends exist. I’m glad that we aren’t all content with frameworks that require ~150KB just to get a hello world up and running. I’m glad people are pushing back and working hard to reduce bloat. To Rich Harris, Jason Miller, Leo Horie and all, *cheers* and good luck.

--

--