Check out myAngular article series with live demos and Facebook group Angular - Advanced Topics

Creating a Treeview in Svelte

Torgeir "Tor" Helgevold
- JavaScript Developer and Blogger
Published: Wed Nov 30 2016

In the following post I will show how to create a treeview using Svelte. I will also compile the treeview with the closure compiler (ADVANCED_OPTIMIZATION).

I randomly heard about Svelte on Twitter. The concept behind Svelte seemed pretty interesting, so I decided to give it a try.

As always I evaluate new frameworks by building a treeview. This is of course no exception, so get ready for another addition to my already large forest of JavaScript treeviews.

The idea behind Svelte is pretty cool. Instead of shipping a framework with a runtime, the idea is to provide a compiler that will output executable JavaScript.

This is in some ways similar to Ahead of Time compilation in Angular, but one major difference is that you don't have to ship any framework bits with your application.

Instead the compiler will generate executable JavaScript based on your application code. The generated code is pure vanilla JavaScript, which is great since no framework bloat is added.

The compiler ships with a CLI that can be installed by running

npm install -g svelte-cli

One interesting thing about Svelte is that you write your application code in an html template. The compiler will then convert the template to regular JavaScript.

In the html file you define your component from a mix of html and JavaScript. I personally try to limit the amount of JavaScript in the html file. Instead I prefer to move my logic to external modules that can be imported in the html file.

Below is the template for my treeview:

<ul> {{#each locations as loc}} <li> {{}} <:Self locations='{{loc.locations}}' /> </li> {{/each}} </ul> <script> export default { }; </script>

In all my previous treeview implementations I've used a recursive template with a tag based self reference.

Svelte's approach to creating recursive templates is using a :Self tag.

:Self effectively allows you to create a template where the component calls itself.

Next I am including the treeview component in my main App component:

<div> <h4>Treeview</h4> <Treeview locations='{{locations}}'></Treeview> </div> <script> import Treeview from './treeview/treeview'; import { LocationService } from './treeview/location-service'; let locationService = new LocationService(); let locations = locationService.getLocations(); export default { data () { return { locations: locations } }, components: { Treeview } }; </script>

Finally I have wired up the App component.

import App from './app'; var app = new App({ target: document.querySelector( 'main' ) });

All I am doing here is make an instance of the App component and add it to the page.

To do the bundling I am using Rollup since it makes it very easy to create optimized application bundles.

In addition to regular application bundling I also wanted to see how compatible Svelte is with the closure compiler. Specifically I was interested in the closure compiler's ADVANCED_OPTIMIZATION.

Typically ADVANCED_OPTIMIZATION works poorly with template bindings in most frameworks. The reason is that closure compiler will aggressively shorten property names in JavaScript code, but the template expressions still refer to the original property names. The challenge is that closure compiler can't trace the properties back to the templates, so we generally get runtime errors due to renamed properties.

However, here is good news if you are using Svelte!

Svelte seems to fare much better with the closure compiler since it doesn't follow a pattern of separation between html and javascript. Instead everything is compiled down to regular JavaScript. This means the closure compiler's shortening of property names will be applied to both binding expressions and bound objects by default. No more naming mismatches between expressions and objects!

The fact that there is no runtime is also good for closure since you don't have to worry about the runtime being incompatible with closure, which is likely if it was not written with the closure compiler in mind.

Below is my Rollup config with the closure compiler integrated via Rollup plugin. I am integrating with the JavaScript version of closure.

import closure from 'rollup-plugin-closure-compiler-js'; export default { entry: 'src/main.js', dest: 'dist/build.js', format: 'iife', moduleName: 'treeview', plugins: [ closure({ languageIn: 'ECMASCRIPT6', languageOut: 'ECMASCRIPT5', compilationLevel: 'ADVANCED', warningLevel: 'DEFAULT' }) ] }

Obviously this is just a simple implementation and I have only scratched the surface of Svelte.

I am definitely very inexperienced with Svelte, but I already see a lot of merit to the idea behind the framework. I particularly love how well it works with the closure compiler.

I have put my code on Github if you are interested. Here is also a simple demo of my treeview impementaton.

As you can tell from the demo, my closure compiled treeview is only 2.8kb :-)

If you liked this article, share it with your friends on social media:

We also have a new Facebook group about advanced Angular topics.

I invite you to follow me on twitter