Make Angular 1 fun again with webpack

Everyone know this good ol' framework called Angular. Perfect for quickly build prototypes of Web application and have fun with javascript. But once you have tried some modern framework like React, Angular 2 or Aurelia, Angular 1 looks juste like an old thing, solid, but boring to use and not very sexy...

But there is a fact: Angular 1 is widely used in Web application development, and that will not change for many years. So, how could we have fun again with Angular 1 ?

All code discribed hereunder is available on this git repository https://github.com/npirotte/angular-webpack

1) Identify the pains

Angular 1 was awesome in 2010, but let's be honest, in 2016, not. Here are the main pains of the classic Angular 1 code :

  • Packaging system : althrouh it as a nice dependency injection mechanism, packing an angular app is a hell, it's very difficult to scale a big angular application with undred of file without writing big and ugly gulp/grunt sequences. The consequence is a tendance to make big controllers and big services instead of small components.

  • ES5 javascript : We all want to write top of the art javascript, using es6/es7 features. Angular 1 was written in 2009, so obviously, we are stuck to goog ol' es5 javascript...

2) Pick a magic tool

Here comes the essential modern javascript tool: Webpack.

Webpack changed the way we develop javaScript Web applications, and it's gonna offer a new way of developping angular applications with two main features:

  • Dependencies managements : Webpack will simplify the dependency managment and app build. That will allow us to use smaller files and write more granular code.

  • Build system : The flexible and extentable build system will allows us to use plugins to transpile code from modern (ES6/ES7, TypeScript) to legacy, browser readable javaScript.

3) Angular and es6

Webpack will allows us to easilly use Babel to transpile ES6/7 javascript code into plain old ES5 code.

The first think to understand is how we can write angular application with ES6 javaScript.

Use angular 1.5 !

Angular 1.5 introduce the concept of "component", whitch simplifies the confusion between controllers and directive. Component are a mixe between classic views and directive, with a simplified configuration.

A component will be composed of 2 parts: A controller and a configuration.

// Component controller
class ComponentControler {  
  contructor (someDependency) {
    this.someDependency = someDependency

    this.someProp : '...'
  }

  someMethod () {
    ...
  }
}
// Component dependencies
ComponentController.$inject = ['someDependency']  
// Component configuration
let component = {  
  controller: ComponentControler,
  template: `
    <div>
      Some html {{$ctrl.someProps}}
    </div>
  `,
  bindings: {
    oneWayBinding: '<',
    twoWayBinding: '='
  }
}

angular.module(moduleName).component('someComponent', component)  

Let's take a look at this code :

  • The controller is a javaScript class. All controller properties are exposed in the view by the $ctrl object. There is no $scope object in components !

  • Services dependencies are declared in the controller static property $inject. For an easy access to dependencies in all class methods we bind it to the controller instance (this.someDependency = someDependency).

  • Thanks to back quotes, we can write inline template for a more React-like coding. This can be usefull for dynamic template generation. (You can still use templateUrl property).

  • In the component configuration, we can declare one way and two way bindings with the < and = keywords. These properties will be binded to the component instance.

We end up with a modern, nice and easy to read component. We can do even better by using TypeScript (but it's another story).

4) Dependencies managment

Here is the more tricky point. How to make work together the webpack commonjs modules with the built in angular dependency injector ?

There is many ways to do that, I will pick the more "natural one".

Where are the rules :

  • One component / service per file.
  • Binding to module (angular.component(...)) occurs only in the ${moduleName}.module.js file.
  • Modules export their name. It makes dependencies injection easier and avoid magic strings usage.
  • Components export their configuration object.
  • Services export their class.

Component file

/**
 * Controller
 */
class ComponentControler {  
  contructor (someDependency) {
    this.someDependency = someDependency

    this.someProp : '...'
  }

  someMethod () {
    ...
  }
}
/**
 * Controller dependencies
 */
ComponentController.$inject = ['someDependency']

/**
 * Exported component configuration
 */
export default component = {  
  controller: ComponentControler,
  template: `
    <div>
      Some html {{$ctrl.someProps}}
    </div>
  `,
  bindings: {
    oneWayBinding: '<',
    twoWayBinding: '='
  }
}

Module file

import { module } from 'angular'  
import someOtherModule from '../someOtherModule/someOtherModule.module.js'  
import configurationFunction from './module.config.js'  
import SomeComponent from './some-component.component.js'

/**
 * someOtherModule is the "{string} - name" of the module
 */
export default module('moduleName', [someOtherModule])  
  .config(configurationFunction)
  .component('someComponent', SomeComponent)
  .name

By doing this, working with angular is mush more fun. The possibilities of webpack are endless, so we can realy do what we want to build awesome workflows !

Don't hesisate to try it along with plugins like css-modules, images loaders ext...