Configurando o Ember.js no Rails com ember-cli
Leia em 8 minutos
Eu recebi alguns comentários no meu artigo sobre como configurar o Ember.js no Rails, sendo que o mais comum foi sobre o ember-cli.
O ember-cli é o modo canônico de executar aplicativos Ember, confirmado pela RFC que formaliza a versão 2.0
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
Conhecer o ember-cli é muito importante e, por isso, decidi testá-lo, mas não diretamente. Eu ainda acredito que manter o meu workflow no Rails é muito mais produtivo, por isso vou usar a gem ember-cli-rails, recomendada pelo próprio Ember.
Atenção: Este artigo possui uma versão anterior que usa ember-rails
. Leia o artigo original.
Instalação
Instalando o ember-cli
Primeiro você precisa instalar o Node.js ou, melhor ainda, IO.js. Por isso visite o site do projeto e siga as instruções para sua plataforma.
Para instalar o ember-cli execute npm install ember-cli -g
.
$ npm install ember-cli -g
$ ember -v
version: 0.1.12
node: 1.1.0
npm: 2.1.8
Perceba que estou usando IO.js, por isso minha versão do Node é identificada como 1.1.0
. Se você tiver uma saída semelhante, então tudo funcionou corretamente.
Configurando seu aplicativo Rails
Nós temos que remover coisas que não iremos usar do arquivo Gemfile
, como turbolinks
e jquery-ujs
. Você também tem que adicionar a gem ember-cli-rails
.
source 'https://rubygems.org'
gem 'rails', '4.2.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'ember-cli-rails'
Instale as dependências com o comando bundle install
.
A gem ember-cli-rails
adicionará um generator chamado ember-cli:init
, que irá criar um arquivo de inicialização.
$ rails g ember-cli:init
create config/initializers/ember.rb
Você pode usar este initializer para configurar os aplicativos Ember. Por padrão ele define um aplicativo chamado frontend
, que será localizado em app/frontend
.
EmberCLI.configure do |config|
config.app :frontend
end
Você pode definir um novo caminho ou até mesmo mapear múltiplos aplicativos.
EmberCLI.configure do |config|
config.app :frontend, path: 'app/ember/frontend'
config.app :admin #=> path will be app/admin
end
Eu sugiro que você defina um caminho como :rails_root/frontend
. Configurar o aplicativo Ember no diretório app
irá impactar na performance no modo de desenvolvimento, porque o Rails irá adicionar todos os arquivos ao sistema de auto-loading, mesmo não sendo usado. Então, neste exemplo eu assumo que o aplicativo Ember está localizado em :rails_root/frontend
.
EmberCLI.configure do |config|
config.app :frontend, path: Rails.root.join('frontend').to_s
end
Para iniciar o Ember, vamos criar um controller/action no Rails. Você pode usar algo como EmberController#bootstrap
. Você não precisa adicionar nada no arquivo app/views/ember/bootstrap.html.erb
.
class EmberController < ApplicationController
def bootstrap
end
end
Perceba que você não precisa especificar o método EmberController#bootstrap
, mas eu gosto da visibilidade que isso fornece. Apenas lembre-se de criar o arquivo em branco em app/views/ember/bootstrap.html.erb
.
Como você pode usar o arquivo app/views/layouts/application.html.erb
para outras coisas que não apenas o Ember, eu sugiro que você use um novo arquivo em app/views/layouts/ember.html.erb
.
<!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>
No momento o ember-cli-rails recomenda usar o ember-cli apenas para o JavaScript; isso significa que você deve usar o asset pipeline para todo o resto, como imagens e arquivos de CSS. Por isso estou usando o método stylesheet_link_tag
em vez de include_ember_stylesheet_tags
.
O Ember tem suporte para history.pushState
; assim, toda vez que você visitar uma rota do Ember, a URL irá mudar, em vez de usar o formato #!
. Você precisa de uma rota catch-all
, so então atualize o arquivo config/routes.rb
para algo como isso:
Rails.application.routes.draw do
root 'ember#bootstrap'
get '/*path' => 'ember#bootstrap'
end
Criando o aplicativo Ember
Tudo o que fizemos até agora foi configurar o Rails. Agora vamos criar o aplicativo Ember. Para isso, use o comando ember
. À partir do diretório raíz do Rails, execute o comando 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.
Você também vai precisar instalar o pacote NPM ember-cli-rails-addon
. Instale-o à partir do diretório do aplicativo Ember.
$ cd frontend
$ npm install ember-cli-rails-addon --save-dev
ember-cli-rails-addon@0.0.11 node_modules/ember-cli-rails-addon
$ cd ..
Vamos ver se tudo está funcionando. Crie um arquivo frontend/app/javascripts/templates/index.hbs
com o seguinte conteúdo.
<p>
Fuck yeah! It works!
</p>
Você também vai precisar do arquivo app/assets/stylesheets/frontend.scss
, que pode ter o seguinte conteúdo:
// @import './frontend/**/*';
Isso signifa que todo o CSS do aplicativo frontend
deve ser colocado no diretório app/assets/stylesheets/frontend
. Lembre-se de atualizar o arquivo config/initializers/assets.rb
, incluindo o arquivo frontend.css
à lista de precompilação.
Rails.application.config.assets.precompile += %w[ frontend.css ]
Inicie o servidor com o comando rails server
e abra o endereço http://localhost:3000
. Você deve ver uma página como esta.
Entendendo o ember-cli-rails
Mas o que exatamente faz a gem ember-cli-rails? Em poucas palavras, ela executa o comando ember
através de um Rack middleware. Quando você visitou o endereço http://localhost:3000
, a gem ember-cli-rails executou o comando ember build
, como você pode ver no 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
Perceba que o processo ember
continuará em background até que você pare o servidor Rails. Isso é muito útil, porque o ember-cli irá compilar apenas quando algum arquivo mudar, tornando o processo muito mais rápido.
Embora esta integração seja muito útil, não significa que você nunca precisará executar o comando ember-cli
diretamente; existem muitos generators que tornarão sua vida mais simples, então é melhor conhecer a API do comando.
$ 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.
Outra coisa que é importante mencionar é que algumas tarefas só podem ser realizadas pelos comandos npm
ou bower
; não existe uma alternativa como tarefa rake.
Então familiarize-se com o ember-cli, NPM e Bower, porque você precisará usá-los eventualmente.
Executando testes
O Ember possui integração com QUnit. Então aqui vai uma dica: use-lo! Caso contrário, você não poderá usar todos os helpers adicionados pelo próprio Ember. Você também encontrará muito mais documentação para Ember e QUnit do que com qualquer outro framework.
Todos os testes do Ember serão carregados de <seu app Ember>/tests
. Quando você criou o aplicativo Ember, alguns testes foram gerados; execute-os com o comando rake ember-cli:test
(à partir da raíz do projeto Rails) ou ember test
(à partir da raíz do projeto Ember).
$ 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
Para executar os testes no navegador, execute ember test --serve
e visite o endereço http://localhost:7357
.
Um problema que você irá perceber é que o CSS da aplicação não será carregado; lembre-se que estamos usando o Rails (Asset Pipeline) para gerenciar imagens e CSS. Uma solução temporária é apontar o CSS para para o seu servidor de desenvolvimento. Apenas altere o arquivo frontend/tests/index.html
, mudando de <link rel="stylesheet" href="assets/frontend.css">
para <link rel="stylesheet" href="http://localhost:3000/assets/frontend.css">
.
Instalando o Ember Inspector
Se você pretender desenvolver com Ember, lembre-se de usar o Chrome com a extensão Ember Inspector. Com ela você consegue inspecionar os objetos criados, ver tempos de renderização, além de muito mais.
Finalizando
Ter um stack totalmente diferente para o seu front-end tem prós e contras. É muito bom ter esta separação quando você tem um desenvolvedor front-end que irá usar o Ember na maior parte do tempo, mas pode ser um problema se você está acostumado com o Rails e seu workflow. Sem mencionar que a configuração se torna muito mais complexa que a descrita no artigo original.
ember-cli-rails é um bom começo, mas ainda é uma ferramenta muito imatura. Em um mundo perfeito você usaria apenas o Rails e asset pipeline. Nada de ember-cli, nada de NPM, nada de Bower, mas eu não acho que isso vá acontecer.
Então, se você está apostando no Rails e Ember.js, acostume-se com o ember-cli e considere usá-lo sem o ember-cli-rails. Assuma que o Rails será apenas uma API e que todo o seu front-end será em Ember, um cliente completamente diferente.