Some First Impressions of GlimmerJS

Initially, when I started looking at Glimmer I wanted to write a post about it, but I didn’t want to write a how to type post, I wanted to look more at why someone might choose Glimmer and what benefits it has to offer. However, I think given how new Glimmer is (as a stand alone tool), there is still a market for “getting started” type posts. So, the hope is, as I create a Glimmer component in this post, along the way, we might see some of what makes Glimmer really cool.

First things first, what is Glimmer? It is a JavaScript component library that was extracted from Ember’s render library. It is very fast, very small, and is built in TypeScript. You can use Glimmer anywhere that you might want a web component. It is important to note that Glimmer is not Ember. It was extracted from Ember’s rendering engine, but where Ember is a full, ambitious, opinionated JavaScript framework, Glimmer is a component library. It is focused on the view layer only - kinda like React, or Vue. Because of this approach, you can adopt Glimmer incrementally, or even just dip your toe in to see how it feels without committing to the all in of an Ember/Angular type framework.

Glimmer uses a two file approach for creating components. You have a template file (.hbs) and a script file (.ts). The template language is handlebars and the script language is TypeScript. The strength of this approach is that both TypeScript and Handlebars are supersets of the base languages. To get started writing TypeScript, you don’t need to know TypeScript, just know JavaScript. To start writing Handlebars you only need to know HTML. You can fill in the details of TS and HBS as you need the features that they offer. I will look at the file structure shortly and you will get an idea of how this plays out, but my takeaway is that the barrier to entry for getting started writing a Glimmer component is very low. Do you know JavaScript and HTML? You are good to go.

There are plenty more cool things to discuss. However, there are also some challenges to getting started with Glimmer. Most of the challenges stem from the newness of the library as a stand-alone product. The documentation is still a work in progress and there are a few gotchas that you might encounter along the way. The two biggest documentation challenges that I have found are around building for and including a component in a production app and using async await. The first shortcoming is directly tied to a small technical hiccup: you have to load your Glimmer app’s JavaScript after the DOM has finished rendering. If you don’t you will see a somewhat unhelpful error (TypeError: Cannot read property 'insertBefore' of null) and since the documentation in this area is still a work in progress, you might start second guessing yourself (What did I do wrong!?!?). All you have to do is move the script tag that includes your JavaScript to the bottom of your HTML document or add defer to the script tag.

The one other challenge I encountered when getting started was in using async await. The documentation leads you to believe that all you have to do is use the Web Components option when creating your app and it will work. But there is actually a bit more setup involved. Having said that, all of the problems that I faced in getting started with Glimmer are problems of using a tool that is still in beta, and they were not at all insurmountable.

There are plenty of other benefits to Glimmer that we could discuss like the type safety of TypeScript or how Glimmer encourages developers to embrace the immutability pattern. But I really want to get into a simple example app, so let’s go.

If you have completed the Ember course here on DailyDrip, you know that in one series we created an Ember addon that displayed a list of the last 10 DailyDrip episodes for a given topic. I want to look at creating a new version of that using only Glimmer. Where our Ember addon had to be consumed by an Ember app, our Glimmer component can be dropped in any server rendered HTML document.

To get started we need to globally install the latest Ember CLI beta (as of this writing that is 2.14.0-beta.2).

yarn global add ember-cli@2.14.0-beta.2

After that installation completes you can create your new Glimmer app. Here we have a choice to make. When you use your Glimmer component in production, you can include it on your page in one of two ways. The default way is just as you would include any other view library, where you have a root element with a given id to which your component attaches itself. The other -- cooler -- way is to include it like a web component.

To start a new app that you will call the normal boring way you just type:

ember new daily-drip-feed -b @glimmer/blueprint

To create an app that we will be able to include like a web component we run the same command but add the --web-component flag. This is also necessary if you want to use async await in your code. After you build your app with the web components flag you can use the component like you would any web component <daily-drip-feed></daily-drip-feed>

EmberCLI provides us with a functioning development environment, but when our component is ready for production we will build it for production and the resulting javascript file will only be the super small glimmer library and our component.

After creating a new Glimmer app, if you cd into the new directory you should take a look at the project structure. If you look at src/ui/components you will see your new component’s directory. In my case, inside the daily-drip-feed component directory I have a component.ts and template.hbs file. If you ever need to generate new glimmer component you can create them in this components directory. You can also nest components if you know they will only be used as the child of another component. For my purposes this single, top-level component will be enough to accomplish my task. First, in the template.hbs I will add the markup that I need.

<h3>

  {{results.feed.title}}

</h3>

<h4>

  {{results.feed.description}}

</h4>

<ul>

  {{#each results.items key="@index" as |item|}}

    <li>

      <a href={{item.link}}>{{item.title}}</a>

    </li>

  {{/each}}

</ul>

The first thing to call out here is that the each helper requires a unique key for the items in the array. Just as I did here, you will generally use the index. The other thing to note is that we are only using component properties in our template. If we had a child template that we passed arguments into we would reference those arguments with an @ symbol (e.g. @results).

Finally, I will add the code to fetch the feed in the component.ts file:


import Component, {tracked} from "@glimmer/component";

export default class DailyDripFeed extends Component {

  @tracked results;

  constructor(options) {

    super(options);

    this.getFeed();

  };

  async getFeed(){

    let feed = await fetch('http://rss2json.com/api.json?rss_url=https%3A%2F%2Fwww.dailydrip.com%2Ftopics%2Fember%2Ffeed.rss');

    this.results = await feed.json();

  };

}

It occurred to me after I wrote this that it looks a lot like the screencast sample app on the glimmer home page. This was unintentional as I was just trying to port the old Ember Daily Drip Feed addon and this is the code that I ended up with. But I suppose this is a reasonable pattern: call an async function from the constructor that loads data for the component.

The first thing that is happening here is identifying results as a tracked property. A tracked property is a property that might change over the life of the component. Explicitly identifying tracked properties is how Glimmer knows what to update when data changes. If you do not identify a property as tracked, that property will be static.

Right after the tracked results property, we call the getFeed function in the component’s constructor. Our getFeed function is an async function (neat). Earlier I mentioned that there was a little setup to get this working. In this function I am using http://rss2json.com to convert DailyDrip’s rss feed to json and then I am setting the results that are returned to the results property on the component. Since this property is tracked, the template will be updated with the results.

EmberCLI handles Glimmer’s development environment. To start the development server from the project root you can type ember serve then navigate to http://localhost:4200. To build a Glimmer component for production all you need to do is type ember build --environment production. This command outputs a JavaScript file and a css file to the dist directory. Since the component I built here does not have any styles, all we need is the JavaScript file. Include it where you want to place the component, then call the component just as you would a web component: <daily-drip-feed />. Interestingly, you can’t currently pass arguments to top level components, but it appears that this limitation is being worked on. Presently, if you have a container element in your Glimmer component any attribute that you attach to your glimmer component is attached to that containing element. For instance, if I had a div surrounding my h3, h4, and ul and I had called my component like this: <daily-drip-feed topic="elm” /> the topic=”elm” would be attached to the container div. I could be wrong, but it seems that this is an iterative step to passing arguments to the component.

If you are so inclined, you can take a look at the component I created here.

That is all there is to getting started with Glimmer. If you want a bit more info on Glimmer, you can check out the Glimmer guides, the Glimmer API Docs, or the #glimmer channel in the Ember Community Slack.Thanks for reading!