When you start a fresh web project or start digging into an existing code base, chances are you’re trying to create or enhance a feature for your users. The last thing you want to do is spend time customizing build tools and creating infrastructure to develop your application. If you land a new client, you want to show them features today, not in a week after you’ve cobbled together a build pipeline.
As you might already know, Ember is an “opinionated” JavaScript web framework focused on building ambitious, rich client web applications. Technologically, Ember has positioned itself as the antidote to hype fatigue. It’s a framework that just won’t die, but keeps pressing on with each innovation and with a commitment to backwards-compatibility.
Further Reading on SmashingMag:
- React To The Future With Isomorphic Apps
- An Introduction To Full-Stack JavaScript
- Journey Through The JavaScript MVC Jungle
Ember CLI is the Ember community’s shared solution for front-end tooling. It provides a productive and feature-rich development experience out of the box.
The Challenge Of Trivial Choices
On the face of it, front-end build tools appear too diverse for a shared solution. There are too many factors to account for, and every project has its own specials needs. As stated on React’s documentation page for “Tooling Integration,” “Every project uses a different system for building and deploying JavaScript.”
Are you using Rails or .NET? What CSS preprocessor are you using? Does your application consist of a single page or “islands of richness”? Are you using JavaScript globals, asynchronous module definition (AMD), universal module definition (UMD), CommonJS or ECMAScript 6 modules? What testing framework do you prefer?
Because developers’ needs vary so much, low-level build tools such as Gulp, Grunt and Broccoli are often the starting point for front-end development. Yeoman, Lineman and Brunch take us further by generating the boilerplate needed for various use cases.
So, how is Ember CLI different? By making Ember CLI the official build tool for Ember, the community gets a default suite of tools that are integrated by 225 Ember CLI contributors and battle-tested around the clock by the Ember user community. These tools provide useful conventions, clear paths to best practices, and escape from the burden of trivial choices. As Chris Eppstein tweeted, referring to the Sass language, “It’s our belief that this consistency promotes a vibrant ecosystem and that it’s a bigger benefit than the ‘just right for me’ approach.”
Some developers might find it difficult to give up choice in favor of productivity. I argue that we must become experts in the domain in which we work and, for most developers, that domain is the intersection of the client’s business and maintainable application development. Frankly, I’ve never heard of a development team that created build tools they were happy with. However, I have seen custom build tools be disastrous for projects. You should try Ember CLI before attempting to build your own.
New Opportunities
Ember CLI isn’t just about building assets better than before. When a community coalesces around a technology, new opportunities for productivity emerge. Here are a few innovations that have become possible with Ember CLI.
- Ember Addons These are libraries that can be installed in an Ember CLI application and that “just work” with zero configuration.
- Ember CLI Deploy This is for conventional front-end deployment.
- Ember FastBoot Render Ember applications on the server for faster initial page load.
Another side effect of Ember CLI is that developers receive the latest and greatest technology, without even needing to know it exists. Out of the box, Ember CLI applications have ECMAScript transpilation with Babel, live reloading during development, and a simple way to proxy AJAX requests to a local or remote server.
Let’s Create An Ember App
Before creating an Ember CLI app, you’ll need to install Node.js. You can find out how to install it on the Node.js website, or you can use the popular Homebrew project if your computer runs Mac OS X:
brew install node
Next, install Ember CLI itself:
npm install -g ember-cli
With the prerequisites out of the way, you’re ready to create your first Ember application:
ember new my-app
Once that’s finished, move to your app’s directory (cd my-app
), run your app with ember serve
, and visit localhost:4200
to see your application in action.
Using Ember CLI
Using the blueprints feature of Ember CLI, let’s add some meat to our app and show a list of posts when a user visits the /posts
URL. You can also follow along in the accompanying GitHub repository.
ember g resource posts title:string body:string
This tells Ember CLI to generate a posts
resource — it creates a route
entry in your router, a route, a posts template and a post model. The post model will have title and body attributes that are cast to strings.
We’ll need to loop through our posts and render them in our posts
template. The each
helper makes this possible in app/templates/posts.hbs
.
{{#each model as |post|}}
<h3>{{post.title}}</h3>
<hr>
{{post.body}}
{{/each}}
Next, we’ll want to find our posts’ data and hand it off to the template when the user visits /posts
. We’ll fetch the posts in the model hook of our posts route, located at app/routes/posts.js
.
export default Ember.Route.extend({
// Add this method
model() {
return this.store.findAll('post');
}
});
You might notice that we’ve used ECMAScript 6’s shorthand syntax for objects to define the model
method. Because Ember CLI uses a JavaScript transpiler by default, expect to see modern JavaScript code in most Ember applications.
We could have just written some JavaScript objects for the post data in our route here and called it a day, but let’s go a little further and actually fetch posts from a server.
We’ll generate an Express web server to serve up some data to our application.
ember g http-mock posts
Then, we’ll return some dummy data from /api/posts
. Edit the generated server/mocks/posts.js
file to return some data from the index route.
postsRouter.get('/', function(req, res) {
res.send({
'posts': [
// Add these objects
{ id: 1, title: 'First Post', body: 'Blogging' },
{ id: 2, title: 'Second Post', body: 'Blogging again' }
]
});
});
The last thing we’ll need is a customized Ember Data adapter.
ember g adapter application
To make sure Ember Data knows to find the posts at /api/posts
, we’ll add a namespace to our adapter in app/adapters/application.js
.
export default DS.RESTAdapter.extend({
namespace: 'api' // Add this
});
Now, if you visit localhost:4200/posts
, you will see the posts in all their glory.
Of course, you’ll probably want to hook up your application to a real web server at some point in the development process. When you’re ready, you can remove the mock server and run your app with the proxy option:
ember s --proxy http://localhost:3000
In this command, replace http://localhost:3000
with your local or remote web server.
This is a great way to build your front end immediately and transition to a production web server later.
Using Ember Addons
If you’re familiar with using Bower and npm to install dependencies, then Ember Addons might impress you.
Let’s install and use a date-picker in our Ember app. My date-picker of choice is Pikaday. Luckily, several people have already integrated this library with Ember CLI. Here, we’ll use the ember-pikaday
addon.
ember install ember-pikaday
Now, let’s create a file at app/templates/index.hbs
and try it out.
{{pikaday-input value=date format='MM/DD/YYYY'}}
<p>You picked: {{date}}</p>
This addon installed Pikaday and Moment.js, it provided an Ember component named {{pikaday-input}}
, and it included the Pikaday CSS in our build — all with a single installation command.
Testing
Integrating your application code, a testing framework and a test runner can be challenging. You’ll want to run unit tests against isolated parts of the code and integrated tests against the running application. You’ll also want to run tests from the command line for continuous-integration testing on a build server.
Let’s write a test for the posts page that we made earlier. We’ll start by generating an acceptance test called “posts.”
ember g acceptance-test posts
Now, you can visit http://localhost:4200/tests
to see the running test.
We already have 16 tests? That’s right. Our generators from earlier each created a test to help us get started, and each of our files was tested with JSHint for errors.
Let’s fill out the generated acceptance test with something that tells us that all of our posts are rendered.
test('visiting /posts', function(assert) {
visit('/posts');
andThen(function() {
var titles = find('h3').toArray().map((el) => el.textContent);
assert.deepEqual(titles, ['First Post', 'Second Post'], "Has both titles");
});
});
This test starts up our Ember app in an isolated portion of the test runner, visits the posts path and then asserts that each post title is on the page. The andThen
helper waits for asynchronous processing to stop before making assertions.
If you’re not an avid tester, you might find yourself running out of excuses with Ember CLI. If you do get excited by testing, you’ll find it easy than ever to get started. The blueprints put current best practices at your fingertips, so that you don’t have to spend time Googling “how to test [x] in Ember.”
Going To Production
Before shipping the code to production, you’ll want to optimize for speed, minify the code, fingerprint your assets and link those fingerprinted assets in the index.html
file.
You can accomplish all of that with a single command, which puts your production-ready files into the /dist
directory.
ember build --environment="production"
Once your assets are built for production, the next step is to deploy them to a remote server. Many Ember CLI users choose to integrate these build files with the same deployment process they use for back-end server code. However, an emerging best practice, refined and championed by Luke Melia, is to use a separate front-end deployment workflow that allows your Ember application to be deployed independently of your server code.
At EmberConf 2015, Luke announced that the maintainers of prominent addons for deployment had joined forces to create one addon under the name Ember CLI Deploy. The newly formed team released its first joint effort, version 0.5.0 of the addon.
Ember CLI Deploy embraces a “core and plugins” architecture. The add-on provides the deployment workflow, but users install different plugins according to the exact infrastructure they use. For instance, one setup proposed by Luke uses Amazon’s S3 service to host files and Redis to store and link the Ember application’s index.html
file.
You can install the current addon using the same installation command we saw before:
ember install ember-cli-deploy
We’ll also install ember-cli-build to build our application for production.
ember install ember-cli-build
From there, you can install the asset-adapter plugin that you need:
ember install ember-cli-deploy-s3
Then, you’ll need to install an index-adapter plugin, which provides a way to link your index.html
file to the server:
ember install ember-cli-deploy-redis
Finally, you can edit your config/deploy.js
file to include information about Redis and S3, so that Ember CLI Deploy can interact with these services.
With those adapters installed and configured, you can deploy with one command.
ember deploy production --activate
This command will:
- build your assets for production,
- upload your JavaScript and CSS assets to S3,
- upload your
index.html
file to Redis, - “activate” the last
index.html
file that was uploaded.
In this sequence of events, only the last step, activation, changes the version of the Ember application that is served to users. Previous versions of index.html
are stored on Redis, and previous versions of your assets are stored on S3. To switch the version of the running Ember application, developers use the activate
command to tell their server to use a particular index.html
file that is pointing to single set of assets stored on S3.
ember deploy:activate production --revision 44f2f92
To learn more about how you can deploy an Ember application with your infrastructure, checkout the documentation for ember-cli-deploy.
Not Just For Ember
All of that talk about eliminating trivial choices might have left you with the impression that Ember CLI isn’t flexible or configurable. Because Ember CLI needs to accommodate a wide range of use cases from the community, it has a well-defined public interface for customization. In fact, despite the name, Ember isn’t a requirement for Ember CLI. For instance, the Firefox OS team has used Ember CLI with an addon that it created, rather than create its own build tool.
Suppose you want all of the wonderful features of Ember CLI without Ember. Again, you can follow along in the accompanying GitHub repository if you like. We’ll start with a new Ember CLI application:
ember new no-ember
Next, we’ll get rid of Ember so that it isn’t in our JavaScript build. We’ll remove Ember and Ember Data from the bower.json
file.
// In bower.json
{
…
"dependencies": {
"ember": "2.2.0", // Delete
…
"ember-data": "^2.2.1", // Delete
…
},
"resolutions": {
"ember": "2.2.0" // Delete
}
}
We also need to remove Ember Data from the package.json
file.
// In package.json
{
…
"devDependencies": {
…
"ember-data": "^2.2.1", // Delete
…
}
}
Next, let’s delete most of the things in our application directory. To have a working application, we only need, styles
, app.js
and index.html
.
app/
├── app.js
├── index.html
└── styles
Ember CLI is expecting us to export an object from app.js
that has a create
method which mirrors the interface to an Ember.Application
. Let’s replace the default content in that file with a simple exported object.
export default {
create() {
}
};
Finally, let’s create an ECMAScript 6 module that renders something in our application.
In app/modules/render-something.js
, we’ll export a function that renders some content.
export default function renderSomething() {
document.write("Who needs a framework?");
}
You can put the modules wherever you want in the app
directory. You’ll use the same path when importing from your application’s namespace. Here is how we can import and use that module in our app.js
file:
import renderSomething from 'no-ember/modules/render-something';
export default {
create() {
renderSomething();
}
};
Now you can see your web app running at http://localhost:4200
.
The Future Of Ember CLI
Without question, Ember CLI is here to stay. Although the Ember community was the first of the modern front-end framework communities to take build tools into their own hands, others have begun to follow suite. AngularJS 2.0 has its own CLI tool, angular-cli, which is an Ember CLI addon. Because React has a narrower scope than AngularJS 2.0 or Ember, an official build tool is not planned, but something promising will hopefully emerge from its current ecosystem of tools.
If you’ve been waiting to give Ember a try, why not start today with Ember CLI? All you need to get started is this:
npm install -g ember-cli
ember new my-first-ember-project
References
- Ember CLI The official documentation
- “Building Custom Apps With Ember CLI” (video), Brittany Storoz, EmberConf 2015 Storoz talks about using Ember CLI at Mozilla.
- “Keynote: 10 Years!” (video), Yehuda Katz, RailsConf 2015 Katz explains why choices can be harmful.