We spend a lot of time writing code. In the early phases of a project, the directory structure doesn't matter too much and many people tend to ignore best practices. In the short term, this allows the developer to code rapidly, but in the long term will affect code maintainability. AngularJS is still relatively new and developers are still figuring out what works and doesn't. There are many great ways to structure an app and we'll borrow some principles from existing mature frameworks but also do some things that are specific to Angular.
In this article, I will cover best practices regarding directory structures for both small and large AngularJS apps. This may be a hot button issue with some developers and while there is no "perfect" way to structure an app, I will be writing from experience and lessons learned from projects I've worked on.
First of all, let's go over what not to do. Many AngularJS tutorials show an app structure that resembles the code below:
app/ ----- controllers/ ---------- mainController.js ---------- otherController.js ----- directives/ ---------- mainDirective.js ---------- otherDirective.js ----- services/ ---------- userService.js ---------- itemService.js ----- js/ ---------- bootstrap.js ---------- jquery.js ----- app.js views/ ----- mainView.html ----- otherView.html ----- index.html
This is a very typical app structure that I see. On the surface, it seems to make a lot of sense and is very similar to a lot of MVC frameworks. We have a separation of concerns, controllers have their own folder, views have their own folder, external libraries have their own folder, etc.
The main problem with this directory structure is not apparent when you are working with only a handful of views and controllers. In fact, it is preferable to follow this approach when writing a tutorial for example or for smaller application. This structure makes it very easy for the reader to visualize and conceptualize the concepts you are covering.
This approach falls apart, however, when you start adding additional functionality to the app. Once you have more than 10 controllers, views and directives, you are going to have to do a lot of scrolling in your directory tree to find the required files.
For example, say you are building a blog with Angular. You decide that you would like to add the author information to the bottom of each article. Well now, you have to find the blog directive, controller, potentially the service and finally the view before you can even look at the whole picture and start making edits.
Say a few months down the line, you are adding additional features to your blog and want to rename a particular feature, again it's a hunt throughout the directory structure to find the affected files, edit them, make sure they are all in sync, and then make the changes.
A Better Structure and Foundation
Let's get to best practices and what you should be doing to build scalable and maintainable AngularJS apps that your coworkers will love you for. An ideal AngularJS app structure should be modularized into very specific functions. We also want to take advantage of the wonderful AngularJS directives to further compartmentalize our apps. Take a look at a sample directory structure below:
This directory structure is much harder to read and understand from the get go. A newcomer to Angular may be completely turned off by this complex approach, and that is why you see tutorials and examples in Angular following the simpler directory structure found in examples earlier. Let's dive into the directory structure above and see what's going on here.
The index.html lives at the root of front-end structure. The
index.html file will primarily handle loading in all the libraries and Angular elements.
The assets folder is also pretty standard. It will contain all the assets needed for your app that are not related your AngularJS code. There are many great ways to organize this directory but they are out of scope for this article. The example above is good enough for most apps.
app.module.js file will handle the setup of your app, load in AngularJS dependencies and so on. The
app.route.js file will handle all the routes and the route configuration. After that we have two subfolders - components and shared. Let's dive into those next.
components folder will contain the actual sections for your Angular app. These will be the static views ,directives and services for that specific section of the site (think an admin users section, gallery creation section, etc). Each page should have it's own subfolder with it's own controller, services, and HTML files.
Each component here will resemble a mini-MVC application by having a view, controller and potentially services file(s). If the component has multiple related views, it may be a good idea to further separate these files into 'views', 'controllers', 'services' subfolders.
This can be seen as the simpler folder structure shown earlier in this article, just broken down into sections. So you could essentially think of this as multiple mini Angular applications inside of your giant Angular application.
shared folder will contain the individual features that your app will have. These features will ideally be directives that you will want to reuse on multiple pages.
This allows us to have definitive components for our site so that a slider will be a slider across the site. You would probably want to build it so that you could pass in options to extend it. For example, you could have:
<!-- user a slider directive to loop over something --> <slider id="article-slider" ng-repeat="picture in pictures" size="large" type="square"> </slider>
Now this slider is accessible from any part of our site so we're not reinventing the wheel. We also just have to change it in one place, the
shared folder and it will update sitewide.
Best Practices (For Huuuuge Apps)
If you are developing a really large application in AngularJS, you will want to go even further and modularize your app. Here are some additional tips on how to accomplish this.
Modularize the Header and Footer
A good practice here would be to create a
Core subfolder under components, and then a subfolder for the Header and Footer and any additional components that will be shared across many pages.
Modularize the Routes
In the structure above we didn't do this, but another good practice for very large apps is to separate the routes into separate files. For example you might add a
blogRoutes.js file in the
/views/blog/ subfolder and there include only the routes relevant to the blog such as
Don't Forget to Minify
If you do decide to opt in and build your AngularJS apps in a modularized fashion, be sure to concatenate and minify your code before going into production. There are many great extensions for both Grunt and Gulp that will help with this - so don't be afraid to split code up as much as you need.
You may not want to necessarily have just one giant
.js file for your entire app, but concatenating your app into a few logical files like:
app.js(for app initialization, config and routing)
services.js(for all the services)
This will be greatly beneficial for reducing initial load times of your app.
If you need some more tips on minifying, check out our guide: Declaring AngularJS Modules For Minification
Keep the Names Consistent
This is more of a general tip, but this will save you a headache in the future, when writing components and you need multiple files for the component, try to name them in a consistent pattern. For example,
Benefits of the Modularized Approach
The example above shows a modularized approach to building AngularJS. The benefits of this approach include:
Follow the approach above will logically compartmentalize your apps and you will easily be able to locate and edit code.
Your code will be much easier to scale. Adding new directives and pages will not add bloat to existing folders. Onboarding new developers should also be much easier once the structure is explained. Additionally, with this approach, you will be able to drop features in and out of your app with relative ease so testing new functionality or removing it should be a breeze.
Debugging your code will be much easier with this modularized approach to app development. It will be easier to find the offending pieces of code and fix them.
Writing test scripts and testing modernized apps is a whole lot easier then non-modularized ones.
To conclude, this article covered some of the best practices in regards to structuring an AngularJS app. It is easy to ignore good practices in order to save time upfront. We all have a tendency to just want to start writing code. Sometimes this passion can hurt us in the long run when our awesome apps grow and become popular and then we're stuck rewriting or even worse maintaining badly thought out code. I hope this article had some helpful tips.
I plan on building a barebones AngularJS application structure that should follow the best practices outlined in this article that will help you get started building Angular apps quickly and efficiently. Keep a lookout for that in the coming weeks. Stay tuned for Part 2 where we put these concepts into practice!