Ember Rails to Ember CLI Migration Path


#1

We have an application on Ember Rails and would like to migrate it to Ember CLI. One of the biggest motivations for this is the page reload time during development is taking longer and longer and hamstringing development and testing.

After seeing this article on the subject we’ve been inspired to attempt this migration again, but would like to do it incrementally. These are the steps I am envisioning where we can still pass our integration tests after each step:

  1. Globals to ES6 Modules: separate our global objects out into their proper module file paths, and begin to use the es6 syntax.
  2. Organize our files into the “standard” structure and into “pods” where either pattern makes sense in our app
  3. Move the Ember application outside of rails and use a new deployment scheme that allows this separation of the rails api and the ember front end

Is it possible to do this incrementally, or will the migration have to occur all at once? Is this a reasonable set of steps, and would you add any? After poking around the ember discussions and SO I haven’t seen a place to discuss this comprehensively, so I’m hoping it can help others while Ember Rails projects still exist in the wild.

If this seems reasonable, I would be interested in learning more about how to accomplish step #1 and #2 as it would require the es6 transpiler and the ember/cli resolver, which I’m not sure you can simply place into the rails project.


#2

On Pods: You can migrate your app from standard to Pods piecemeal or all at once, the new resolver can handle both structures. I’m not sure if the more traditional structure will go away, but I think everyone’s moving to Pods right now.

Modules: You do need to use ES6 modules though, since the new resolver’s semantics depend on that.

I do suggest you consider using Rails solely as an API and use Ember CLI to handle its builds and deployment.


#3

I’m giving a talk on this topic in like 2 hours haha. All my current projects are JS only, but I’ll ask around Rails Devs what are they doing to tackle this right now.


#4

So I do want to use the transpiler and the resolver, but I don’t want to migrate the entire code base to CLI all in one go. I’d like to move global Ember application objects into the module and pod structure one at a time, run tests, make sure they pass. Then, start moving handfuls of the objects. Then, within the Rails project, I’ll have the entire folder structure and everything written in modules, so that I can simply copy that folder structure into CLI and then make the big leap of the migration into CLI without having to fiddle with all of the small code changes I will need to do just to get into the module and pod form.

This seems like it would require somehow brining the es6 transpiler into Rails first (without Ember CLI, which I think can be done) and then also bring in the Ember CLI resolver into Rails first (without Ember CLI, which I have no idea how to do, or if it can be done.)


#5

You may want to use https://github.com/fivetanley/ember-cli-migrator by @fivetanley so you don’t have to whittle the code all by yourself. It looks awesome judging by tonights presentation.


#6

That actually looks like a really cool project, thanks for the reference. Unfortunately in our case, our code would require much more massaging to get something like that to work (we have globals grouped together in the same files, and have other code smells that we want to clean up at the same time we move to modules.) I’m still looking for an incremental solution where I can manually step through a migration.


#7

We’re at the tail-end of one conversion and the start of another. There is a good amount of stuff to do, however, we completed the conversion in a week.

We broke it into 4 basic phases

  1. Restructuring the rails project to match the structure of an ember-cli project
  2. Creating the basic ember project with all the dependencies that we need
  3. Moving all front-end code over to the ember project
  4. Removing all front-end code from the rails project

Interestingly enough I believe the second is probably the biggest because it requires that we make sure all our libraries, and addons (that includes custom addons that we’ll need to create) are in the project.

Restructuring the rails project to match the structure of an ember-cli project

This is all about matching the file names and folder structure. For example some of our files had both the route and controller in the same file. This will need to be separated. It will also need to be renamed to match the right conventions for the resolver. Especially because we aren’t naming the object inside the file anymore (when it’s in ember-cli) but instead it’s based on the name.

We’ve opted for the pod structure from the beginning and so we continued using that. However we ended up making a couple of minor changes to the folder structure that I may put together in more detail at some point.

Creating the basic ember project with all the dependencies that we need

Here is where we create a brand new ember project and pull in any dependency that we need. For us that means

  • ember-validations
  • semantic-ui-ember
  • ember-json-api
  • ember-document-title
  • ember-simple-auth

But it also means our own extensions that we need to create custom addons for including

  • ajax
  • current-user
  • errors
  • generators
  • schema

You should have the basic working pieces of an app here with some testing routes before you start pulling application code over. Making sure you can call the api, validate things, titles get mapped, etc. It’s easier to test the basic working parts in this phase than we you have half of your application code ported over.

Moving all front-end code over to the ember project

Since we already renamed the files in the first step this phase is pretty mechanical and we use generators to build the structure with a simple copy. Goes like this

ember g route user/login

Open pods/user/login/route.coffee and take everything to the right of the object name

App.UserRoute = Ember.Route.extend(App.SomeMixin, {
   // user code
})

and put it into our newly generated route

import Ember from 'ember'

UserRoute = Ember.Route.extend(App.SomeMixin, {
   // user code
})

export default UserRoute

At this stage any objects you’re referencing such as “App.SomeMixin” will need to be pulled over and referenced properly as an ES6 module. We follow the tree, generate the mixin, copy the code and then reference it properly within the file.

Removing all front-end code from the rails project

This one is pretty easy. Drop all the existing code from the rails project, make sure all the API bits are intact. Call it good.


#8

This is great Nathan! Exactly what I’ve been thinking, as well, glad to see you guys were able to do it in such a short time frame. Thanks for the thought out reply.

I’m thinking step #2 will be most difficult, as well. For us this will also have a sub step of moving from ember-devise-simple-auth to ember-simple-auth which have different authentication schemes. We would like to keep using the former, but I have had trouble getting it to work in cli and I don’t think the project will continue to be supported, while ember-simple-auth looks like it is becoming de facto. Did you have alter an application code like this when you migrated?

We also have controllers and routes grouped together in the same files. I like the idea of mimicking the folder structure while still keeping the globals pattern, and then when you move the files over you can then begin the migration to modules.

Overall though, it looks like you can’t bring in the resolver and transpiler into rails first to get everything in module and pod structure, but rather make that conversion when you move the objects into the ember folder?


#9

I don’t think authentication is solved yet to be honest. We used the standard rails cookies for authentication right now and write out <meta name="current-user"> into the html to signal that there is an active user. The common convention with ember-cli seems to be more token based requests which sends an authentication header with each xhr request. That’s fine for ajax requests but doesn’t cover things like images and files that are clicked directly. In our converted project we’re using a combination of cookies and token but will be revisiting it soon.

This is why I suggest you create the barebones ember project and get the basic building blocks working before you start porting application code. You need authentication, cross-origin concerns, api and serializers, deployment, etc. These are all blockers and once you start porting code you start a timer where the rest of your team (assuming there are multiple) can’t modify those files without potentially losing changes or having to port them a second time.

I find the import's and module system to be pretty easy when you are copying code and ember serve will throw an error if an object isn’t found. File by file conversions you should be able to resolve any import as you go along.