24

I'm trying to migrate to ember-cli from some old homegrown build tools. Our app is quite large and is actually split into several ember.js single page apps (e.g. index, admin, reports, etc) that share a common set of utils and components.

I'm trying to figure out if that's even possible with ember-cli and if so, how do I do it? I saw some people talking about pods, others talking about addons and yet another set of people talking about private bower repos. I tried finding out information on each of these, but it seems it's all in a bit of flux.

I'm not picky about the directory structure or the details. But I guess this is how I would envision it:

[app]
  - [controllers]
  - [models]
  - [routes]
  - [views]
  - index.html
[admin]
  - [controllers]
  - [models]
  - [routes]
  - [views]
  - index.html
[reports]
  - [controllers]
  - [models]
  - [routes]
  - [views]
  - index.html
[shared_code]
  - [components]
  - [utils]
Brocfile.js
etc

Any advice would be greatly appreciated. Even just a starting point would be immensely helpful.


Edit (Jan 28th 2015):

Ember-cli addons are more stable now and could be used for this application. But IMHO they still have some short comings for this use case. They create more boiler plate as you still have to import individual models/controllers/components/etc into your application space. See the "Components" section under the addons here: http://www.ember-cli.com/#managing-addon-dependencies

There is also an interesting RFC to bring engine like support to ember and ember-cli that could satisfy this as well: https://github.com/emberjs/rfcs/pull/10


Edit (October 3rd 2015):

There is a new update to the Engines RFC and that looks promising for many users. However, we still have the need for multiple apps which are actually different. Another developer I work with spent sometime to flush out the details of how best to use this pattern.

I've documented that and created demo in a repo: https://github.com/workmanw/ember-multi-app

Wesley Workman
  • 917
  • 9
  • 22
  • So Wesley, what did you decide to do in the end, as I'm thinking about this problem now too (http://discuss.emberjs.com/t/sharing-models-via-ember-cli-addons/6311/2) – cjroebuck Sep 26 '14 at 07:39
  • @cjroebuck I see your discuss post, that's exactly what I was trying to do. At first I was able to just make two EmberApp instances and a third tree with my common files in my Brocfile.js, then use merge-trees to get them all working. But the current volatility of ember-cli proved too much for now. So I punted and used pure broccoli. I hope to move back to an ember-cli solution once it's more stabilized. – Wesley Workman Sep 30 '14 at 14:19
  • @cjroebuck Also, I think there is a clear need for this behavior. Hopefully it'll become an easy function of ember-cli in the future. – Wesley Workman Sep 30 '14 at 14:19
  • 1
    I've gone down the ember-addon route at the moment, so all my common code is in the 'common' project which is an ember addon that I add to both of my apps, using npm link in dev - it isn't so bad so far, but I agree it would be nice for this workflow to be officially supported by ember-cli as an actual use-case. – cjroebuck Sep 30 '14 at 20:12

2 Answers2

3

Ember-cli doesn’t support multiple apps out of the box. (By the way, I am still amazed how many things that were common in SproutCore are still problematic with Ember). The pods you mentioned are supported by tools which ember-cli depends on, so most of the ember-cli commands will work fine. The way resolver (an ember-cli dependency) puts everything together is described in its pull request. But you won’t be able to use generators because they are not aware of pods yet. Ember addons mostly extend ember-cli or Ember itself, although they may be able to solve your problem, they are not the right tool.

I think the best thing for you is to wait for more pods aware ember-cli commands or to implement this feature to ember-cli yourself.

The next best thing is to actually split your project into multiple projects, one per app, and include shared code via Bower, NPM or other solution. They all usually allow to import dependencies via git or file system if you have your own private components. You might have a super project where everything goes together (via NPM or Git submodules) and where you’d still have some homegrown solution to orchestrate everything (by basically delegating it to ember-cli).

