This post describes the architecture that you can use RIGHT NOW on your AngularJS 1.x or Ionic applications and that will be compatible with AngularJS 2. When the time comes and according to this article: Angular 1 and 2 running together, you will be able to migrate easily your application, module by module.
Forget what you know
A large majority of the Ionic, AngularJS 1.x projects are using Bower, Gulp and a folder-by-type architecture. If you want to build large scale applications with several developers, you will definitely have problems if you follow that kind of architecture.
AngularJS is often used to create prototypes and MVP really quickly so why bother? Well, we all know what happen to prototypes and MVPs that somehow work… they go directly into production. If you have reached that point, it is not too late to restructure your code and think about it before your application turns into FrankenstApp!
Bower
Here are few reasons not to use Bower:
- It does not support CommonJS out of the box.
- Using npm and Bower at the same time is a non sense (they both fulfill the same need).
- npm has become the most popular package manager for JavaScript.
- Requires closures to avoid scope leaking.
If you want to know more reasons I recommend you to read this article: Why my team uses npm instead of bower
What is CommonJS?
The CommonJS group defined a module format to solve JavaScript scope issues by making sure each module is executed in its own namespace.
CommonJS handle modules outside the browser and works great with ECMAScript 5 or 6.
// Import with ECMAScript 5
var angular = require('angular');
// Export with ECMAScript 5
module.exports = function(){}
// Import with ECMAScript 6
import angular from 'angular';
// Export with ECMAScript 6
export default function(){}
Gulp
Few reasons not to use Gulp:
- Compiling, concatenating and minifying your application require to install a lot of dependencies (gulp-concat, gulp-minify-css, express, livereload etc.).
- Basic needs (web server, livereload, concat etc) require to create many scripts that YOU will need to maintain yourself.
In 2015 it should not be that complicated to fulfill your application’s basic needs. The solution is to use Webpack.
Folder-by-type structure
The folder-by-type structure is basically grouping JavaScript files by types (controllers, configs, views, directives etc.) as followed:
app/
app.js
controllers/
aaa.js
bbb.js
ccc.js
directives/
ddd.directive.js
eee.directive.js
fff.directive.js
services/
xxx.js
yyy.js
zzz.js
views/
aaa.html
bbb.html
ccc.html
ddd.directive.html
eee.directive.html
fff.directive.html
This folder architecture is a terrible idea for large scale applications. I have experienced it before and it is not a good memory, especially if you are several developers to work at the same time. Here are some reasons not to use it:
- The number of files in your folders can become really large.
- Finding all the files you need to modify for a specific feature can be tricky.
- Working on a feature will lead to open many folders.
If you do not trust me, at least trust John Papa’s styleguide :)
A better solution is to Create components/modules with a Folders-by-Feature structure.
Use Webpack
Webpack is a module bundler, it takes modules with dependencies and generates static assets.
Webpack and Webpack-dev-server easily replace Gulp for basic application needs (web server, livereload, concatenation, minification, compliling JS or Sass etc.). Instead of having to maintain several Gulp scripts, what you only need is a configuration file webpack.config.js
… that’s ALL!
For instance having an autoprefixed CSS injected into your application from several Sass files is as simple as that with Webpack:
{
test: /\.scss$/,
loader: "style!css!autoprefixer!sass"
}
No need to show you the equivalent using Gulp or Grunt, I think you got my point! If you want to go further with Webpack you can read this article I created some time ago: Introduction to Webpack with practical examples
Create components/modules
The solution to large scale applications is to create loosely coupled modules. I have been doing AngularJS applications for a long time now and after a lot of experimenting I have settled to the following architecture:
- Every file that can be edited, live in the src/ or /lib folder.
- Every AngularJS module needs a proper folder.
- Every module file *.module.js must define a unique namespace (and must be the only place where this namespace appears).
- Every module file *.module.js must declare all its dependencies (even if dependencies are already injected in the app).
- Every module file *.module.js must declare all its configs, controllers, services, filters etc.
- Every config, controller, service, filter etc. must export a function or a Class.
- If a module needs some specific style, the .scss file must live within the module as well.
All of this is very powerful, it assures you to have modules that can be shared by several applications without getting any error (except for missing dependencies).
Here an example of a home
module structure:
lib/
index.js
home/
home.module.js
home.config.js
home.service.js
home.controller.js
home.html
home.scss
Now here is the home.module.js
file using ECMAScript 6:
import modConfig from './home.config';
import modController from './home.controller';
let mod = angular.module('prototype.home', [
'ionic',
'ui.router'
]);
mod.config(modConfig);
mod.controller('HomeController', modController);
export default mod = mod.name
Use Angular 1.5 components
http://toddmotto.com/exploring-the-angular-1-5-component-method/
Use Folders-by-Feature structure
Reasons to use Folders-by-Feature structure:
- The number of files in your folders are limited to few.
- Finding all the files you need to modify for a specific feature is easy (they are in the same folder!).
- You can work independently on a feature.
- Knowing what the module represents is easy (the folder name is sufficient).
lib/
index.js
home/
home.module.js
home.config.js
home.service.js
home.controller.js
home.html
home.scss
parameters/
parameters.module.js
parameters.config.js
parameters.service.js
parameters.controller.js
parameters.html
parameters.scss
Recommended boilerplates
If you are ready to start making some changes in your application with the architecture I suggested in this post you can clone those repositories, they are a good start:
- [Angular Material]: shprink/angular1.4-ES6-material-webpack-boilerplate. A simple AngularJS 1.4 boilerplate using ES6, material design and Webpack.
- [Ionic]: shprink/ios-android-wordpress-ionic-webpack-ES6. Repo created for the TutsPlus article: Creating iOS/Android mobile applications for WordPress using Ionic SDK, Webpack, ES6 and WP-API.