Brought to you by
Icon of Hamster in a wheel

Ember Pro Workshop

Learn about pro Ember.js topics from simplabs and Mike North.

Sign up to be notified about future dates and locations

  • Just wanted to say how helpful I have found the Ember 2.0 course by Mike North. Ember is a really great tool, and Mike proved himself to be extremely knowledgeable and able to carefully articulate the nuances of Ember development, I certainly learned a lot of little things that I wasn't aware of previously and my understanding of Ember is that much better. Daniel Jeffery

  • [...] There was a very broad consensus that your style and depth would be a great fit for our team. John Norman, Chief Architect Iora Health

  • I appreciate someone that approaches the topic from the perspective of someone who both knows how to write Ember apps *and* understands the community, framework, future direction, etc. Andy Pickler

The Workshop

We'll go way beyond the fundamentals, tackling topics like authentication, advanced debugging techniques, server-side rendering and modular app design.

This course is designed to help developers already familiar with Ember.js to unlock the true power of the framework.

Day 1

Booting and Building  

It makes sense to begin at the beginning. We'll thoroughly examine how your ember app is built and how it boots up, getting a little hands-on experience with the parts of the framework that glue all of your application code together.



Welcome & Setup

Some friendly introductions, and a quick overview of the training plan.


Container, Loader and Resolver

Like many opinionated web frameworks, most of the code developers write is in hooks: important functions that are called in a predictable way, which may be extended to customize behavior.

When things appear to go wrong between hooks, being able to peek into a few of the important framework internals can be incredibly valuable. We'll cover three important concepts that will start to give you visibility into what may have previously been a black box.


Exercise: Consume ES5 modules in ES6

Using our knowledge of the loader, let's put a file in our /vendor folder to make an ES6 module available in our app in totally different namespace.



If you've ever copied and pasted a code from a library's source, in order to customize a little behavior within a complex internal process, you've likely felt the pain of keeping your customized behavior in sync with upstream changes to the library.

Ember's boot process was built with customization in mind, and provides a mechanism for inserting our own custom code at various places in startup process. These bits of code are called initializers and instance-initializers.

We'll build on our knowledge of the container, and use the Registration API to prepare it for our app, in some initializers and instance-initializers of our own.


Exercise: Container Setup in an Initializer

We only want our app to boot up once we have geolocation data. Retrieving this from the browser is an async process, so we'll need to ensure we halt the boot process until it's complete. Once data has been retrieved, put it in the container under the data:location key, in such a way that we only have a single copy of the object used across the whole app.


Building with Broccoli

Broccoli is the asset pipeline used by ember-cli, and it has one job: transforming and combining files. While the core broccoli library is great, some of the most important build-related stuff happens inside the many broccoli plugins that are used to transpile, minify, uglify and analyze your source code.

We'll build our own broccoli plugin, explore some debugging techniques and learn some broccoli best practices.


Exercise: Build a Broccoli Plugin

We want to add a copyright notice comment to the top of all built JavaScript files. Do so by way of a broccoli plugin.

Note: you may end up tampering with files after the've already been fingerprinted, so you may need to remove ember-cli-sri from your project.


A simple CI/CD Scheme

One of the distinct advantages of working with an opinionated framework is that many people are working with the same set of libraries and tools. Continuous integration and continuous deployment typically take a lot of effort to set up, but in the ember world, it's incredibly easy! We'll use Travis-CI and Heroku (coincidentally, two both apps) to automatically test and deploy new code that's pushed to our project's GitHub master branch.


Exercise: Github + Travis CI + Heroku = easy CI/CD

Set up free continuous integration w/ Travis-CI, create a new app on Heroku using the ember-cli build pack, and have Travis automatically deploy in the event that tests pass.

BONUS: setup a heroku pipeline, and enable PR apps, so you can view and play with proposed changes before merging PRs!



Break for Lunch



Ember's server side rendering technology is incredibly easy to set up, particularly in comparison to getting something equivalent working in ecosystems that are less opinionated and aligned to a common set of ideas.

Although both browsers and Node.js both run JavaScript, there are a couple of very important differences that we need to be aware of, as we prepare our app for Fastboot.


Exercise: Ready, Set, FastBoot!

