Big SPA with Angular and ES6 (2/2)

Angular - Gulp -Yeoman

This is the second post of a series about big SPA with Angular and ES6. In the first post we’ve set a couple of things up to improve upon. This post will go deeper into tricks and tips that will help once your application becomes bigger. Before we continue coding, we’ll take a small step back and discuss some of the things we have already created.

File structure

We’ve already created some files, but haven’t discussed why or how. Forx the most part, I always stick to johnpapa’s styleguide. This works great for Angular with ES5, and a lot can be used for ES6. If you have never seen this guide before, I recommend going through it. In the ‘src/app’ folder we currently have two sub folders. The ‘components/‘ folder that will contain components that we create. And the ‘main/‘ folder which contains our main module. I call these things modules, which might be a bit confusing since Angular also uses the word modules. Whenever I talk about Angular modules, I will put ‘Angular’ in front of it.

app folder structure

I would recommend only putting components in the components folder which will be reused throughout your entire application. If you create a component which will only be used once or twice within the same module, it is mostly better to store it in that specific module. This depends very much on the context. If for example you have one module that is about football, and you create a component to show the last match your team played, and you are only displaying this in a single locations. It is better to store it under the football module instead of components.

Components

In recent SPA’s I have worked on, we got to about 15/20 components which isn’t huge. If we would create separate folders for each component, it will be easy to lose the overview. This is why we should divide our components up into several sub folders. There isn’t a single way you should structure your components, because it depends on the amount you have. There are however some sub folders you could create depending on your project:

  • Helpers
  • Filters
  • Models

Helpers

Helpers are small, reusable functions. If you have a couple of helpers, you can store them in one Angular service. If you get more, you can create several services per type. An example of a helper-function is:

1
2
3
4
5
6
toFilename(filename) {
return filename
.toLowerCase()
.replace(/ /g,'-')
.replace(/[^w-]+/g,'');
}

Note that Angular already has quite some helper functions like: isNumber, isFunction, etc. So be carefull not to reinvent the wheel.

Filters

Just a place to put your custom Angular filters. Same as with the helper functions don’t reinvent the wheel. There is a great library called angular-filter available which has a bunch of very good filters.

Models

Here you can put your models (as the M in MVC), which you’ll be able to use within your application. With ES6 you can create actual classes which will represent you data. If, for example, you are making an application about music albums. You could have the following model:

1
2
3
4
5
6
7
8
class Album {
constructor(data) {
this.name = data.name;
this.artist = data.artist;
this.releaseDate = data.releaseDate;
this.price = data.price;
}
}

When you would receive JSON from your API which represents an album, you’ll pass the payload into your model and create an actual Album object out of it. This way of working makes it clear which objects there are within the application, and it helps with auto complete in different IDE’s.

Modules

Modules are different states that the user can navigate to. In most applications I have worked on, each of these represent a link in the menu. I would suggest that for each module that you use, you create its own Angular module like we have done in the ‘main/‘ folder. Modules can also have sub-modules, which won’t be different from their parents in the sense of structure.

Let us create an module with sub-module. We’ll make a module which will allow us CRUD functionality on a list of music albums.

Album module structure

The structure of the files looks the same as in our main module. But you can see that 3 folders have been added and a ‘.spec.js’ and ‘.scss’ file have been added. Respectively these are a test and styling file, and they are part of a module so that each module can live on its own. If you would copy a module out, and place it into another project. You wouldn’t have to copy the tests or style from another location.

If we open the create folder, we’ll see the following files:

Album create structure

The sub-module’s files will always start with the name of the main module and then a dash. This is done so that when you have this file open in your favourite IDE, you can see that it is part of the ‘album’ module. The sub-modules don’t actually have Angular module files, but will be imported in the ‘album.module.js’. In theory you can nest your modules endlessly. But from experience I stick to 3 modules deep, because otherwise it will get too complicated.

End note

Every time I create a new application, I find better ways to structure my code. If you are working in a team, it is very important to do reviews of each others work. If someone does not stick to the agreed structure, you will have to tell him/her. We do this by using pull request. Another thing that helps is if you have some way of calculating your technical debt. But for this we are already entering the area of DevOps, which I will try to create a post on soon. If you have any questions, or ideas which could help make this structure better, please don’t hesitate to leave a comment.

To part 1

Big SPA with Angular and ES6 (1/2)

Angular - Gulp -Yeoman

This guide might help if you:

  • want to create a big Single Page Application (SPA) using Angular.
  • don’t have much experience with big SPA’s.
  • don’t know how to structure your SPA.
  • want to be able to ensure quality.
  • don’t want to create your own standards.

Also see: Part 2

Intro

