Skip to content

Issues with the Google Best Practice Recommendation for Angular App Structure

Cosmin Ronnin edited this page Feb 13, 2015 · 15 revisions

This document is written as an extension of https://github.com/kosz/generator-modular/issues/2, proposing a few enhancements to Google's Best Practice Recommendation for Angular App Structure : https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/mobilebasic?pli=1

1) The way Google Recommendation sees the project root

Quoting the Google Recommendation

"We propose a recursive structure, the base unit of which contains a module definition file (app.js), a controller definition file (app-controller.js), a unit test file (app-controller_test.js), an HTML view (index.html or app.html) and some styling (app.css) at the top level, along with directives, filters, services, protos, e2e tests, in their own subdirectories."

Thoughts

I see the base of an angular app (unlike a stand alone Module) as having 2 distinct levels.

  • the first level is the index.html file. this file is now rarely modified, and instead it contains some sort of ng-view routing related directive, that gives control over the SPA content, to a designated router. The index.html file, is often modified by automation scripts, making it a more special type of file, that we normally don't modify often, during the development process. Keeping this file separated at a very root level of the project, may make more sense.
  • the second is the main route. Or call it home ... Basically the main page that shows under the / route. This consists of:
    • a route definition
    • a route template
    • a route controller
    • any inner child angular components such as filters, directives or services, that may only be used by this route ( this is what we'd expect to have in any route component )

Based on this, we would actually split things into 3 different places:

  • the index.html file at the root of the project
<html ng-app="Modular">
  <head>
    <!-- auto:inject:css -->
    <!-- endinject -->
  </head>
  <body>
    <ng-view></ng-view>
    <!-- auto:inject:js -->
    <!-- endinject -->
  </body>
</html>
  • the main route ( encapsulated in it's own "component" directory, which also contains all it's other sub components )
  • the app directory ( where the module is defined, and space is left for future large config files, global constants, and other root level/module/setup related things that we may want to separate from the root directory )

Modular Recommendation

2) File Naming conventions

The convention suggested by the Google Recommendation is that of the format :

name-type.filetype
name-type_test.filetype

so an example :

app-controller_test.js

Someone with background in a language that uses snake case may at first focus on the controller_test portion, and at first perceive that as the NAME . Someone with a background in dash-cased languages would instead see app-controller as the name. In reality however : app is the name, controller is the angular object type, test describes the type of content, and .js describes the file type.

Based on this, a different approach which i've seen in various projects, starting with generator-angular-fullstack is more natural:

app.controller.js
app.controller.test.js

now the file feels like it has multiple subtypes. which it does. and the first thing before the first dot is the name.

3) The lack of clarity regarding route modularity

Based on what I've read, the Google Recommendation seems to be a bit ambiguous on the matter of route modularity. It never talks about it really, and it seems like the concept of a Route is not something clearly ironed out.

I see a Route as an additional Angular Component which can and should be encapsulated in it's own directory, not only with it's files ( controller, html, subcomponents ) but also with it's route definition ( index.js or main.js ). This is a pattern i've seen in a few places, I myself picked it up from https://github.com/DaftMonk/generator-angular-fullstack, and I've been in awe of it ever since.

Quoting the Google Recommendation

app.js top-level configuration, route def’ns for the app

Basically saying "define all your routes in app.js". Like so :

angular.module('modular', ['ngRoute']) // a module definition
.config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: '/main/main.html',
      controller: 'mainCtrl'
    })
    .when('/login', {
      templateUrl: '/login/login.html',
      controller: 'login'
    }) // etc 
});

The proposed alternative to this is creating a directory for each route, and at the base level of that directory, having a index.js file, which configures only THAT route :

Standalone Route defined alone in main/index.js:

angular.module('modular') // not a module definition
.config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: '/main/main.html',
      controller: 'mainCtrl'
    });
});

Standalone Route defined alone in login/index.js:

angular.module('modular') // not a module definition
.config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/login', {
      templateUrl: '/login/login.html',
      controller: 'loginCtrl'
    });
});

This directory would encapsulate all files relevant to the route, the route template, controller, definition and any subcomponents:

login/
login/index.js
login/login.html
login/login.controller.js
login/login.controller.spec.js
login/login-form.directive.js  ( or login/login-form/login-form.directive.js )
login/login-form.directive.spec.js ( login/login-form/login-form.directive.spec.js )

4) The mixed components directory

The Google Recommendation, suggests throwing any type of base level component in the components directory. I feel that in a very large project this can cause confusion, especially for new additions to teams working on such large projects. The alternative suggestion for this is to split components by type, but maintain multiple file types relevant to a component, within the component directory.

Modular Recommendation

5) Ambiguity regarding how modules should be used.

I cannot find a clear recommendation here on the Google Recommendation spec, but I normally see an Angular Project, as ONE module and never more than ONE module.

If I feel the need to separate some services and a directive in their own module, for reusing purpose, that's the point where I create a new project, drop those components into the new project, then import that project's module into my project ( and any other projects that I may want to reuse my now : REUSABLE STANDALONE MODULE in )

Having multiple modules per project code base, does not allow to easily share that module amongst projects, nor for example, making ONE module open source, while keeping your project private, with minimum ease.