Install ember-cli-fastboot, and run ember fastboot --serve-assets. You'll find that something we're doing is making our lightweight and incomplete DOM implementation unhappy. Use our knowledge of Fastboot guards to fix this problem (i.e., skip it if we're running in fastboot land).


Exercise: Server data in client land

Grab the user agent of the incoming request to index.html, and make it available in the container under the container key data:request.

State Management I  

Particularly when working in an environment like the browser, where some things are fast, and some things are really slow, it behooves us to set some state management ground rules, so we don't run into trouble as our app grows in size and complexity.



Addressable State

Addressable state is essentially anything that's directly represented in the browser's URL. Poorly managed addressable state can lead to problems, where the browser's back button doesn't do what your user expects.


Exercise: Bookmarkable List Filters

Add a feature where we can type a name fragment in our project's search field in order to filter the list of records.

  • This should be done in a data down, actions up way
  • Reduce the number of API calls made if you can
  • Ensure that you don't break browser history

State Management II  

Particularly when working in an environment like the browser, where some things are fast, and some things are really slow, it behooves us to set some state management ground rules, so we don't run into trouble as our app grows in size and complexity.




We'll remind ourselves of what was covered in the earleir sessions so it's fresh in our minds.


Draft State & WeakMap

When a user spends some effort creating some state (i.e., a comment on a GitHub issue), it's important to protect them from losing it by way of an accidental swipe, press of the browser's back button, or a file drop in the browser's window.


Exercise: Draft Comments

We want to be able to make comments, and first we want to ensure that we don't allow users to accidentally discard their draft comments. Additionally, we need to ensure that drafts are always associated with the appropriate record.


Persisted State

You're no doubt familiar with persisted state, and using ember-data to help you manage it. However, when doing anything asynchronous, we have to keep context and life cycles in mind.


Exercise: Saving Comments

When a user wants to save a comment, it should be persisted to the API. Please implement this feature and meet the following requirements

  • Once a save has successfully completed, the appropriate draft state should be cleared
  • Your solution must behave as expected in a high-latency environment


UI State

UI State is often pertinent to the presentation layer only, is only relevant "in the moment", and can in fact be harmful if not discarded and given a clean start if a user leaves and comes back. You may be thinking that component member data is the tool for the job, but it's more nuanced than you think!


Exercise: UI State

We have a little metadata area at the top of each record, and want to allow users to expand and collapse it to their heart's content! Implement this feature, and meet the following requirements:

  • The expand/collapse state should not carry over from one record to another as we navigate around
  • If we expand the metadata area on a record, then go somewhere else, and then come back, we should see things as we left them


Wrap up & Recap

We'll recap everything we've learned today, and set our sights on more topics for tomorrow!

Day 2

Managing Complexity  

Ambitious apps have a tendency to be inherently a little complex. We'll look at a few battle-tested ember addons that have emerged as the go-to solutions in their domains, and leverage this third party code to enrich our app while keeping complexity under control.




Promises are soooo 2016. We'll do a few things with ember-concurrency, a library that leverages the power of Generator Functions to help us manage asynchronous tasks with grace and poise.


Exercise: Better Comment Saving

We can improve our comment saving experience, by disabling the textarea and save button while the operation is underway.



A little tasteful animation can make a world of difference, in making your app feel rich and interactive. We'll look at a few easy to use features in Ember's official animation library, liquid-fire, whose "big idea" is making animations declarative.


Exercise: Animated Comment Count

We have a small comment count indicator in the list of records on the left side of the screen. Use liquid fire to animate this so that it rolls over "odometer style" when comments are added or removed.


Logic in Templates

As you start building a sizable app, it's easy to become annoyed at all of the repetitive computed properties that usually come along with conditionals, filtering and transforming data, and mutating values. We'll look at two libraries

  • ember-composable-helpers
  • ember-truth-helpers

That allow us to express simple logic declaratively in templates.


Exercise: Public vs. Private Comments

Good news! We have a new feature whereby comments can be made either in "fact" or "opinion" mode.

  • Using only a <select> element, composable helpers, and minimal imperative code in JavaScript files, add a drop down allowing the user to pick between comment types when creating a comment
  • Add a filter to the top of the list, allowing us to pick from three modes "fact", "opinion" or "all"
  • In "all" mode, facts should be sorted higher on the list than "opinions", but they should otherwise be sorted by createdAt within each category.


Authentication & Authorization

Authentication is often the first big thing we end up building into a new app, and the approach ember-simple-auth takes has clearly resonated with the Ember community. By building a small set of single-purpose JavaScript modules, and mixing a few things into a few foundational framework objects, we can have authentication working in no time! We'll go a step further and explore the concept of roles, whereby users are granted or denied access to certain routes, based on some data associated with their user object.


Exercise: Login/Logout

The API we've been using supports authentication via OAuth2 Password Grants. Implement "logging in", and unlock the ability to post non-anonymous comments. Add a "Logout" button to the navbar, which should

  • make a DELETE request to the same endpoint we use for login, and then
  • invalidate the client-side session



Break for Lunch

Professional Patterns  

Knowing how things work is one thing, but knowing how they're used by experts in the wild will help you learn the easy way instead of the hard way.



CRUD Mixins

There are several types of repetitive routes that most apps end up needing for the following purposes

  • Creating a new record
  • Updating an existing record
  • Showing a record
  • Showing a list of records

We'll devise a common abstraction for each of these, and DRY up our code by establishing some conventions within our project.


Exercise: CRUD Mixins

Let's DRY up our routes for showing a list of records, and the route for creating a new record, by building some general purpose mixins.


ES2016, ES2017 & ES2018 in Ember

You're no doubt aware of new language features coming to the JavaScript world, but since some of us have years of experience writing ES5 code, it's hard to develop new habits that take advantage of the new stuff.

We'll look at some ideal places to apply destructured assignment, enhanced object literals, ES6 classes, async/await and more, with a specific focus on how the new ideas mix well with Ember.


Exercise: async/await
  • Rewrite our logout logic using async/await
  • Write an acceptance test for visiting a record and comment on it, using async/await



ember-cp-validations takes an approach to validating ember-data records (or really, any Ember.Object subclass) that's built entirely using computed properties. We'll look at how to apply this library, customize error messages, display them on the screen, and even integrate with ember-data to surface server-side errors in the UI.


Exercise: Client-side Comment Validation

Implement clients-side validation for comments, where anonymous comments must be less than 140 characters, but non-anonymous comments can be up to 255.

Modular Architecture  

One of the unique strengths of the Ember ecosystem is the concept of an Ember Addon.

The big recent advancement in this area over the past year is the concept of engines, a special kind of addon that essentially is an app in and of its self, embedded or mounted in the consuming app.

Tomorrow's ember apps will take advantage of all of these great capabilities, so we'll thoroughly study the various building blocks, and cover some important and broadly useful scenarios.



Addon Basics

Ember addons can exist as their own independently-versioned separate projects, or as in-repo addons that live within a host app's /lib folder. There are major benefits to both of these patterns, so once we cover some common addon basics, we'll outline important differences and practical use cases for each.


Module namespaces, Resolvers consequences

Typically, when working with addons, you have two top-level folders: app and addon, each of which may contain familiar folders like components, routes, etc... . We'll connect back to our newfound knowledge of the container, loader and resolver, to understand important consequences of putting certain types of files in each tree.


Exercise: UI Kit

Move our {{x-input}} and {{x-textarea}} components into a new in-repo addon called core-ui. Make sure your templates are not in the /app folder.


Exercise: Modifying a host app's Asset Pipeline

Addons are the go-to way of building up an app's asset pipeline in a modular way. We'll look at the different places that we can get access to important Broccoli trees, and cover some important distinctions between being consumed in apps vs other addons vs engines.


Route-less Engines

Engines are a powerful new capability, similar in concept to the idea of Rails engines, for embedding a sub-application into a host app. This is a departure from non-engine addons, in that the engine has its own registry & container, can have its own initializers, services, etc...


Routed Engines

We've already embedded a route-less engine into a view, so let's take things to the next level and mount a routed engine in our router. We'll need to introduce a few new concepts relating to how engines share information with the host app, and pay special attention to the way we create components that cross the host/engine boundary.


Lazy Engines

Beyond encapsulation, one of the biggest benefits that come along with engines is that it frees us from having to pile our entire app into one big set of static assets, to be downloaded as the user first enters. Lazy engines allow chunks of assets to be downloaded on an as-needed basis, as a user crosses an engine boundary.

Although this adds a little extra complexity to our apps, the performance payoff can be huge, particularly if infrequently-used sections of your app are particularly heavy in terms of dependencies and application code.


Wrap up & final Recap

We'll take a step back and recap everything we've learned so far, putting in the broader context of being able to build out things quickly, robustly and sustainably with Ember.js.

Your instructor Mike North

Image of Marco Mike North

Mike is a global speaker, trainer and modern web consultant. Previously he was the CTO of Levanto Financial, and the UI Architect of Yahoo Ads & Data. He's a Front End Masters instructor, a Pluralsight author, and at his core a "product guy who codes". Mike has a passion for helping developers master the tools they're working with, in the interest of team productivity and happiness.