F4-Z4
  • 679
  • 6
  • 12
  • ember-cli addons are new and a great way to share original code across projects. Worth checking out. – Sam Selikoff Jul 18 '14 at 16:34
  • @SamSelikoff I agree, I just don’t think they are for apps. They are great for code shared among numerous apps, something more general. – F4-Z4 Jul 18 '14 at 22:50
  • definitely, not for apps. but if he takes the approach you suggested of separating out into different apps but wants to share some code, they could use addons. – Sam Selikoff Jul 18 '14 at 23:22
  • 3
    Sorry to chime in late. I did try to use addons with `npm link`, but they didn't fit the need, it really felt like I was swimming upstream. To start, they are "unwatched", changing addon code doesn't trigger app rebuilds. Secondarily, they end up sandwiched under the app resolved path. So "my-addon/controllers/alpha" becomes "app/controllers/alpha" ... potentially resulting in conflicts. Last, I wasn't able to simulate production. What was "/", "/admin", "/report" in prod became: "localhost:4200/", "localhost:5200/admin", and "/localhost:6200/report" respectfully. – Wesley Workman Jul 19 '14 at 04:11
  • All of that said ^^, I appreciate your response. At the very least I was able to acknowledge I was not alone. I too am an "old SproutCore guy". There are definitely things I stumble on and flash back to how SC use to handle it. But all in all, with the Router, Templates, Promises, Resolvers, etc; I would still take EM over SC every day of the week. – Wesley Workman Jul 19 '14 at 04:13
1

If you must accomplish multiple apps with Ember CLI, per your 2015/1/28 edit, you'll want to wait for more pod support, or engines.

Consider however the naive DIY solution here: make your n separate Ember apps into n separate Ember CLI apps. Serve them yourself in a single superproject.

Disadvantages

As with your investigation into addons, you will have repeated boilerplate, package.json, environment.js, etc. You will incur the overhead of maintaining each app's Ember, Ember CLI, etc. versions separately. You will have to create a way yourself to serve them all in a superproject. Even if multiple apps are on the same library version, clients will likely have to download duplicate vendor.js code.

These are strong disadvantages you'll have to weigh.

Advantages

  1. You keep your current code organization.

  2. You must be disciplined about the code you extract for sharing.

    "Duplication is far cheaper than the wrong abstraction." In the world of dynamic JavaScript, where anything goes in the type system, and everybody has a different module implementation, abstracting/extracting too early gets you into trouble. When shared code is carefully extracted into a separate library—perhaps using the Rule of 3—it results in a higher quality microlib. The lib's maintenance can be focused on optimizing just the shared functionality, and its backwards-compatibility. You might not get that if the shared code remains in your app, employed via import spaghetti.

    As with frzng's answer, "include shared code via Bower, NPM," and Ember addons.

  3. The tech debt of one app doesn't corrupt another app.

    This is good particularly in the Ember ecosystem. Even though its motto is "stability without stagnation," new Ember patterns come out every day. Want to try one of those bleeding edge Ember techniques, but don't want to spend time upgrading your entire Ember monolith? Upgrade just one smaller app instead!

    I've worked with a massive Ember app whose tech debt in small areas prohibited upgrading the entire app. With this scheme, don't need to say no anymore.

    (Halting the spread of tech debt is part of why microservices are so popular lately. Many small Ember apps could be called a microservices approach.)

The Superproject

Organizing

You can explore Git submodules (*shudder*) subtrees or NPM artifacts. You'll jump through hoops to keep them all in sync.

In my situation, it doesn't make sense to run 1 app without the others. I've had success with a monorepo.

Serving

My URL scheme worked for the Unix philosophy-like separation of my Ember apps. Each could be served by a single server, but each grouped under a logically separate context path. For example, all requests to /app1/* get routed to app #1's compiled index.html. All requests to /app2/* get routed to app #2's compiled index.html. And so on. Ember takes over routing from there.

You might be able to do the same with /index/*, /admin/*, and /reports/*.

To mount these apps to their various public URLs, add some metadata in each's package.json to tell the server how. On startup, the server loops through the metadatas, and dynamically generates web framework routes.

for packageJson in packageJsons:
    path = packageJson.contextPath                               # e.g. '/app1/*'
    indexHtml = packageJson.abspath.dirname + '/dist/index.html' # Ember CLI's conventional location

    # Dynamically mount the route.
    # Normally you'd hardcode your routes, something like  
    #     yourWebFramework.GET('/hello', echo('Hello world'))
    yourWebFramework.GET(path + '/*', serveStaticFile(indexHtml))
Community
  • 1
  • 1
Bluu
  • 5,226
  • 4
  • 29
  • 34