The goal of this post/tutorial is to give developers who have to create a a big SPA a good starting point. Whether it is for work or a private project. There are different ways of organising your files, from which I have gone to love a module based structure. This is what we will be using here today.

This is not a guide where you will have to create everything from scratch. It will use boilerplates and set standards when possible. This will leave you free to start developing asap, and will make it easier for new people to understand your code. I will first go into details on how to set things up. After that I will create a couple of modules which will give you the idea of how to structure the application.

This will consist of two parts, where this first part will mainly be about setting up the base application. The second part will be about setting up the Angular controllers, directives and services with ES6.

Prerequisites

Installation

We’ll start by setting up the base project you’ll be working with. If you are creating a server and client, I recommend you create a separate folder for each:

  • appname
    • client
    • server

Install required tools yo, gulp and bower:

npm install -g yo gulp bower

Install generator-gulp-angular:

npm install -g generator-gulp-angular

Navigate to the client folder and run yo gulp-angular, and select desired technologies:

yo gulp-angular

You are free to choose your preferences. These are mine:

  • Angular 1.4
  • All modules
  • No jQuery
  • Restangular for CRUD calls to API vs $http for few calls
  • Bootstrap vs Angular material design (project dependend)
  • UI-router
  • SASS (node)
  • ES6 (Babel)
  • No template engine

After you have selected your preferences, ‘npm install’ and ‘bower install’ will be run. If everything goes well, you will have the base set-up. Your folder structure should look like:

structure of application

Build the application and serve it up on a local web server:

gulp serve

This should open your default browser with the following:

Initial application

Structure

Now that we have the base framework set-up, we’ll look into the structure which will help when our applications get big. For this we will be focussing on the ‘src/‘ folder. The base framework gives us the following files and folders there:

Source structure

The ‘assets/‘ folder is where assets to our application go. Images for example. The ‘app/‘ folder is where the application itself will live. The index.html is the base HTML file where the Angular application is bootstrapped in and the favicon.ico speaks for itself. If we open the ‘app/‘ folder, we’ll see that a couple of files and folders have been generated again:

app folder structure

The indexx files that got generated we’ll keep as the starting point of our application. The ‘index.module.js’ file that got generated contains all the imports for the components in the ‘components/‘ folder. This can get messy quite fast in projects with a lot of components. That is why we will create a components module which we will import, but more about this later.

The other folder we have is the ‘main/‘ folder. The generated main files are also all imported in the ‘index.module.js’ file. For this, we’ll also create a module which we’ll import in the index module. The last thing we’ll cover in this post will be to change the current code we have to what is described above. Let us start with the index.module.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* global moment:false */

import { config } from './index.config';
import { routerConfig } from './index.route';
import { runBlock } from './index.run';

/** Modules **/
import coreModule from './core.module';
import componentsModule from './components/components.module';
import mainModule from './main/main.module';

angular.module('testApp', [
coreModule.name,
componentsModule.name,
mainModule.name
])
.constant('moment', moment)
.config(config)
.config(routerConfig)
.run(runBlock);

We removed all the separate imports, and limited to the files that are in the same folder and the modules. The file is trying to import coreModule, componentsModule, and mainModule which do not exist yet. We’ll have to create them ourselves.

Create the file ‘core.module.js’ in the ‘src/app’ folder, and add the content below. This module is used to import the core libraries for our project. It is to keep the ‘index.module.js’ file clean.

1
2
3
4
5
6
7
8
9
10
11
12
export default angular.module('testApp.core', [
'ngAnimate',
'ngCookies',
'ngTouch',
'ngSanitize',
'ngMessages',
'ngAria',
'ngResource',
'ui.router',
'ngMaterial',
'toastr'
]);

Create a ‘component.module.js’ file in ‘src/app/components’, and add the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/** Services **/
import { GithubContributorService } from './githubContributor/githubContributor.service';
import { WebDevTecService } from './webDevTec/webDevTec.service';

/** Directives **/
import { NavbarDirective } from './navbar/navbar.directive';
import { MalarkeyDirective } from './malarkey/malarkey.directive';

export default angular.module('testApp.components', [])

.service('githubContributor', GithubContributorService)
.service('webDevTec', WebDevTecService)
.directive('malarkey', MalarkeyDirective)
.directive('navbar', NavbarDirective);

Create a ‘main.module.js’ file in ‘src/app/main’, and add the following content:

1
2
3
4
5
import { MainController } from './main.controller';

export default angular.module('testApp.main', [
])
.controller('MainController', MainController);

We have now restructured the application, but there are still more things we can do to keep things organized. In the next tutorial we’ll go deeper into the different aspects of the structure.

To Part 2