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
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
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
@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" />
`;
}
yarn add -D @babel/plugin-proposal-class-properties
@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++;
}
}
yarn add -D @babel/plugin-proposal-decorators
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>`;
}
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
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',
],
},
},
],
],
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.
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.
Let's add the same to our snowpack.config.js
install: ['@glimmer/core']
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.
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
And this is how our app should look like in the browser.
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
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)
Great post!
Great stuff!
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
This is great, thanks for sharing! Love to see some glimmer.js stuff and especially using newer tools like Snowpack.
Have anyone tried this with
@glimmerx/xxxx@v0.6.7
packages?i'm facing dedupe issues from v0.4
This should be added to github.com/snowpackjs/snowpack/tre... along with the tutorials that show how to use snowpack with react and svelte.
I am not sure whether the Snowpack team will approve it, I will trying raising a PR for the same.
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?
No Leonardo, I haven't tried it