DEV Community

Rajasegar Chandran
Rajasegar Chandran

Posted on

Building Glimmer apps with Snowpack

In this tutorial we are going to see how to use Snowpack to build glimmer.js apps. Typically we use ember-cli for building glimmer apps since Ember.js is the first JS framework to use glimmer under the hood for its rendering engine. This tutorial is an attempt to use a general purpose build tool which makes use of the ESM capabilities of modern JavaScript.

Before diving into the tutorial let's set the stage first. Let's have a brief introduction about the tools and technologies we are going to use.

Glimmer

Glimmer is one of the fastest DOM rendering engines, delivering exceptional performance for initial renders as well as updates. Architected like a virtual machine (VM), Glimmer compiles your templates into low-level code so it can run as fast as possible—without sacrificing ease of use. Glimmer VM powers the components in Ember.js

Snowpack

Snowpack is a modern frontend build tool for faster web development. It replaces heavier, more complex bundlers like webpack or Parcel in your development workflow.

Snowpack leverages JavaScript’s native module system (known as ESM) to create a first-of-its-kind build system that never builds the same file twice. Snowpack pushes changes instantly to the browser, saving you hours of development time traditionally spent waiting around for your bundler.

So now we have seen about the tools, let us start building our app.

Create snowpack app

The first step is to create a project boilerplate with create-snowpack-app. The easiest way to get started with Snowpack is via Create Snowpack App (CSA). CSA automatically initializes a starter application for you with a pre-configured, Snowpack-powered dev environment.

This is a lot like using ember-cli or create-react-app to bootstrap a new project.

We are going to use the blank app template which is the ideal one for our tutorial since we are going to start from a clean slate.

npx create-snowpack-app my-awesome-glimmer-app --template @snowpack/app-template-blank
Enter fullscreen mode Exit fullscreen mode

Add dependencies

The next thing is adding the required dependencies for our project. The first one is @glimmerx/core. This package contains the renderComponent function which is similar to React.render method in React to mount components on to a DOM node.

The second dependency is @glimmerx/component which exports the Component and hbs functions for defining Glimmer components.

Add them to your dependencies

yarn add @glimmerx/core @glimmerx/component
Enter fullscreen mode Exit fullscreen mode

Adding babel plugins

The next thing in our tutorial is to install the necessary dependencies to build our glimmer app.

@glimmerx/babel-plugin-component-templates

The first dev dependency we need is @glimmerx/babel-plugin-component-templates which is a Babel plugin that compiles templates with the Glimmer compiler.

yarn add -D @glimmerx/babel-plugin-component-templates
Enter fullscreen mode Exit fullscreen mode

@babel/plugin-proposal-class-properties

This plugin is to use the class property syntax like below to use in our component definitions.

import Component from '@glimmerx/component';
import Button from './Button';

export default class MyComponent extends Component {
  static template = hbs`
      <h1>Hello world!</h1>
      <Button @title="Click me" />
    `;
}
Enter fullscreen mode Exit fullscreen mode
yarn add -D @babel/plugin-proposal-class-properties
Enter fullscreen mode Exit fullscreen mode

@babel/plugin-proposal-decorators

This plugin allows us to use the @decorator syntax in our components for things like tracked properties, actions and services.

import Component, { hbs, tracked } from '@glimmerx/component';
import { on, action } from '@glimmerx/modifier';
export default class extends Component {
  static template = hbs`
        <button {{on "click" this.incrementCounter}}>Counter: {{this.count}}</button>
      `;
  @tracked count = 1;

  @action
  incrementCounter() {
    this.count++;
  }
}
Enter fullscreen mode Exit fullscreen mode
yarn add -D @babel/plugin-proposal-decorators
Enter fullscreen mode Exit fullscreen mode

App.js

Next we are going to put some code in our App.js situated under the /src folder in our project.

import Component, { hbs, tracked } from '@glimmerx/component';
import './App.css';
import logo from './logo.svg';

export default class App extends Component {
  @tracked count = 0;

  constructor() {
    super(...arguments);
    setInterval(() => {
      this.count++;
    }, 1000);
    this.logo = logo;
  }

  static template = hbs`
   <div id="intro">
      <img src={{this.logo}}/>
      <h1>Hello, glimmerx!</h1>
      <h3>
        You can get started by editing <code>src/App.js</code>
      </h3>
      <h2>Time elapsed since start: {{this.count}} seconds</h2>
   </div>`;
}

Enter fullscreen mode Exit fullscreen mode

