Best practices for Component Folder structure?

I am new to ember and from react background. Categorising components in react is flexible, want to know how the same is done in ember.

Considering the following types of components that present in every app

Stateful/Stateless Components - UI components like Buttons 
Container/Presentational Components - Like App container, Body container
Higher Order Components - Parent of every page/route 
Contextual Components - Specific to pages

Currently I have categorised the components into 3 types:

  1. Containers - A container component that has nested divs that are used across multiple places in app. Instead of using those nested every-time, they are constructed as a component and the children are yielded here.
  2. Pages - All the child elements of every route/page will be here and this component will be rendered in specific route template.hbs.
  3. Ui-elements - All the Elements/Components in the app, which are not specific to page, and that may-or-may not be reusable.

Is it a good approach, How does complex applications architecture their app?

Thank you

2 Likes

Hi @SarathSantoshDamaraj, I’m not sure how well I can answer your questions directly but hopefully I can give you some pointers in the right direction. My React knowledge is all academic or theoretical so forgive me if anything doesn’t sound right.

First off, @NullVoxPopuli gave a talk at EmberConf last month comparing patterns between React and Ember (video here, slides here). Definitely worth a watch and might be helpful for some context.

From what I understand, some of the “component types” in React were conceived to deal with the fact that everything in React is a component, and that state management is generally (flux/redux/etc) managed in a different, somewhat segregated way. In Ember there are more constructs for dealing with state and application architecture so these component categories might not all be necessary or useful, at least in the sense that they would be in React.

For example in Ember we have the Router and Routes as first class primitives. A route is made up of a route js file, a corresponding template, and generally a controller. In React you might have one or more components that perform the same functions. In the classic Redux sense your route controller and template might replace the “Container” component that deals with data/state and render “Presentation” components which can be reused across the app/other apps. The route/controller “own” the model and then, in the data flow that we call “Data Down Actions Up” the route model (and controller state) and actions will be passed down to the presentation components, which will invoke the actions to mutate the data. This establishes a clear one-way data flow, not dissimilar to Flux architecture. In general I prefer to write a route template and wait to extract components until there is repetition or clear separation of concern between UI elements, but that’s just my 2c.

Another thing that can replace the need for some of the higher order or provider components is Ember’s “Service” construct. A service is a singleton that can contain properties, methods, etc. and can be injected into any component/controller. The Ember Data store is a service, and common addons like Ember Simple Auth use services as the primary way of sharing authentication state with the app. Because a service isn’t a component it doesn’t need to live in the component hierarchy, it can just be used when and where it is needed.

As far as I’m aware Ember Data is quite different from the way data management is typically done in the React ecosystem. Ember Data is concerned mainly with data from an API/backend/source of truth, and doesn’t concern itself with component state (which, from what I understand is different from Redux where your application state and “backend” data would all be in the same store, again though I’m not an authority on that). Data is typically loaded in the model hook of a route, and kept in the store. Each record is not just an instance of your a model but also a complex object with it’s own “state machine” more or less that tracks changes, saved/in-flight/unsaved status, etc. Ember Data is very powerful, and highly customizable. Anyway I guess the real point is that because it’s accessed via the store service and generally used in Routes, you don’t need extra stuff in your component hierarchy for data fetching either.

Oh and as for folder structure, one of (IMO) the great parts about Ember is that it follows strong conventions so you don’t have to worry too much about your source file tree structure. This “classic” layout will be changing fairly soon with what we call “Module Unification” which is a new default file structure, but the way the Ember currently organizes source is just in /app with subdirectories for templates, routes, components, helpers, etc. It’s possible to nest routes (there are rules of thumb about why/when you should do this) and also possible to have component directory trees but that is less common in my experience. So all that to say, you don’t need to worry all that much about your file structure, the app architecture (route hierarchy, good component design patterns) is much more important.

Hope some/all of that makes sense and is helpful. There might not be clear analogs between Ember and all of the React concepts, but there’s probably a tool that accomplishes the same thing. Maybe someone with more React experience can weigh in with a better comparison.

EDIT: oh and I think you’re definitely on the right track with your approach. Again I’m not a proponent of abstracting components out too soon, but YMMV. The best use-case for extracting a component from a route template is obviously a reusable piece of UI, but also any containers that will organize their own child components or that you want to render container elements. And of course any code/UI that fits together in a natural way. Leveraging services where appropriate can keep your component hierarchy nice and clean.

5 Likes

I’m working on a blog/guide “ember for react developers” I should be done a week or so, I’ll be sure to post it.

@dknutsen’s overview of ember is very good :slight_smile:

Be sure to go over the guides / tutorial, they’re also very good.

Also be sure to hop in the ember discord if you haven’t already - sync chat/support is great :slight_smile:

2 Likes

That sounds awesome, looking forward to it!

1 Like

Thanks @dknutsen for the detailed explanation. As you have mentioned about the component design patterns, are there any good patterns to handle different components or all the types of components should be direct children of app/components/. I feel it would be good to have some separation of components. I feel with out this components folder looks pretty messy with hundreds of Components.

Great!! Looking forward for it.

Yeah hundreds of components would definitely get out of hand. You have a few options:

  1. subdirectories: say you have a component called “bar-chart” and you could put it in components/foo/bar-chart and then use it in a template like this: {{foo/bar-chart ...}}. I think there might be caveats to doing this with Angle Brackets but I can’t remember offhand. You could organize these subdirectories by type, or function, or whatever you want really. The main downside is that component invocation becomes more verbose.
  2. Use pods structure. Pods was a more experimental file layout where “unit” files (e.g. a component and its template, or a route and its controller and its template) are co-located. It will be replaced by module unification eventually, but is totally usable in the meantime. I think you can nest components with this structure but honestly can’t remember.
  3. Try to use module unification WIP. This might be most natural and it will be fairly future proof, but you also might run into bugs or roadblocks since it is not a fully implemented concept yet.
  4. Organize your components into addons (either in-repo or separate). At my company we have a UI toolkit library with basic building blocks like buttons and cards and stuff, and then more project specific addons that contain components that we want to reuse across apps/engines but that also have more app-specific business logic or look/feel. There was a recent thread about building a UI toolkit that might be of interest.
  5. Look into engines. Engines are kinda like “mini apps” that are fairly isolated and can be mounted either as routes or without routes like a component (routable vs routeless engines). They can contain their own components so you could break a complex app into a series of engines that compose together to form a single app. LinkedIn uses a ton of engines. We have one of each type at my company and they work pretty well for isolating and organizing pieces of an app. Only caveat is that they are another concept to learn and configure and while fairly well supported they are still technically a “beta” feature.
1 Like

Regarding components in subdirectories and angle brackets, angle bracket invocation of nested components is now supported via ember-angle-bracket-invocation-polyfill (back to Ember 2.12) and will be native in Ember 3.10.

2 Likes