Taking Glimmer for a ride

Glimmer is a JavaScript library to create user interfaces for the web that’s been launched last week at EmberConf. The big differentiating factor is that it’s the same engine that’s used in the Ember framework. While Ember includes a router and a model layer, Glimmer just defines a way to update the UI when the data changes.

As one example in my React book is a word counter, I tested Glimmer by building word counters with other frameworks. You can find the code on Github.

I have followed the official guide to build a Glimmer application from scratch. An alternative is to build the Glimmer application as a web component. In both cases, you need the ember-cli command-line tool to generate the project.

It’s not apparent immediately from the examples but you must use TypeScript. I say it’s not immediately apparent because the examples on the website do not include any type annotations and my word counter also worked perfectly without type annotations.

Among others, ember-cli two files named index.ts and main.ts. Here’s index.ts:

import App from './main';
import { ComponentManager, setPropertyDidChange } from '@glimmer/component';

const app = new App();
const containerElement = document.getElementById('app');

setPropertyDidChange(() => {
  app.scheduleRerender();
});

app.registerInitializer({
  initialize(registry) {
    registry.register(`component-manager:/${app.rootName}/component-managers/main`, ComponentManager)
  }
});

app.boot();

app.renderComponent('glimmer-wordcounter', containerElement, null);

I am a little surprise that this amount of setup is required to start an app, but maybe it is something you never have to touch so you can happily forget about it.

The first component I created was a counter, which just displays a number. You generate new components with ember-cli:

ember g glimmer-component glimmer-counter

To avoid name collisions, each component name must contain a dash. That’s a bit annoying initially. As in React and Vue.js, you pass data to a component from its parent, so I wanted the counter to just display a count from the parent component (make the counter a presentational component, as the React community calls them).

The counter component essentially defines a visual style for its content: that would be the ideal use case for libraries like styletron-react or glamorous that create components just from style definitions. There’s no such solution for Glimmer and I could not find a mention of any styling integration like in Vue.js either. glimmer-cli does compile SASS files to CSS, though.

A Glimmer component is made of two files: a TypeScript file that contains a class and a template. For the counter, I found out all I needed to do was to fill in the template and I could leave the TypeScript file as just an empty class.

In templates, Glimmer distinguishes data that’s stored on the component class from data that’s passed from the parent (what React calls props) by prefixing props with @. So my counter ended up looking like this:

<div>Count: {{@count}}</div>

I can imagine @ could become a pain to remove it if you want to change where you store the data in the component hierarchy. On the other hand, with experience, you’ll hardly ever turn your presentational components into smart components, so it should not become too much of an issue.

All frontend frameworks essentially try to solve the problem of syncing data with the UI. Glimmer has a relatively Vue-flavoured solution. By default, Glimmer assumes all data is immutable. When you want to update some information, you annotate the variable with @tracked. For example, the word counter text:

@tracked
text = 'Hi';

If you assign a new value to text, Glimmer updates the view. This reminds me of Java JPA annotations that map classes to database tables: in both cases a decoration at declaration point triggers side-effects at usage. I am not a fan because it can leave you scratching your head at where exactly a change was triggered, since everything looks like a normal assignment.

If you’ve got some data that depends on tracked variables, like the word count depends on the text, you define it in a getter method and annotate it with @tracked:

@tracked('text')
get wordCount() {
}

Then, in the template, pass the data to the component that needs it and Glimmer also updates it automatically:

<glimmer-counter @count="{{wordCount}}"/>

If you set up an event handler in the template to update some @tracked data, you must preface the event handler name with action:

 <glimmer-editor @text="{{text}}" onInput={{action updateText}}

And that’s basically it. Glimmer has a quite simple API.

Now, my impressions. Concerning TypeScript, I have the same perplexity as with Angular: what good does it do to use a statically typed language if you then use templates that are not type checked? With Glimmer, you can leave most properties undefined and TypeScript does not complain at all. I do not think template properties should be optional by default. Undefined should fail because they point to a programmer error.

Concerning the class/template split, I like that Glimmer avoids the problem with Angular and Vue that every time you want to use a component, you need to both import the component JavaScript module and register in some framework-specific way to be able to use the component in templates. Glimmer requires no framework-specific component registration. I presume Glimmer adds the required components to templates based on the folder structure.

Glimmer shares the concept of tracked and computed properties with Vue (the data and computed fields on a Vue component) and a similar minimalist feel, but obviously, given its age, lacks the community. So while vue-router and vuex exist, there’s no complementary libraries of that kind for Glimmer yet.

The ability to integrate with its parent framework Ember would give Glimmer a boost, but at the time of writing, the team is still working on this and no out-of-the-box solution exists to drop a Glimmer component into an Ember app, except as a web component.

Glimmer is very fast to pick up if you’ve dabbled in front-end JavaScript before, but Ember integration needs to be the killer app, otherwise I see few developers picking Glimmer over more established incumbents.