Now we installed the required dev dependencies in our project, it's time to tell Snowpack how to use all of them to build or compile our glimmer.js components.

Configuring snowpack

Snowpack already comes with built-in support for building JavaScript, TypeScript, and JSX. However, If you would like to run your build through Babel instead, you can replace the default file builder with the official Snowpack Babel plugin.

The plugin will automatically read plugins & presets from your local project babel.config.* config file, if one exists.

We also need to tell Snowpack to use our babel plugins we installed earlier to build the components.

This can be done by adding the necessary plugins to the plugins option in our Snowpack config file which is snowpack.config.js present in the root directory of our project.

Before that we need to install the @snowpack/plugin-babel:

yarn add -D @snowpack/plugin-babel
Enter fullscreen mode Exit fullscreen mode

Then we need to add the plugins in the snowpack config.

plugins: [
    [
      '@snowpack/plugin-babel',
      {
        input: ['.js', '.mjs', '.jsx', '.ts', '.tsx'],
        transformOptions: {
          plugins: [
            '@glimmerx/babel-plugin-component-templates',
            ['@babel/plugin-proposal-decorators', { legacy: true }],
            '@babel/plugin-proposal-class-properties',
          ],
        },
      },
    ],
  ],
Enter fullscreen mode Exit fullscreen mode

And we need to do one more thing. If we try to start the build we will get an error something like this in the browser.
Alt Text

What it actually says is that we are missing @glimmer/core as a dependency for our app, since @glimmerx/core is actually dependent on this library but we haven't installed it. We also get an error in the console to add the @glimmer/core package to the install option in the Snowpack config file.

Alt Text

Let's add the same to our snowpack.config.js

install: ['@glimmer/core']
Enter fullscreen mode Exit fullscreen mode

We can also add this to our project dependencies, but that throws another error something like this, which is basically the @glimmer/reference package doesn't have a ComponentRootReference function exported. If you know how to fix this one, please let me know in the comments.

Alt Text

So, let's stick with the install option in Snowpack for now until we figure out, why adding @glimmer/core directly in our project dependencies is not working.

All done, now it's time to start our app. Just fire up npm start in the terminal and Snowpack will start its work. It will install the project dependencies and bundle them into the web_modules folder, from where the libraries are referenced in our code in the final build output.

npm start
Enter fullscreen mode Exit fullscreen mode

Alt Text

And this is how our app should look like in the browser.

Alt Text

Using snowpack-app-template-glimmer

Now we have seen, how to setup and configure Snowpack to build Glimmer.js apps, but we don't have to do this manually everytime to setup a glimmer project with Snowpack, that is where the create-snowpack-app templates come into play.

All the above mentioned steps from adding dependencies and configuring Snowpack have been put together in a create-snowpack-app template called snowpack-app-template-glimmer which you can use to bootstrap your glimmer apps without all the hassle.

It's just about using our new app template for glimmer with create-snowpack-app:

npx create-snowpack-app my-glimmer-app --template snowpack-app-template-glimmer
Enter fullscreen mode Exit fullscreen mode

Demo app - Todo-List

I have built a demo Todo-List app with this template, the demo is hosted here and the source code is available on Github.

Top comments (9)

Collapse
 
knownasilya profile image
Ilya Radchenko

Great post!

Collapse
 
fpauser profile image
Falk Pauser

Great stuff!

Collapse
 
tschoartschi profile image
tschoartschi

That's really cool 🤩 great to see some Glimmer.js again. We used it in an old project and loved it. I hope that there is more development coming on Glimmer.js

Collapse
 
dknutsen profile image
Dan Knutsen

This is great, thanks for sharing! Love to see some glimmer.js stuff and especially using newer tools like Snowpack.

Collapse
 
ahemedhaneen profile image
Haneen Ahemed A

Have anyone tried this with @glimmerx/xxxx@v0.6.7 packages?
i'm facing dedupe issues from v0.4

Collapse
 
fpauser profile image
Falk Pauser • Edited

This should be added to github.com/snowpackjs/snowpack/tre... along with the tutorials that show how to use snowpack with react and svelte.

Collapse
 
rajasegar profile image
Rajasegar Chandran

I am not sure whether the Snowpack team will approve it, I will trying raising a PR for the same.

Collapse
 
leonardopuleggi profile image
Leonardo

hi, I was thinking of implementing something similar in a full Ember classic app. Did you have a go at that as well? Is it in pipeline already?

Collapse
 
rajasegar profile image
Rajasegar Chandran

No Leonardo, I haven't tried it