Naming Conventions

Overview

  • kebab-case
    • file names
    • directory names
    • html tags/ember components
    • CSS classes
    • URLs
  • camelCase
    • JavaScript
    • JSON

When using Ember CLI it’s important to keep in mind that the Resolver changes some of the naming conventions you would typically use out of the box with Ember, Ember Data and Handlebars. In this section we review some of these naming conventions.

Module Examples

Adapters
// app/adapters/application.js
import DS from 'ember-data';

const { RESTAdapter } = DS;

export default RESTAdapter.extend({});
Components
// app/components/time-input.js
import TextField from '@ember/component/text-field';

export default TextField.extend({});
Controllers
// app/controllers/stop-watch.js
import Controller from '@ember/controller';

export default Controller.extend({});

And if it’s a nested controller, we can declare nested/child controllers like such: app/controllers/posts/index.js.

Helpers
// app/helpers/format-time.js
import { helper } from '@ember/component/helper';

export default helper(function(){});
Instance Initializers
// app/instance-initializers/observation.js
export function initialize(appInstance) {

};

export default {
  name: 'observation',
  initialize: initialize
};

Note: instance-initializers are loaded automatically.

Mixins
// app/mixins/evented.js
import Mixin from '@ember/object/mixin';

export default Mixin.create({});
Models
// app/models/observation.js
import DS from 'ember-data';

const { Model } = DS;

export default Model.extend({});
Routes
// app/routes/timer.js
import Route from '@ember/routing/route';

export default Route.extend({});

Nested routes as such: app/routes/timer/index.js or app/routes/timer/record.js.

Serializers
// app/serializers/observation.js
import DS from 'ember-data';

const { RESTSerializer } = DS;

export default RESTSerializer.extend({});
Transforms
// app/transforms/time.js
import DS from 'ember-data';

const { Transform } = DS;

export default Transform.extend({});
Utilities
// app/utils/my-ajax.js
export default function myAjax() {};
Views
<!-- app/index.hbs -->
{{view 'stop-watch'}}
// app/views/stop-watch.js
import Ember from 'ember';

export default Ember.View.extend({});

And views, which can be referenced in sub-directories, but have no inheritance.

<!-- app/index.hbs -->
{{view 'inputs/time-input'}}
// app/views/inputs/time-input.js
import TextField from '@ember/component/text-field';

export default TextField.extend({});

Filenames

It is important to keep in mind that the Resolver uses filenames to create the associations correctly. This helps you by not having to namespace everything yourself. But there are a couple of things you should know.

All filenames should be lowercased
// models/user.js
import DS from 'ember-data';

const { Model } = DS;

export default Model.extend({});
Dasherized file and directory names are required
// controllers/sign-up.js
import Controller from '@ember/controller';

export default Controller.extend({});
Nested directories

If you prefer to nest your files to better manage your application, you can easily do so.

// controllers/posts/new.js results in a controller named "controllers.posts/new"
import Controller from '@ember/controller';

export default Controller.extend({});

You cannot use paths containing slashes in your templates because Handlebars will translate them back to dots. Simply create an alias like this:

// controllers/posts.js
import Controller from '@ember/controller';
import { alias } from '@ember/object/computed';

export default Controller.extend({
  needs: ['posts/details'],
  postsDetails: alias('controllers.posts/details')
});
<!-- templates/posts.hbs -->
<!-- because {{controllers.posts/details.count}} does not work -->
{{postsDetails.count}}

Tests

Test filenames should be suffixed with -test.js in order to run.

Pod structure

As your app gets bigger, a feature-driven structure may be better. Splitting your application by functionality/resource would give you more power and control to scale and maintain it. As a default, if the file is not found on the POD structure, the Resolver will look it up within the normal structure.

In this case, you should name the file as its functionality. Given a resource Users, the directory structure would be:

  • app/users/controller.js
  • app/users/route.js
  • app/users/template.hbs

Rather than hold your resource directories on the root of your app you can define a POD path using the attribute podModulePrefix within your environment configs. The POD path should use the following format: {appname}/{poddir}.

// config/environment.js
module.exports = function(environment) {
  let ENV = {
    modulePrefix: 'my-new-app',
    // namespaced directory where resolver will look for your resource files
    podModulePrefix: 'my-new-app/pods',
    environment: environment,
    rootURL: '/',
    locationType: 'auto'
    //...
  };

  return ENV;
};

Then your directory structure would be:

  • app/pods/users/controller.js
  • app/pods/users/route.js
  • app/pods/users/template.hbs