As JavaScript applications tend to grow in size, the need to organize and structure our code become essentials.
JavaScript modules was the answer to structure our code in a clean, maintainable, testable way.
The purpose of this post is to show how to write clean Angular code, and how to structure it to be re-usable, testable using NodeJs style modules.
We will see how our structure will follow the Angular community best practices and guidelines.

  1. NodeJS modules, and JavaScript Modules
  2. Until EchmaScript 2015 (formerly ES6), JavaScript didn't have built in API for modules, and developers had to count on third party frameworks.
    There are two main flavours of modules: AMD, and CommonJS which is what NodeJs used to build their modules.
    This post is not going to describe the differences between the two, and I will just say that I decided to use NodeJS Style.
    Even though NodeJs modules cannot be used directly in a web browser, but with the help of tools like browserify, or webpack we can use any NodeJs module.

  3. Angular modules and best practices
  4. Angular was built with the modular design in mind.
    Angular has the Module API, which allows to build modular applications.
    And the Angular team recommend dividing our application into modules according to their functionality, each functionality has its own module, and the module will contain everything related to the functionality (services, factories, directives, controllers, etc...) .
    From Angular Documentation, a module is a collection of services, directives, controllers, filters, and configuration information.

  5. Write Angular module as NodeJS Module
  6. Angular modules are conceptual and logical partitioning of the code. A module represent a separate functionality that can be tested separately.
    Angular modules don't employ any physical or file structure, and we can write multi modules in one file, or one modules in different files.
    But writing every Angular module as NodeJS module will help achieve many good practices.
    Let us start on how to structure the root and entry point of our application.
    The following picture shows the best practice of how to structure the files in an Angular application.

  7. Explain the file structure
  8. We can specify the following guidelines in structuring the application.
    • App.js
    • App.js is the entry point for our application. It has the code for the main module (the application module). The file should exist in the root folder.
    • config.js and run.js
    • Each Angular module can have a running block, and a configuration block.
      We have one file for each.
    • Single responsibility guideline
    • One of the guideline in the Angular community guideline was Single Responsibility guideline. And as you saw before, by creating a file for the running block and another file for the configuration block, we are following this guideline.
    • A folder for each Angular module
    • Building an Angular applications on module-based design is a good practice that is recommended by the community. And we store each module in a separate folder.
      In the above example, we have four modules: payment, home, common and auth.
      And in case a module has many sub-modules then we create sub-folders for this sub-modules, as in the sub-modules: emailLogin, oauth in our module auth.
    • A separate file for each module component
    • An Angular module can contains: controllers, services, directives.
      As we said, we follow single responsibility guideline, so we create a file for each component.
      In the above example we have a file called navbar-controller.js, which is a directive for the main module.

  9. Writing the entry point for main application
  10. Let us see now the code inside the app.js file.
    // contents of the file app.js
    // -----------------------------------------
    'use strict';
    
    require('angular');
    require('angular-touch');
    require('angular-ui-router');
    require('angular-bootstrap');
    angular.module('app', [
            'ui.router',
            'ngTouch',
            'ui.bootstrap',
            require('./auth'),
            require('./home'),
            require('./common'),
            require('./payment')
        ])
        .config(require('./config'))
        .run(require('./run'))
        .controller('NavbarCtrl', ['$scope', require('./navbar-controller')]);
    Analysing the above code:
    • First add external required libraries
    • As you see, we start by adding required libraries (angular, angular-touch,...etc) at the beginning of the file.
    • Next we define and register the main application module "app"
    • Add dependencies using the require statement
    • As you see, we define the run block, and config block using the require statement.
      This will load the equivalent file with the same name in the require statement (with .js suffix). To bootstrap the previous code, all what we have to do is to hook the "app" main module in the html page like this:
      // contents of the file index.html page
      // ----------------------------------------
      <html class="no-js" lang="en"
      ng-app="app"> 
      <head>

  11. But how a module component will be written?
  12. Now let us see how we write a module component, and let us take as an example the file "navbar-controller.js":
    // contents of the file navbar-controller.js
    // -----------------------------------------
    'use strict';
    module.exports = 
        function ($scope) {
            // .......
            // .......
        };
    We just write the controller function, and assign it to module.exports, where module.exports is the code that will be visible from outside the file.
    This is a NodeJS (or CommonJS syntax), and I am not going to cover it in this post, and I assume that you know it.

  13. Digging into the module file structure
  14. Now, let us see how to structure and build a module using NodeJS standard.
    The following files are what a typical Angular module consists of:
    Let us examine the above file structure:
    • index.js
    • We notice the file index.js.
      When we use the require statement like this :
      require('emailLogin')
      The loader will try to load the file emailLogin.js
      In case it didn't find it the it will look for the directory "emailLogin" with a file : index.js.
      We will use the file index.js to register and configure the module.
    • config.js, run.js
    • Again, as we discussed it with the main app, each module can has its config block and running block, and we create a corresponding file for each.
    • a separate js file for each module compoenent

  15. Examine registration code for a module:
  16. Let us see how we register a module using the nodejs api:
    // contents of the file emailLogin/index.js
    // -----------------------------------------
    'use strict';
    
    require('angular');
    require('angular-resource');
    require('angular-ui-router');
    
    module.exports =
       angular.module('app.auth.email',  ['ui.router', 'ngResource'])
          .config(require('./config'))
          .controller('signupCtrl', require('./signup-controller'))
          .controller('loginCtrl', require('./login-controller'))
          .controller('singedupCtrl', require('./signedup-controller'))
          .factory('User', require('./user-factory'))
          .directive('compareTo', require('./compareTo-directive')).name;
    As you can see from the previous code, we configure the module in index.js, and we define all its components using the require statement, which will import the corresponding file.

  17. How to make NodeJS modules work in the browser?
  18. These NodeJS modules and the require statement work on a file system, which is not going to work in a browser environment.
    But with the use of tools like Browserify, or Webpack, we can process these nodeJs files into a file that is consumable by the browser.
    I am not going to explain how these tools work (in this post at least), and I will just show how to do it. I will use the browserify tool as an example:
    1. Install browserify using npm
    2. npm install browserify
    3. Run browserify
    4. browserify app.js -o bundle.js
      As you can see, we only had to specify the app.js file as input.
      Browserify will figure out the required libraries from the usage of the require statements.