How to move from Ember-Rails to Ember-CLI
TL;DR; Make use of sprocket's ES6 precompilation and few ember-cli libraries to put in place a hybrid ES6 module - Globals App for incremental transition to ES6 modules.
So you want the magic of Ember-CLI?
Well, you came to the right place. I am going to be documenting how to move over a large Ember-Rails app to Ember-CLI. Before you start reading too far, Yeah, it's going to take awhile.
So since a "stop the world" for refactoring was probably not on the table, I got creative: Let's have a hybrid globals and ES6 module approach for incremental conversion.
Before we start though...
Take a look at ember-cli-migrator. It didn't work for us, but it sure as hell might work for you and save you a ton of work.
Bower > Asset Gems
Bower is going to be your new best friend. If you don't know what bower is, I recommend you watch a bower tutorial and check out bower's website.
This write up is about getting you started with the smallest amount of effort, so the packages you will need are:
I highly recommend migrating your assets/asset-gems used exclusively by your ember app to bower as soon as possible. This includes Ember and Ember-Data (though
ember-rails has a dependency on it
ember-source, so you may want to wait).
But what versions do I use?
versions are changing quickly, so what version you may need will depend on what version of Ember you are running and what version of Ember-cli you are targeting to move to. Take a look at the ember-cli repo, and under
blueprints/app/files/bower.json will have various versions.
bower.json is ready to go,
One more thing...
bower_components path to sprockets so you can start requiring files from there.
# config/application.rb or config/environments/*.rb # snip... # use bower directory path config.asset.paths << Rails.root.join('bower_components') # snip...
Setup The File Structure
Your Ember Rails app is probably structured like this and is under
Finished? Good. Now create a new folder under
This will allow you to start conforming to Ember-CLI naming conventions.
ES6/ES2015/ insert new name here Modules
I'm not going to spend anytime here explaining ES6 modules or syntax, as there are many more, well qualified sources out there. I recommend you start at http://jsmodules.io/ or with this blog post.
Housekeeping time. In your
Gemfile add the following, and
gem 'es6_module_transpiler-rails' # if you use coffeescript, do this too gem 'sprockets-es6-coffee'
Now a new initializer:
This will essentially help craft your module names. Remember, ES6 modules are not supported in the wild right now. Under the covers they are getting transpiled into AMD modules, which are then loaded by loader.js.
The only thing you should care about is that the module names should come out to be something like
<your app name>/models/user. If you are ever unsure of your modules names, you can check
requirejs.entries, where loader.js stores a dictionary of the modules.
Anything with the extension
js.es6 will be transpiled. add
.coffee to the end if you need to use coffeescript, and make sure to wrap those imports and exports in backticks.
Is it conversion time yet?
Before you jump head first into conversion, you are going to need a custom resolver that will resolve classes from both globals and AMD modules. You can go take a look at either the Ember-CLI resolver or extend Ember's default resolver, but I am going to do you one better:
WARNING: I would be weary of using this without regression testing.
This extends Ember-Resolver from Ember-CLI, adds a global resolver method and a
resolveTemplate method that resolves templates compiled to
Ember.TEMPLATES, including the
barber gem. Since the Ember CLI Resolver extends
Ember.DefaultResolver, I actually don't know if you need to use the
resolveGlobal method. I recommend diving into the resolver code a bit and seeing what meets your needs.
Tips from the Front Lines
Convert Simple, but Vital Files First
This gives you the benefit of failing fast™, so you know if things are really broken before handing them over to QA or worse, merging them. Some examples of simple but vital might be custom transforms, models, components, ect.
Don't be afraid of the source code
The source for Ember.DefaultResolver and Ember Resolver aren't that complex if you know even a little bit about the container. Hopefully you won't need to dive into it more than I did.
Dasherize your file and folder names
Ember CLI's site says to do it. so just do it.
Note: Ember-Qunit >=0.1.8 will not always play nicely with dasherized file names.
Create a strategy with your team to convert files
I implemented a "touch the file, convert the file" rule for new pull requests. It's had it's bumps, but has been relatively successful. Depending on how much free time you have between features and how fast you want to move fully over to Ember CLI will determine a good strategy for your team.
Handle any deprecations along the way
I'm looking at you, global lookup of views in templates. Also, all helpers and components should have a dash in the name to make your life easier.
When migrating, make sure to reference the Ember Deprecations Guide.
Use the hacky require sparingly
If all else fails, use
require to bring a converted module back into the global namespace. Use this when you have so many places the global is referenced directly that converting over all the files in one shot would be tough. Don't let it allow you to get lazy though
// old-app/models/user.js var App.User = require('new-app/models/user')['default'];
Just get started
The resolver will probably fail. You will probably forget to name your export and realize it 30 minutes later. But you gotta start somewhere. We all know your PM isn't going to give you 3 weeks to migrate over the code. Get to it!