ember-cli is the canonical way of running Ember apps, confirmed by the RFC that formalizes the upcoming v2.0 release.
While globals-based apps will continue to work in 2.0, we may introduce new features that rely on either Ember CLI or ES6 modules. You should begin moving your app to Ember CLI as soon as possible.
—Tom Dale, The Road to Ember 2.0
So ember-cli is a big deal. And so I decided to try it out, but not directly. I still think keeping my workflow under Rails is more productive, so I’ll use the recommended ember-cli-rails gem.
Warning: This article has a previous version that uses
ember-rails instead. Read the original article.
To install ember-cli, run
npm install ember-cli -g.
$ npm install ember-cli -g $ ember -v version: 0.1.12 node: 1.1.0 npm: 2.1.8
Notice that I’m using IO.js, so that’s why my Node version is listed as
1.1.0. If you get similar output, then you’re good to go.
Configuring your Rails app
First, let’s remove things we won’t use from our
Gemfile. This includes
jquery-ujs. You also have to add the
source 'https://rubygems.org' gem 'rails', '4.2.0' gem 'sass-rails', '~> 5.0' gem 'uglifier', '>= 1.3.0' gem 'ember-cli-rails'
You can install the dependencies with
Setting up your Rails app
ember-cli-rails will give you a generator called
ember-cli:init, that will basically create an initializer file. Go ahead and generate it.
$ rails g ember-cli:init create config/initializers/ember.rb
You can use this initializer to setting up your Ember apps. By default it’s configured to use an application called
frontend that must live under
EmberCLI.configure do |config| config.app :frontend end
You can define a different path, or even map multiple apps.
EmberCLI.configure do |config| config.app :frontend, path: 'app/ember/frontend' config.app :admin #=> path will be app/admin end
For your Ember application, I suggest changing the app to something like
:rails_root/frontend. Adding to the
app directory will impact your performance in development mode, because Rails will track all files for auto-loading, even though this won’t be used. So for this example, I’m assuming your Ember app will live under
EmberCLI.configure do |config| config.app :frontend, path: Rails.root.join('frontend').to_s end
To bootstrap your Ember app, let’s create a Rails controller/action. You can go with
EmberController#bootstrap. You don’t have add anything to the
class EmberController < ApplicationController def bootstrap end end
Notice that you don’t have to specify the
EmberController#bootstrap method, but I like the visibility. Again, remember to create a blank file at
Since you may use
app/views/layouts/application.html.erb for other things than just Ember, I recommend creating a new layout file at
<!doctype html> <html dir="ltr" lang="<%= I18n.locale %>"> <head> <meta charset="UTF-8"> <title>Ember</title> <%= stylesheet_link_tag 'frontend' %> <%= include_ember_script_tags :frontend %> </head> <body> <%= yield %> </body> </html>
stylesheet_link_tag instead of
Ember has support for
history.pushState; this means that every time you visit a route, the URL will change, instead of using the
#! scheme. You’ll need a
catch-all route for this to work, so update your
config/routes.rb to something like this:
Rails.application.routes.draw do root 'ember#bootstrap' get '/*path' => 'ember#bootstrap' end
Creating an Ember app
Everything we’ve done so far was configuring Rails. Now it’s time to generate the Ember application. You’ll have to use the
ember command for this. From your Rails app root directory, run
ember new frontend.
$ ember new frontend --skip-git version: 0.1.12 installing create .bowerrc create .editorconfig create .ember-cli create .jshintrc create .travis.yml create Brocfile.js create README.md create app/app.js create app/components/.gitkeep create app/controllers/.gitkeep create app/helpers/.gitkeep create app/index.html create app/models/.gitkeep create app/router.js create app/routes/.gitkeep create app/styles/.gitkeep create app/templates/application.hbs create app/templates/components/.gitkeep create app/views/.gitkeep create bower.json create config/environment.js create .gitignore create package.json create public/crossdomain.xml create public/robots.txt create testem.json create tests/.jshintrc create tests/helpers/resolver.js create tests/helpers/start-app.js create tests/index.html create tests/test-helper.js create tests/unit/.gitkeep create vendor/.gitkeep Installed browser packages via Bower. Installed packages for tooling via npm.
You also need to install the
ember-cli-rails-addon NPM package. Do it from your Ember app directory.
$ cd frontend $ npm install ember-cli-rails-addon --save-dev firstname.lastname@example.org node_modules/ember-cli-rails-addon $ cd ..
Let’s check if everything works together. Create a file at
frontend/app/templates/index.hbs with the following content.
<p> Fuck yeah! It works! </p>
We need to create a CSS file for our Ember app. So, create
app/assets/stylesheets/frontend.scss with the following content.
// @import './frontend/**/*';
This means that all CSS for
frontend Ember app will live under
app/assets/stylesheets/frontend directory. Remember to update your
config/initializers/assets.rb file to include this file to the precompiling list.
Rails.application.config.assets.precompile += %w[ frontend.css ]
Fire up your server with
rails server and head to
http://localhost:3000. You must see a page like this:
So, what exactly does ember-cli-rails do? In a few words, it runs
ember commands through a Rack middleware. When you visited
http://localhost:3000, ember-cli-rails issued the
ember build command, as you can see in your server log.
$ rails s => Booting WEBrick => Rails 4.2.0 application starting in development on http://localhost:3000 => Run `rails server -h` for more startup options => Ctrl-C to shutdown server [2015-02-07 22:37:06] INFO WEBrick 1.3.1 [2015-02-07 22:37:06] INFO ruby 2.2.0 (2014-12-25) [x86_64-darwin14] [2015-02-07 22:37:06] INFO WEBrick::HTTPServer#start: pid=87021 port=3000 Started GET "/" for ::1 at 2015-02-07 22:37:07 -0200 version: 0.1.12 Building... Build successful - 792ms. Slowest Trees | Total -------------------------------+---------------- Concat: Vendor | 139ms SixToFive | 71ms JSHint app- QUnit | 59ms ES6Modules | 55ms ES3SafeFilter | 53ms Processing by EmberController#bootstrap as HTML Rendered ember/bootstrap.html.erb within layouts/ember (1.5ms) Completed 200 OK in 118ms (Views: 117.2ms) Started GET "/assets/frontend/vendor-64e62ddc273c2f5847f30d698ca14b67.css?body=1" for ::1 at 2015-02-07 22:37:12 -0200 Started GET "/assets/frontend/frontend-64e62ddc273c2f5847f30d698ca14b67.css?body=1" for ::1 at 2015-02-07 22:37:12 -0200 Started GET "/assets/frontend/frontend-e07fffa094f820251c6586556d21c934.js?body=1" for ::1 at 2015-02-07 22:37:12 -0200 Started GET "/assets/frontend/vendor-a050afbf761cda6b6c9046c755b3dceb.js?body=1" for ::1 at 2015-02-07 22:37:12 -0200
Notice that the
ember process will be running in background until you stop your Rails server. This is useful, because ember-cli only compiles your Ember app when a file changes, making the whole process so much faster.
Although this integration is really helpful, it doesn’t mean you won’t ever run ember-cli directly; ember-cli has generators that will make you life easier, so you better off knowing the command-line’s API.
$ ember g -h version: 0.1.12 Requested ember-cli commands: ember generate <blueprint> <options...> Generates new code from blueprints. aliases: g --dry-run (Boolean) (Default: false) aliases: -d --verbose (Boolean) (Default: false) aliases: -v --pod (Boolean) (Default: false) aliases: -p Available blueprints: ember-addon: ember-data <name> ember-cli-qunit: ember-cli-qunit <name> ember-cli: acceptance-test <name> Generates an acceptance test for a feature. adapter <name> <options...> Generates an ember-data adapter. --base-class adapter-test <name> Generates an ember-data adapter unit test addon <name> The default blueprint for ember-cli addons. app <name> The default blueprint for ember-cli projects. blueprint <name> Generates a blueprint and definition. component <name> Generates a component. Name must contain a hyphen. component-test <name> Generates a component unit test. controller <name> Generates a controller. controller-test <name> Generates a controller unit test. helper <name> Generates a helper function. helper-test <name> Generates a helper unit test. http-mock <endpoint-path> Generates a mock api endpoint in /api prefix. http-proxy <local-path> <remote-url> Generates a relative proxy to another server. in-repo-addon <name> The blueprint for addon in repo ember-cli addons. initializer <name> Generates an initializer. initializer-test <name> Generates an initializer unit test. lib <name> Generates a lib directory for in-repo addons. mixin <name> Generates a mixin. mixin-test <name> Generates a mixin unit test. model <name> <attr:type> Generates an ember-data model. model-test <name> Generates a model unit test. resource <name> Generates a model and route. route <name> <options...> Generates a route and registers it with the router. --type=route|resource (Default: route) aliases: -route (--type=route), -resource (--type=resource) --path (Default: ) route-test <name> Generates a route unit test. serializer <name> Generates an ember-data serializer. serializer-test <name> Generates a serializer unit test. server <name> Generates a server directory for mocks and proxies. service <name> Generates a service and initializer for injections. service-test <name> Generates a service unit test. template <name> Generates a template. test-helper <name> Generates a test helper. transform <name> Generates an ember-data value transform. transform-test <name> Generates a transform unit test. util <name> Generates a simple utility module/function. util-test <name> Generates a util unit test. view <name> Generates a view subclass. view-test <name> Generates a view unit test.
Another thing that’s worth mentioning is that some tasks can only be performed by
bower commands; there’s no alternative as a rake task.
So, make yourself comfortable with ember-cli, NPM and Bower. You’ll probably have to do this eventually.
Ember has integration with QUnit. So here’s a tip: use it! Otherwise you won’t be able to use all built-in helpers. You also have way more documentation about Ember + QUnit than with any other framework.
All your Ember’s tests must be loaded from
<your ember app>/tests. When you generated the Ember app, some tests were generated too. You can run them by issuing
rake ember-cli:test (Rails app root) or
ember test (Ember app root).
$ cd frontend $ ember test version: 0.1.12 Built project successfully. Stored in "myapp/frontend/tmp/class-tests_dist-YU0yGWyj.tmp". ok 1 PhantomJS 1.9 - JSHint - .: app.js should pass jshint ok 2 PhantomJS 1.9 - JSHint - helpers: helpers/resolver.js should pass jshint ok 3 PhantomJS 1.9 - JSHint - helpers: helpers/start-app.js should pass jshint ok 4 PhantomJS 1.9 - JSHint - .: router.js should pass jshint ok 5 PhantomJS 1.9 - JSHint - .: test-helper.js should pass jshint 1..5 # tests 5 # pass 5 # fail 0 # ok
To run tests in your browser, execute
ember test --serve and visit
One problem you’ll notice is that your app’s CSS won’t be loaded; remember that we’re using Rails Asset Pipeline to handle images and CSS. A quick fix while we don’t have an official solution is pointing the CSS to your development’s web server. Just change the file
<link rel="stylesheet" href="assets/frontend.css"> to
<link rel="stylesheet" href="http://localhost:3000/assets/frontend.css">.
Installing Ember Inspector
If you want to develop Ember apps, make yourself a favor and install Ember Inspector, a Chrome extension that can inspect your app. You check objects, see rendering times, and more.
Having a totally different stack for your front-end has pros and cons. It’s great to have this separation when you have a front-end engineer that will hack Ember most of the time, but can be a pain point when you’re used to Rails and its workflow. Not to mention that the setup got way more complex than the one described by the original text.
ember-cli-rails is a nice start, but is still immature. In a perfect world you’d just use Rails and the asset pipeline. No ember-cli, no NPM, no Bower, but I don’t think that will ever happen.
So if you’re betting on Rails and Ember.js, make sure you get comfortable with ember-cli and consider using it without ember-cli-rails. Assume that Rails will be just an API and that you’re front-end is Ember, a completely different client.
You can found the source code for this example at Github.