When building an addon, why use the `addon` folder?


#1

When generating code for an addon (eg. ember generate component foo), Ember CLI will typically create files for both an addon and app folder. Typically, the file in the app folder will just import/export the file from the addon directory. So why follow this paradigm? When looking at mature projects such as liquid-fire, we see a lot of code added directly to the app folder with no corresponding code in the addon folder. Why might the developers of that project have chosen that architecture in some situations, but not all?


#2

Namespacing and easier to extend functionality. Since the addon’s app folders get merged into your consuming app, you’ll have a hard time in cases where you want to extend functionality if they’re not available on the addon’s namespace.

We’ll use some live-code as an example:

If I did not have all the logic contain inside of my addon’s namespace, any consuming app would find it difficult to extend the service. You would need to create a second service that extends from ember-intl\services\intl.js or reopen to class somewhere which would make debugging interesting trying to track down where your class is mutated. Instead, now the consumer app can just create their own app\services\intl.js which would look something like:

import IntlService from 'ember-intl/services/intl';

export default IntlService.extend({
  adapter: Ember.computed({
   get() {
     // override behavior
   }
  })
});

For things I do not import from my addon folder into app, are usually private utility methods or private classes.


#3

Those are great reasons to put logic in your app folder, but why put anything in your addon folder in the first place? I’ve encountered a few situations where it makes sense to have something in your addon folder but not your app, such as a mixin that’s only used by files in your addon. But what about addon files that have a corresponding app file like:

export { default } from 'ember-intl/services/intl';

Why not just put the contents of intl directly into the app file?


#4

I explained why, I guess I wasn’t clear. Isolation under a namespace that doesn’t get merged with app and the ability to extend functionality in a clean way.

Just answer this question, if you had an app and lets say I had implemented the service entirely under app/services/intl how would you extend it to implement some custom logic? You can’t just create app/services/intl because now my default implementation of IntlService is overridden (app wins out in the addon app’s tree merging). You would be forced to import the app/services/intl somewhere within your app and reopen. That’s confusing and would be a maintance nightmare trying to track down everywhere you reopen.


#5

So it’s principally for extensibility? That makes sense. I’m still curious why an established project like liquid-fire would sometimes put components directly in their app folder like this. Perhaps it’s a way of saying, “Don’t extend this”? Either way, thanks for taking the time to explain this.


#6

FYI - Liquid Fire has existed as an addon since before there was an ability to use addon/ folder. Most likely that is why it doesn’t follow the now default pattern in all cases.


#7

To reopen an old thread…

Is this genuinely the only reason we should use the addon directory, to ensure we can extend things?

I’d rather encourage composition so it feels to me that this is a reason not to use the addon directory. Would there be any downsides asides from not being able to extend / use the same names as things my addon includes?