Components structure in Ember.js

Maciej Kwaśniak
Macsour
Published in
4 min readDec 11, 2018

--

Photo by Alexandre Debiève on Unsplash

Before you start:
Make sure you are already familiar with components patterns

Ember.js is a framework that uses a lot of patterns and is conventions oriented. Fortunately, it’s also flexible. A lot of things depend clearly on developers, what sometimes can bring unexpected consequences. Very often fixing those issues is not an easy thing, and can change our mind about Ember because of its limitations. The truth is, hacks are not going in pair with conventions.

One of the first places where developers make this kind of mistake are components. They start to build their projects by adding new blocks, very often even without thinking about architecture, how this will be reused in the future and how flexible it will be. Today, components are super crucial parts, and their structure should be thought well. Thanks to it, you will be able to easily use them, navigate, they will be more flexible, and isolated. Good patterns in this field will allow you to develop maintainable applications and keep up with rapidly changing business requirements.

Have you ever reached a moment where your app was so big that you had to split it? Thanks to using conventions in components structure this operation will be much easier to achieve.

Disclaimer:
Those patterns may not work for the angle brackets components and after Module Unification implementation

Photo by chuttersnap on Unsplash

Naming

This is a pretty important thing in components structure. It allows you to determine a purpose of a component so you will know if it’s used in a way it is meant to be.

We can determine 3 types of components:

1. Public

Public components are named as a normal component and can be accessed anywhere.

Example:

app
└── components
└── user-profile

Usage: {{user-profile}}

2. Internal (Private)

Internal (private) components have a prefix char - (dash), so you can see that this component was not meant to be used outside of its scope or you should be careful with using it. It’s very useful if you have a big complicated component and don’t want to expose underneath layer.

Example:

app
└── components
└── user-profile
└── -avatar

Ideally, you should only use internal components in the scope of its parent, so in case of a big components tree, you can easily tell which of them you can or can’t call directly.

Usage: {{user-profile/-avatar}}

3. Abstract

These components can be used mostly for extending other components (used as a base). So, you can create a component file but this component cannot be called in a template. Perfect as an abstract layer.

Example:

app
└── components
└── user-profile
└── fields
└── _base

The usage will look like: {{user-profile/fields/_base}} however, this will be omitted and not be rendered anyway.

Photo by Ilya Orehov on Unsplash

The Structure

Okay, so you already know what kind of name you should use. Now, you need to get to know how to structure it. I propose to use those 3 levels:

NAMESPACE
└── PURPOSE
└── MY-COMPONENT

1. Namespace

It can be a business logic part (eg. dashboard) custom namespace (eg. shared) or resource name (eg tasks). First, you will probably build components for resources and maybe use shared namespace for non-related things. After that, you will shape bussines logic namespaces like the dashboard and settings.

2. Purpose

  • parts
    All components that will serve you as parts to build UI elements. They shouldn't contain any layout markup, should work with custom data and be flexible enough to modify them easily. Mostly those are composable or container components.
  • ui
    Components that are a wrapper for parts and build a layout of the application. Ready to use in routes templates, almost out-of-the-box. They contain proper styling and maintain data. You can call it a public interface of your components.

3. Component

And finally, here you can create your components and choose a correct name and pattern for them.

Example

app
└── components
├── tasks
│ ├── parts
│ │ └── tasks-list
│ │ └── -item
│ └── ui
│ └── todo-list
└── shared
└── parts
└── form-builder
└── -fields
├── _base
├── input
└── textarea

Looks cool, right? But wait! There is a disadvantage. Your components name will get longer, right?

From tasks-list/item now we got tasks/parts/tasks-list/-item . Well, yes. But look how much information you have.

  1. You know that this is an internal component (not meant to be used outside of tasks-list.
  2. Its parent is composable, not containing layout (as it’s in parts )
  3. The whole thing is related strictly to tasks namespace.

What’s more, if you use components patterns correctly you will use full names rarely as you will call most of them through the block of the contextual component.

Thanks to the correct naming and structure it will be much easier for you to build, maintain and refactor this important segment of each app.

Hire me as your next frontend engineer!

Check out my projects, experience, and ask me a question on macsour.com

--

--