Angular2 series – Routing

This post is part of a series of posts about Angular2. You can find them all in the introduction: http://julienrenaux.fr/2015/11/30/angular2-series-introduction/


Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.

All the following code examples are part of a boilerplate I created. It is available on GitHub: https://github.com/shprink/angular2-nobullshit-boilerplate.


If you are used to AngularJS applications you have probably used the ui-router instead of the Angular basic router (ngRoute). The ui-router is more popular because it has more features (such as nested views) and was adopted by big projects such as Ionic Framework.

The Angular2 router is a complete rewrite of the old ngRoute module. It was created keeping the ui-router use cased in mind, but also Angular2 components based architecture (a concept not yet adopted with AngularJS).

If you want to know more details about the Router history I recommend watching this video (beware the API changed a little bit since this video):

If you want to know more about components in Angular2 I suggest you to read this previous article of mine: Angular2 series – Component, Directive, Pipe and Service.

Path location strategies

Using AngularJS

With the ui-router in AngularJS you have the choice between two modes. The default one, aka the Hash mode (#products/id) that is not interpreted by servers or the HTML5 mode (/products/id).

One or the other can be selected using the $locationProvider

$locationProvider.html5Mode(true);

Notice: This HTML5 mode requires your web server to be configured.

Using Angular2

In Angular2 we have the same “modes” but they are called PathLocationStrategy and HashLocationStrategy.

PathLocationStrategy

PathLocationStrategy is the default strategy used by the new router. It is equivalent to the HTML5 mode in AngularJS.

If you want to use this strategy, you must define the APP_BASE_HREF to a string representing the URL prefix that should be preserved when switching pages.

import {ROUTER_PROVIDERS, APP_BASE_HREF} from 'angular2/router';

bootstrap(yourApp, [
  ROUTER_PROVIDERS, // includes binding to PathLocationStrategy
  provide(APP_BASE_HREF, {useValue: '/my/prefix/here'})
]);

If you have problems understanding the above example, learn how to create an application with Angular2 first by reading: Angular2 series – Component, Directive, Pipe and Service.

If you do not want any prefix to be kept you can set APP_BASE_HREF to be:

provide(APP_BASE_HREF, {useValue: '/'})

Official docs

HashLocationStrategy

HashLocationStrategy is the strategy equivalent to the default strategy in AngularJS ui-router. This strategy is used to configure the Location service to represent its state with the hash fragment of the browser’s URL.

import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router';
bootstrap(yourApp, [
  ROUTER_PROVIDERS,
  provide(LocationStrategy, {useClass: HashLocationStrategy})
]);

Official docs

Define Routes

Using AngularJS

In AngularJS and ui-router here is how to define states (or Routes) during the configuration phase:

$stateProvider.state('home', {
    url: '/',
    templateUrl: 'home.html',
    controller: 'HomeCtrl'
}).state('about', {
    url: '/about',
    templateUrl: 'about.html',
    controller: 'AboutCtrl'
})

Using Angular2

In Angular2 a state is created from a Route class. Using the @RouteConfig annotation you can create your application route definition.

@RouteConfig takes as first argument an Array of Route that have the following properties:

  • path equivalent to url in ui-router states
  • component a component type.
  • name is an optional CamelCase string representing the name of the route.
  • data is an optional property of any type representing arbitrary route metadata for the given route (we talk about it in the Passing data between routes section)

With that in mind let’s create an equivalent of the routes we created in the AngularJS version:

import {RouteConfig, Route} from 'angular2/router';
import {MyComponentHome, MyComponentAbout} from './myComponents';
@Component({
    selector: "app"
})
@RouteConfig([
    new Route({ path: '/', component: MyComponentHome, name: 'Home' }),
    new Route({ path: '/about', component: MyComponentAbout, name: 'About' })
])
export class App {...}

Template update

We have now defined our Routes, the next step is to define where to display the components when switching pages.

Using AngularJS

In AngularJS and ui-router we can use the ui-view directive to insert dynamic content from each state:

<body>
    <ui-view>
        <i>Some content will load here!</i>
    </ui-view>
</body>

Using Angular2

Using Angular2, it is similar, only the name of the directive change!

First we need to import the RouterOutlet directive and inject it into our App component, then we can use it in our template.

import {RouterOutlet} from 'angular2/router';
@Component({
    selector: "app"
})
@View({
    directives: [RouterOutlet]
    template: `
      <router-outlet></router-outlet>
    `
})

Now any location change will load a different component inside the RouterOutlet directive.

Navigate between pages

Using AngularJS

To navigate between pages (or states) in AngularJS and the ui-router we can use the ui-sref directive.

<a ui-sref="home">Home page</a>
<a ui-sref="about">About page</a>

Using Angular2

With Angular2 we can use the RouterLink directive instead.

This directive needs to be injected in your component first:

import {RouterLink} from 'angular2/router';
@Component({
  selector: "menu",
  directives: [RouterLink],
  template: `
     <a [routerLink]="['./Home']">Home page</a>
     <a [routerLink]="['./About']">About page</a>
  `
})
export class Menu {...}

Please note that [routerLink] uses the Route name that we defined earlier in the

Passing data between routes

Using AngularJS

In AngularJS we could defined URL parameters in state definitions:

$stateProvider.state('product.item', {
    url: '/product/:id',
    templateUrl: 'item.html',
    controller: 'ItemCtrl'
})

To pass the id from a state to another we have two choices. We can use the ui-sref directive or the $state service:

<a ui-sref="product.item({id: 4})">Go to item 4</a>
function($state) {
    // Go to item 4
    $state.go('product.item', {id: 4});
}

Then getting this data in our controller is easy using the $stateParams service:

function($stateParams) {
    var id = $stateParams.id;
}

BEWARE: The concept of params (passing data between states but without using URL parameters) in the ui-router does not exist in Angular2 (see my question on stackoverflow). A similar concept exist though and it is called data.

Using Angular2

Similar to AngularJS, we can define URL parameters using path from the Route class:

@RouteConfig([
    new Route({ 
        path: '/product/:id', 
        component: MyProductItemComponent, 
        name: 'ProductItem'
    })
])
export class App {...}

To pass the id from a Route to another we also have two choices. We can use the routerLink directive or the Router service.

In a template:

<a [routerLink]="['./ProductItem', {id: 4}]">Go to item 4</a>

In a Component:

import {Router} from 'angular2/router';
class {
  constructor(private _router: Router) {
    this._router.navigate( ['./ProductItem', { id: 4 }] );
  }
}

Then getting this data in a Component is easy using the RouteParams service:

import {RouteParams} from 'angular2/router';
class {
  id: number;
  constructor(private _params: RouteParams) {
    this.id = _params.get('id');
  }
}

Official docs

You can also retrieve data from a Route using RouteData service. I think this feature would not be used often (I probably will not use it on my applications) but it is good to know that it exists:

@RouteConfig([
    new Route({ 
        path: '/product/:id', 
        component: MyProductItemComponent, 
        name: 'ProductItem',
        data: {
            isAdmin: true
        }
    })
])
export class App {...}

You can now retrieve the isAdmin flag or any other Route metadata in your Components using the RouteData service:

class {
  isAdmin: boolean;
  constructor(private _data: RouteData) {
    this.isAdmin = _data.get('isAdmin');
  }
}

Official docs


Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook!

Angular2 series – Component, Directive, Pipe and Service

This post is part of a series of posts about Angular2. You can find them all in the introduction: http://julienrenaux.fr/2015/11/30/angular2-series-introduction/


Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.

Component

A component is what you used to call a directive in AngularJS. It contains a template, styles, a list of injectables (directives, services) and a selector.

Official docs

Let’s create a component that lists the US Democratic Party presidential candidates.

import {Component, View, NgFor} from 'angular2/angular2';

@Component({
    selector: "navbar",
    directives: [NgFor], 
    styles: [`
        li{
          color: gray;
        }
    `],
    template: `
        <h2>Democratic Party presidential candidates</h2>
        <ul>
            <li *ngFor="#item of items; #i = index">{{item}} {{i}}</li>
        </ul>
    `
})
export class Navbar {
    items: Array<String>

    constructor() {
      this.items = [
        "Hillary Clinton",
        "Martin O'Malley",
        "Bernie Sanders"
      ]
    }

    ngOnInit() {
        console.log('[Component] navbar ngOnInit');
    }
}

When a component is instantiated, Angular2 creates a shadow DOM for the component (Shadow DOM provides encapsulation for the JavaScript, CSS, and templating in a Web Component). Then, the template and styles are injected inside it.

Learn a bit more about Web component and specifically about the <template> tag by reading the previous article of this series of posts: Angular2 series – Template Syntax.

You can now use your component by inserting it into your html page:

<navbar></navbar>

Demo

Screen Shot 2015-12-12 at 19.32.27

http://embed.plnkr.co/cUCWoUDRzd31YRRbo5Rg/preview

Lifecycle hooks

In the previous example, we used the ngOnInit Class method to dump a message [Component] navbar ngOnInit in the console. It is called only when the component is initiated. It exists several hooks that make your life easier when it comes to plug yourself in between component life phases.

  • ngOnChanges (if any bindings have changed)
  • ngOnInit (after the first check only)
  • ngOnDestroy (at the very end before destruction) Implement this interface to get notified when any data-bound property of your directive changes
  • ngDoCheck
  • ngAfterContentInit
  • ngAfterContentChecked
  • ngAfterViewInit
  • ngAfterViewChecked

Official docs


Directive

Directives allow you to attach behaviour to elements in the DOM. It is also what you used to call a directive in AngularJS, but without a proper view. You can therefore place as many directives as you want on one DOM-element. This is not possible with components.

Official docs

Let’s get back to our previous component and this time, let’s make our presidential candidates red. To do so, we are going to create the redify directive:

import {Directive, ElementRef, Renderer} from 'angular2/angular2';

@Directive({
  selector: '[redify]'
})
export class Redify {
  constructor(private _element: ElementRef, private renderer: Renderer) {
      renderer.setElementStyle(_element, 'color', 'red');
  }
}

Notice that in order to obtain a reference to our Presidential Candidate element we injected _element: ElementRef.

Official docs for ElementRef

To modify the element style we injected renderer: Renderer, which is a service that gives you methods to manipulate the style of a particular element.

Official docs for Renderer

Then we can add the redify directive to our component:

import {Redify} from 'path/to/your/Redify/directive';

@Component({
    selector: "navbar",
    directives: [NgFor, Redify], 
    ...
    template: `
        <li redify *ngFor="#item of items; #i = index">{{item}} {{i}}</li>
    `
})

Result

Screen Shot 2015-12-12 at 19.28.28

http://embed.plnkr.co/iJiZVqixM0qAo4RMelB7/preview


Pipe

A pipe in Angular2 is the equivalent of filters in AngularJS. As in AngularJS, pipes can be stateless (pure functions, not reevaluated) or stateful (has dependencies that can modify the output).

A better explanation of what is a pipe is available in the previous article of this series of posts: Angular2 series – Template Syntax

Official docs

Let’s get back again to our previous component and this time, let’s create a pipe to transform our presidential candidates last name to uppercase.

First we create lastnameUppercase pipe:

import {Pipe} from 'angular2/angular2';

@Pipe({
  name: 'lastnameUppercase'
})
export class LastnameUppercase {
  transform(v, args) {
    return `${v.split(' ')[0]} ${v.split(' ')[1].toUpperCase()}`;
  }
}

Then let’s add this pipe to our navbar component in order to consume it.

import {LastnameUppercase} from './pipes';
@Component({
    selector: "navbar",
    ...
    pipes: [LastnameUppercase],
    template: `
        <li redify *ngFor="#item of items; #i = index">{{item | lastnameUppercase}} {{i}}</li>
    `
})

Demo

Screen Shot 2015-12-12 at 19.37.13

http://embed.plnkr.co/L1ERY1Pn6qmGl0B1hi0K/preview

Built in pipes

In Angular2 you have access to the following pipes for free:

  • currency
  • date
  • uppercase
  • json
  • limitTo
  • lowercase
  • async
  • decimal
  • percent

Service

Now that we saw how to create a component, a directive and a pipe, we are going to clean up our code and separate the data retrieval (the presidential candidates) into a service.

Official docs

import {Injectable} from 'angular2/angular2';

@Injectable()
export class PresidentialCandidate {

    constructor() {}

    getRepublicainList() {
        return [
        "Donald Trump",
        "Rand Paul",
        "Ben Carson"
      ]
    }

    getDemocraticList() {
        return [
        "Hillary Clinton",
        "Martin O'Malley",
        "Bernie Sanders"
      ]
    }
}

Now let’s consume this service on our navbar component:

import {PresidentialCandidate} from './services';

@Component({
    selector: "navbar",
    providers: [PresidentialCandidate],
    ...
    template: `
        <h2>Democratic Party presidential candidates</h2>
        <ul>
        <li redify *ngFor="#item of democrats; #i = index">{{item | lastnameUppercase}} {{i}}</li>
        </ul>
        <h2>Republican Party presidential candidates</h2>
        <ul>
        <li redify *ngFor="#item of republicans; #i = index">{{item | lastnameUppercase}} {{i}}</li>
        </ul>
    `
})
export class Navbar {
    democrats: Array<String>
    republicans: Array<String>

    constructor(private presidentialService :PresidentialCandidate) {
      this.democrats = presidentialService.getDemocraticList(); 
      this.republicans = presidentialService.getRepublicainList();
    }
}

We have decoupled the presidential candidates retrieval with the component that displays them. It is now easier for other components to consume this data.

Demo

Screen Shot 2015-12-12 at 19.40.57

http://embed.plnkr.co/z1B96b4OX7BHwkT0492G/preview


Application

AngularJS

With AngularJS an application was a simple module. It had no difference from any other module of your application.

angular.module('yourApp', []);

Angular2

With Angular2, it is similar. An application is a simple component as any other component of your application. It is just the root component that basically contains the scaffolding of your page.

@Component({
    selector: "yourApp"
})
@View({
    directives: [Header, Navbar, Content, Footer]
    template: `
      <header></header>
      <navbar></navbar>
      <content></content>
      <footer></footer>
    `
})
export class App {
  constructor() {
   
  }
}

Header, Navbar, Content and Footer are custom components, they do not exist within Angular2 core.

Bootstrap

Now that you know how to create components and a root component (or app), you need to bootstrap the application.

AngularJS

In AngularJS you could use angular.bootstrap(document, ['yourApp']); or the ng-app directive <body ng-app="yourApp">.

Angular2

In Angular2 it is very similar.

import {bootstrap} from 'angular2/angular2';
import {yourApp} from 'path/to/your/app/component';

bootstrap(yourApp, []);

Our application is now ready to be rendered. Insert your app component in your index.html file and reload the browser, your app is ready!

<body>
    <app>
        Loading...
    </app>
</body>

Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook!

Angular2 series – Template Syntax

This post is part of a series of posts about Angular2. You can find them all in the introduction: http://julienrenaux.fr/2015/11/30/angular2-series-introduction/


Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.

To understand the code blocks in that Angular2 series of posts, we need to learn a bit about the new Angular2 template syntax.

Be careful, as of alpha52 core directives syntax changes from kebab case to camel case. Example: ng-if becomes ngIf. For more information read the migration docs

Bind property

AngularJS

With AngularJS, binding a given expression to a property value requires to use either a core directive such as ng-value or use AngularJS markup {{}}.

ng-value is expecting an AngularJS expression, whose value will be bound to the value attribute of the input element:

<input ng-value="firstName" />

But you could also use it that way:

<input value="{{firstName}}" />

Angular2

With Angular2 it is similar, without the need to use a specific directive. Only the new syntax is necessary [value] and it is not limited to value, you can use it to bind anything to any particular element property:

<input [value]="firstName" [placeholder]="firstNamePlaceholder" />

Exactly like AngularJS you can use the following:

<input value="{{firstName}}" placeholder="{{firstNamePlaceholder}}" />

Event

AngularJS

With AngularJS we need to use special directives to listen to events. The most famous being ng-click. Ng-click listen to the onClick event. Here is the list of all the HMTL5 events that you can normally listen to: http://www.w3schools.com/tags/ref_eventattributes.asp

Most of the HTML5 events are covered by AngularJS directives such as ng-blur, ng-change, ng-focus, ng-keyup etc.

<button ng-click="doSomething($event)">

Angular2

With Angular2 you can listen to any HTML5 native element event using this special syntax: (eventName)

<button (click)="doSomething($event)">

Two-way data binding

Angular2 also has a two-way data binding in place but do not use the famous and decried “digest cycle” of AngularJS. Instead, Angular2 uses zone.js.

A zone is an execution context that persists across async tasks.

If you want to make sense out of this sentence I suggest you watch this talk by Brian Ford:

Basically zone.js gives Angular2 a low level foundation that let it instrument the browser and let it know when asynch operations are finished.

That way, you can combine event and bind property syntaxes that we saw before:

<input type="text" [value]="firstName" (input)="firstName=$event.target.value" />

That being said, ngModel can be used as a simplified version of what we have above:

<input type="text" [(ngModel)]="firstName" />

The result is identical.

Pro tip: you can also run anything outside the Angular2 zone using the NgZone service. The most common use of this service is to optimize performance when starting a work consisting of one (or more) asynchronous task that does not require UI updates.


Local variable

A local template variable is a vehicle for moving data across element lines. As far as I know, there is no equivalent of local variable in AngularJS. A local variable # can be a pointer to an object or an DOM element.

<video #movieplayer ...>
  <button (click)="movieplayer.play()">
</video>

In the above example, having the movieplayer allows us to manipulate the video HTML5 api on the same element, its siblings or its children.

Pro tip: # is the canonical version of the local variable. You can also use it with var-. In our movieplayer case we could have var-movieplayer instead of #movieplayer.


* symbol

This is probably the most disturbing syntax choice of the new Angular2 syntax. It is actually pretty simple to understand what it does if you have a little background on what the template tag is.

template tag

The template tag allows you to declare a piece of DOM that can be instantiated after run time. It guaranties better performance and the usage of a resource only when needed.

Here is an example to be clearer:

<div style="display:none">
  <img src="path/to/your/image.png" />
</div>

As you can see, the image will not be displayed because of display:none on its parent. The problem is that the browser will prefetch this image whether you use it or not. It is a waste of resource and can impact your page performance.

The solution to this very problem is to use the template tag!

<template>
  <img src="path/to/your/image.png" />
</template>

The image in the above example will not be fetch by the browser until we instantiate the template.

Let’s get back to the * symbol now. Using it on a element will turn it into an embedded template:

<hero-detail *ngIf="isActive" [hero]="currentHero"></hero-detail>

The following will be transformed as:

<template [ngIf]="isActive">
  <hero-detail [hero]="currentHero"></hero-detail>
</template>

Now that I explained what the template tag is for, it is easy to understand that the * symbol is used by conditional directives such as ngFor, ngIf, and ngSwitch. Indeed, <hero-detail> component does not need to be instantiated until isActive is true.


Pipe

A pipe in Angular2 is the equivalent of filters in AngularJS. As in AngularJS, pipes can be stateless (pure functions, not reevaluated) or stateful (has dependencies that can modify the output).

Stateful

In Angular2, most built-in pipes are stateless, it is the case with DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe, and PercentPipe.

You can use them that way:

<p>My birthday is {{ birthday | date:"MM/dd/yy" }} </p>

and even chain them (same as AngularJS):

{{ birthday | date | uppercase}}

Stateful

The Async pipe is a built-in stateful pipe. It can receive a Promise or Observable as input and subscribe to the input automatically, eventually returning the emitted value(s).

@Component({
  selector: 'my-hero',
  template: 'Message: {{delayedMessage | async}}',
})
class MyHeroAsyncMessageComponent {
  delayedMessage:Promise<string> = new Promise((resolve, reject) => {
    setTimeout(() => resolve('You are my Hero!'), 500);
  });
}

Here, <my-hero> component will display Message: You are my Hero! only once the delayedMessage promise is resolved.


Elvis operator

In JavaScript, you often end up checking the existence of object properties. For instance I am sure you have written that kind of conditions before:

if (cordova && cordova.plugins && cordova.plugins.notification){
  // use cordova.plugins.notification
}

All of this to avoid such an error TypeError: Cannot read property 'notification' of undefined.

Pro tip: you can simplify it using lodash _.get function. The previous example could be written that way:

if (_.get(cordova, 'plugins.notification')){
  // use cordova.plugins.notification
}

Even if plugins is not defined _.get will return undefined.

The Elvis operator (?) in Angular2 fixes that very problem but in the template side.

<p>Employer: {{employer?.companyName}}</p>

Here the employer field is optional and if undefined, the rest of the expression should be ignored. Without the Elvis operator here you will get a TypeError.

It also works with long property path: a?.b?.c?.d


Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook!

Angular2 series – Tooling

This post is part of a series of posts about Angular2. You can find them all in the introduction: http://julienrenaux.fr/2015/11/30/angular2-series-introduction/


Tooling is really important when starting a new project. This post presents my favorite tool stack (TypeScript & Webpack) and explain why you should use it too with Angular2.

Angular2 does not require any of the following tools, the choice is entirely yours to use them or not.

ECMAScript6

ECMAScript 2015 (6th Edition) is the current version of the ECMAScript Language Specification standard. ES6 got officially approved and published as a standard on June 17, 2015 by the ECMA General Assembly.

Angular 2 requires ES6 support, but ES6 is only available on modern browsers. For older browsers (including IE 11) you can use a shim to get the needed functionality.

<script src="../node_modules/es6-shim/es6-shim.js"></script>

If you use a compilation phase (using Gulp, Grunt, Webpack or Browserify), which I recommend (see last paragraph about Webpack) you could directly compile your ES6 code into ES5 instead of using es6-shim. ES5 is available on most browsers.

If you want to have a complete overview of what ES6 new features are, I recommend reading the this great babeljs doc

Class

Classes are used everywhere in Angular2, a Service is a Class, a Component is also a Class and a Directive is… a Class. It is therefore important to learn a bit about them.

ES6 introduced Classes (available for a long time in CoffeeScript). Classes are a simple sugar over the prototype-based object oriented pattern. If you come from an object oriented language such as Java, Php or C++ you are already accustomed to classes.

Here is simple example from a book that I love JavaScript Design Patterns by Addy Osmani:

class Car {
  constructor(model, km) {
    this.model = model;
    this.km = km;
  }
  drive(km) {
    this.km = this.km + km;
  }
  getKm() {
    return `${this.km} km`;
  }
}

Classes support inheritance, super calls and static methods.

Instantiation

Let’s play with our new car! We are going to instantiate a used car and drive it a little:

let twingo = new Car("Renault Twingo",100000);
console.log(twingo.getKm()); // dump: 100000 km

// Drive 150km
twingo.drive(150);
console.log(twingo.getKm()); // dump: 100150 km

Access static methods

class Car {
  ...
  static getWheels(){
    return 4;
  }
}

console.log(Car.getWheels()); // dump: 4

Calling getWheels static function on a Car instance twingo.getWheels() will result as twingo.getWheels is not a function..

All of these examples are available on plunker.


TypeScript

TypeScript is a super-set of ES6, meaning that when writing TypeScript code you have access to all ES6 new features such as arrow functions, generator, multiline strings etc. It also means that you can rename your ES6 based files from .js to .ts without any problem.

If you are used to ECMAScript6, jumping to TypeScript should not be difficult at all. While you are not forced to use TypeScript when developing Angular2 applications, I I still recommend using it for several reasons:

ES6 shim not needed anymore

TypeScript can also transform your code into ES5 (available on most browsers).

To do that, add a tsconfig.json file to the root of your project and specify the compile option to be ES5:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    ...
  }
}

Optional typing

TypeScript enables the optional typing. It means that if we want to force a type on a Class property we can do it that way:

export class Car {
    model: string;
    km: number;
    constructor(newModel: string, newKm: number) {
        this.model = newModel;
        this.km = newKm;
    }
    drive(km: number) {
        this.km = this.km + km;
    }
}

Here we made sure that the car model is a string and the car number of km is a number.

Now running new Car("Renault Twingo", "100000") (note that the second argument is a string) will return an error.

Interface

In TypeScript, interfaces fill the role of naming these types, and are a powerful way of defining contracts within your code as well as contracts with code outside of your project.

Class Types

Interfaces are capable of describing the wide range of shapes that JavaScript objects can take. In addition to describing an object with properties, interfaces are also able to describe function types.

interface CarInterface {
    model: string;
    km: number;
    drive(km: number);
    getKm();
}

class Car implements CarInterface {
    model: string;
    km: number;
    constructor(newModel: string, newKm: number) {
        this.model = newModel;
        this.km = newKm;
    }
    drive(km: number) {
        this.km = this.km + km;
    }
    getKm() {
        return `${this.km} km`;
    }
}

Interfaces are a great feature to have. I personally use it when building applications that are Web and Mobile compatible.

With an interface, I expose common properties and methods that we can implement. Then, we can have CarMobile and CarWeb Classes that expose the same API but implement methods in a different way (for instance using Ionic service on mobile and Bootstrap service on Web).

IDE support

What I really like about TypeScript is the IDE support. Whether you use Atom, WebStorm or SublimeText you will still have plugins to enable autocompletion, type checking and linter.


Webpack

Webpack is a module bundler that is quite popular lately in the React community, but now also in the Angular2 community.

You can forget about Grunt or Gulp scripts that need to be maintained. Webpack allows you to require any type of file (.js, .coffee, .css, .scss, .png, .jpg, .svg, etc.) and pipe them through loaders to generate static assets, available to your application.

If you need examples on how Webpack works I suggest you go check out a previous post of mine: http://julienrenaux.fr/2015/03/30/introduction-to-webpack-with-practical-examples/.

Compilation phase

Having a compilation phase has a real advantage. It allows you to automate behavior that you have to do manually otherwise. For instance, autoprefixing your CSS to work with most of the Browsers.

The following CSS with -webkit- and -ms- prefixes is really painful to write manually because you need to know which prefix to use on different cases.

.page-wrap {
  display: -webkit-box;  /* OLD - iOS 6-, Safari 3.1-6, BB7 */
  display: -ms-flexbox;  /* TWEENER - IE 10 */
  display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
  display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
}

If you use a compilation phase you could just write it that way:

.page-wrap {
  display: flex;
}

The CSS is now lighter, easier to understand and to maintain.

Webpack allows you to “pipe” your CSS code into several loaders that will transform it. In that particular case, we want the autoprefixer loader to add prefixes compatible with the last 2 versions of all browsers.

{
    test: /.css$/,
    loader: "style!css!autoprefixer?browsers=last 2 versions"
}

Catching syntax errors

Having a tool such as Webpack is great to catch potential JavaScript syntax errors even before running your code in the browser. With webpack-dev-server your code is compiled on the fly when any file is modified. Any syntax error will display this kind of message on your terminal:

ERROR in ./lib/home/controller.js
Module build failed: SyntaxError: /Users/shprink/Sites/test/controller.js: Unexpected token (6:39)
  4 |     var vm = this;
  5 |
> 6 |     $scope.$on('$viewContentLoaded' () =&gt; {
    |                                    ^
  7 |
  8 |     });
  9 |

Here we forgot to add a coma between '$viewContentLoaded' and our function.

Avoid CSS and template inline

ES6 introduces a really great feature which is multiline strings. Before ES6, a multiline string could be written that way:

"<h4>Give me some keys!</h4>" + 
"<div>{{values}}</div>"

or:

["<h4>Give me some keys!</h4>",
"<div>{{values}}</div>"].join('')

Now with ES6, you can write it that way:

`
    <h4>Give me some keys!</h4>
    <div>{{values}}</div>
`

This is really nice, but I am not a big fan of using it for HTML or CSS. In a lot of Angular2 examples you will see something like this:

@Component({
    selector: "app"
})
@View({
  styles: [`
     .container{
        color: red;
     }
  `],
  template: `
    <h4>Give me some keys!</h4>
    <div><input (keyup)="onKey($event)"></div>
    <div>{{values}}</div>
  `
})

While this is great for tutorials as it is concise and inline, it is, in my opinion, not good to use on your projects.

The reason is fairly simple. When using CSS or HTML into a JavaScript file you loose all the great features that your IDE provides. For instance, you cannot correctly format your HTML or CSS and you do not have autocompletion.

What I prefer to do is having separated HTML and CSS files so we can leverage IDE’ features on them. With Webpack you could do something like this to import your HTML and CSS as strings:

@Component({
    selector: "app"
})
@View({
    directives: [Navbar, RouterOutlet],
    styles: [require('./index.scss')],
    template: require('./index.html')
})

Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook!

Angular2 series – Introduction

Angular2 is new, the quantity of blog posts is very limited at the moment and the documentation is sometimes incomplete. In these conditions, it is hard to find the right information to start your own application.

Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.

Angular2 is a complete rewrite of the famous AngularJS that we love and that I have used for years. Angular2 uses modern Web standards (Web components, Shadow DOM etc.) which make it faster than AngularJS. It includes a wealth of essential features such as mobile gestures, animations, filtering, routing, data binding, security and internationalization.

By going through this series of posts you will learn all you need to know about creating a complete application using Angular2 and TypeScript.

Tooling

http://julienrenaux.fr/2015/11/30/angular2-series-tooling/

Template Syntax

http://julienrenaux.fr/2015/12/02/angular2-series-template-syntax/

Component, Directive, Pipe and Service

http://julienrenaux.fr/2015/12/13/angular2-series-component-directive-pipe-and-service/

Routing

http://julienrenaux.fr/2015/12/25/angular2-series-routing/

Http request

[Early 2016]

Change detection

[Early 2016]

V1 to V2 migration

[Early 2016]

you can start preparing your code to be Angular2 compatible right now by following the advice I shared on: Modular AngularJS and Ionic architecture: a first step towards AngularJS 2

Create a Mobile Application Using WordPress, Ionic, and AngularJS

Introduction

This tutorial is a post that I did for tutsplus.com. It will explain you step by step how to create a modern, hybrid, mobile application (iOS and Android) of your WordPress website using the latest technologies. We’ll be using Ionic Framework, ECMAScript 6, npm, webpack, and Apache Cordova.

http://code.tutsplus.com/tutorials/create-a-mobile-application-using-wordpress-ionic-and-angularjs–cms-24170

Modular AngularJS and Ionic architecture: a first step towards AngularJS 2

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:

  1. It does not support CommonJS out of the box.
  2. Using npm and Bower at the same time is a non sense (they both fulfill the same need).
  3. npm has become the most popular package manager for JavaScript.
  4. 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:

  1. Compiling, concatenating and minifying your application require to install a lot of dependencies (gulp-concat, gulp-minify-css, express, livereload etc.).
  2. 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:

  1. The number of files in your folders can become really large.
  2. Finding all the files you need to modify for a specific feature can be tricky.
  3. 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 Folders-by-Feature structure

Reasons to use Folders-by-Feature structure:

  1. The number of files in your folders are limited to few.
  2. Finding all the files you need to modify for a specific feature is easy (they are in the same folder!).
  3. You can work independently on a feature.
  4. 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:

  1. [Angular Material]: shprink/angular1.4-ES6-material-webpack-boilerplate. A simple AngularJS 1.4 boilerplate using ES6, material design and Webpack.
  2. [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.

Creating an application with AngularJS 1.4, ECMAScript 6, Material Design and Webpack

AngularJS 1.4 has now been released.

It introduces a new Router, a translation system similar to angular-translate created by Pascal Precht, some performance enhancement and a better Webpack, Browserify support (CommonJS) without any “hacks”. You can for example directly import AngularJS like this

import 'angular/angular.js';

instead of this

require('expose?angular!exports?window.angular!angular/angular.js')

Demo

Source available on Github : https://github.com/shprink/angular1.4-ES6-material-webpack-boilerplate


Basic Needs

Dependencies (package.json)

For this tutorial we will need AngularJS, Angular Material, the UI router (The new router is not ready for production yet) and a icon library.

"dependencies": {
    "angular": "~1.4.0",
    "angular-animate": "~1.4.0",
    "angular-aria": "~1.4.0",
    "angular-material": "^0.10.1",
    "angular-ui-router": "^0.2.14",
    "font-awesome": "^4.3.0"
}

Webpack

If you need an explanation on what is Webpack for, I suggest you go check out a previous post of mine: http://julienrenaux.fr/2015/03/30/introduction-to-webpack-with-practical-examples/

We will need the following Webpack loaders to be able to compile ECMAScript 6 code and to process CSS, HTML files.

"devDependencies": {
    "babel-loader": "^5.0.0",
    "css-loader": "^0.12.0",
    "file-loader": "^0.8.1",
    "html-loader": "^0.3.0",
    "html-webpack-plugin": "^1.3.0",
    "style-loader": "^0.12.1"
}

The webpack.config.js cannot be easier:

module.exports = {
    entry: './lib/index.js',
    output: {
        path: './www',
        filename: 'bundle-[hash:6].js'
    },
    module: {
        loaders: [{
            test: /.html$/,
            loader: 'file?name=templates/[name]-[hash:6].html'
        }, {
            test: /.css$/,
            loader: "style!css"
        }, {
            test: /.js$/,
            exclude: /(node_modules)/,
            loader: "ng-annotate?add=true!babel"
        }, {
            test: [/fontawesome-webfont.svg/, /fontawesome-webfont.eot/],
            loader: 'file?name=fonts/[name].[ext]'
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './lib/index.html'
        })
    ]
};

Entry point (lib/index.js)

The following entry point gathers all our application basic needs: Angular, Material Design, the router and the icons. Here we use import which is the ECMAScript 6 way to require CommonJS modules, inject angularMaterial and angularUIRouter as our module dependencies and to finish we export our module as default (You can export several modules within a single file, default is the export you will get if you do not specify a specific import).

// Import angular
import 'angular/angular.js';
// Material design css
import 'angular-material/angular-material.css';
// Icons
import 'font-awesome/css/font-awesome.css';
// Materail Design lib
import angularMaterial from 'angular-material';
// Router
import angularUIRouter from 'angular-ui-router';

// Create our demo module
let demoModule = angular.module('demo', [
    angularMaterial,
    angularUIRouter
])

export default demoModule;

Index.html

The index.html needs two things. A way to bootstrap the application (here ng-app="demo") and a way to include the JavaScript file generated by Webpack (here src="{%=o.htmlWebpackPlugin.assets[chunk]%}").

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    </head>
    <body ng-strict-di ng-app="demo">
        {% for (var chunk in o.htmlWebpackPlugin.assets) { %}
        <script src="{%=o.htmlWebpackPlugin.assets[chunk]%}"></script>
        {% } %}
    </body>
</html>

Now you should have your demo module running. To make sure it works add the following lines to your entry point:

demoModule.run(($log) => {
    $log.info('demo running');
})

and check the console!


Going further

Create your own module

Now that our application is running let’s create a home module with ES6!

// Create a new module
let homeModule = angular.module('demo.home', []);
// Named export is needed to inject modules directly as Angular dependencies
export default homeModule = homeModule.name

Then we can import it the same way as other modules:

import home from './home/home.module.js';

// Create our demo module
let demoModule = angular.module('demo', [
    angularMaterial,
    angularUIRouter,
    home
])

Now let’s create a controller function './home.controller' that will be imported by our new module:

export default function($scope) {
    'ngInject';
}

'ngInject'; is an annotation of ng-annotate that allow us to use AngularJS in strict mode. If you want to know more about Ng-annotate here is an explanation: http://julienrenaux.fr/2015/01/18/angularjs-1-x-open-source-projects-to-follow-in-2015/#Ng-Annotate

We can then import the function that way:

let homeModule = angular.module('demo.home', []);

import HomeController from './home.controller';

homeModule.controller('HomeController', HomeController);

export default homeModule = homeModule.name

Full demo

A working example is available on Github, feel free to fork: https://github.com/shprink/angular1.4-ES6-material-webpack-boilerplate

Install

git clone git@github.com:shprink/angular1.4-ES6-material-webpack-boilerplate.git
cd angular1.4-ES6-material-webpack-boilerplate.git
npm install

Dev (liverelaod server)

npm run-script devserver

Build

npm run-script build

Introduction to Webpack with practical examples

Webpack is taking the task automation market by a storm. I have been using it for months now and for most of my needs Webpack took over Grunt and Gulp.

Webpack is a module bundler, it takes modules with dependencies and generates static assets representing those modules.

This post will only focus about Webpack “loaders” and “post loaders”.

Webpack Loaders

Loaders are pieces of code that can be injected in the middle of the compilation stream. Post loaders are called at the end of the stream.

webpack can only process JavaScript natively, but loaders are used to transform other resources into JavaScript. By doing so, every resource forms a module.

Source available on Github

Prerequisite

You will need to have Node and Npm installed on your machine to go through the following examples.

Install

npm install webpack --save-dev

Now create a webpack.config.js file and dump this basic scaffolding in it:

var webpack = require('webpack'),
    path = require('path');

module.exports = {
    debug: true,
    entry: {
        main: './index.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    module: {
        loaders: []
    }
};

You main entry point is now index.js at the root of your folder. The compiled file will be dumped in the dist folder when compiling.

Compile

When your entry point is defined you can start the compilation using the CLI:

# Debug mode
webpack

# Production mode (minified version)
webpack -p

ECMAScript 6 compilation

ECMAScript 6 introduce tones of new features (Arrows, Classes, Generators, Modules etc.) that can be used right now! To do so I recommend using Babeljs.

Installation:

npm install babel-loader --save-dev

Add the loader to the Webpack configuration:

loaders: [{
  test: /.es6.js$/,
  loader: "babel-loader"
}]

You now can require any ES6 modules using require('./src/index.es6.js');

Result

Before

// Generators
var fibonacci = {
    [Symbol.iterator]: function*() {
        var pre = 0,
            cur = 1;
        for (;;) {
            var temp = pre;
            pre = cur;
            cur += temp;
            yield cur;
        }
    }
}

module.exports = fibonacci;

After

"use strict";

var fibonacci = function() {
    var a = {};
    a[Symbol.iterator] = regeneratorRuntime.mark(function b() {
        var a, c, d;
        return regeneratorRuntime.wrap(function e(b) {
            while (1) switch (b.prev = b.next) {
              case 0:
                a = 0, c = 1;

              case 1:
                d = a;
                a = c;
                c += d;
                b.next = 6;
                return c;

              case 6:
                b.next = 1;
                break;

              case 8:
              case "end":
                return b.stop();
            }
        }, b, this);
    });
    return a;
}();

module.exports = fibonacci;

CoffeeScript compilation

Coffeescript needs no introduction, it has been popular for a long time now.

Installation:

npm install coffee-loader --save-dev

Add the loader to the Webpack configuration:

loaders: [{
  test: /.coffee$/,
  loader: "coffee-loader"
}]

You now can require any CoffeeScript modules using require('./src/index.coffee');

Result

Before

module.exports = ->
    square = (x) -> x * x
    math =
      root: Math.sqrt
      square: square
      cube: (x) -> x * square x

After

module.exports = function() {
  var math, square;
  square = function(x) {
    return x * x;
  };
  return math = {
    root: Math.sqrt,
    square: square,
    cube: function(x) {
      return x * square(x);
    }
  };
};

Require CSS files

Installation:

npm install css-loader --save-dev

Add the loader to the Webpack configuration:

The css-loader will create a style tag that will be injected into your page on run time. The css-loader also takes care of minification when called in the production mode (-p) e.g webpack -p

loaders: [{
  test: /.css$/,
  loader: "css-loader"
}]

You now can require any CSS file using require('./src/index.css');


Autoprefix CSS files

Installation:

npm install autoprefixer-loader --save-dev

Add the loader to the Webpack configuration:

What’s really annoying with CSS is that some properties are not implemented the same way by browsers. That’s the reason behind prefixes -ms- for IE, -moz- for Firefox and -webkit- for Chrome, Opera and Safari. The autoprefixer loader allow you to use the standards CSS properties without having to care for browser compatibility.

loaders: [{
  test: /.css$/,
  loader: "css-loader!autoprefixer-loader"
}]

You now can require any CSS file using require('./src/index.css');

Result

Before

body {
    display: flex; 
}

After

body {
    display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */
    display: -ms-flexbox;      /* TWEENER - IE 10 */
    display: -webkit-flex;     /* NEW - Chrome */
    display: flex;             /* NEW, Spec - Opera 12.1, Firefox 20+ */
}

Sass compilation

Sass lets you use features that don’t exist in CSS yet like variables, nesting, mixins, inheritance etc. the code created using sass is less complex and therefore easier for developers to maintain than standard CSS.

Installation:

npm install css-loader sass-loader --save-dev

Add the loader to the Webpack configuration:

Here we use two loaders at the same time. The first one the sass-loader (read from right to left) will compile Sass into CSS then the css-loader will create a style tag that will be injected into your page on run time.

loaders: [{
  test: /.scss$/,
  loader: "css-loader!sass-loader"
}]

You now can require any Sass file using require('./src/index.scss');

Result

Before

$font-stack:    Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

After

body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

Less compilation

Less is a CSS pre-processor similar to Sass.

Installation:

npm install css-loader less-loader --save-dev

Add the loader to the Webpack configuration:

Here we use two loaders at the same time. The first one the less-loader (read from right to left) will compile Less into CSS then the css-loader will create a style tag that will be injected into your page on run time.

loaders: [{
  test: /.less$/,
  loader: "css-loader!less-loader"
}]

You now can require any Sass file using require('./src/index.less');

Result

Before

@font-stack: Helvetica, sans-serif;
@primary-color: #333;
body {
    font: 100% @font-stack;
    color: @primary-color;
}

After

body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

Move files

You can move any type of file around by using the file-loader.

Installation:

npm install file-loader --save-dev

Add the loader to the Webpack configuration:

For the example let’s try to move images from their directory to a brand new image folder with a naming convention of img-[hash].[ext].

loaders: [{
  test: /.(png|jpg|gif)$/,
  loader: "file-loader?name=img/img-[hash:6].[ext]"
}]

You now can require any image file using require('./src/image_big.jpg');

Result

the image ./src/img.jpg will be copy and renamed as such: dist/img/img-a4bd04.jpg


Encode files

Sometimes you do not want to make HTTP requests to get assets. For example, what’s the point making HTTP requests to get tiny images when you can directly access them encoded (base64) ? The url-loader does just that. What you need to do is to determine the limit (in bytes) under which you want the encoded version of the file (if the file is bigger you will get the path to it).

Installation:

npm install url-loader --save-dev

Add the loader to the Webpack configuration:

When images are under 5kb we want to get a base64 of them and when they are greater than 5kb we want to get the path to them (exactly as with the file-loader).

loaders: [{
  test: /.(png|jpg|gif)$/,
  loader: "url-loader?limit=5000&name=img/img-[hash:6].[ext]"
}]

Result

Before

var imgBig = '<img src="' + require("./src/image_big.jpg") + '" />';
var imgSmall = '<img src="' + require("./src/image_small.png") + '" />';

After

var imgBig = '<img src="img/img-a4bd04.jpg" />';
var imgSmall = '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA" />';

Require HTML files

The html-loader turn any html file into a module and require any image dependency along the way!

Installation:

npm install html-loader --save-dev

Add the loader to the Webpack configuration:

loaders: [{
  test: /.html$/,
  loader: "html-loader"
}]

You now can require any HTML files using require('./src/index.html');. All images will also be treated as dependencies and therefore go through their specific stream of events (see Encode files).

Result

Before

<html>
    <head>
        <title></title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
    </head>
    <body>
        <img src="./image_small.png">
    </body>
</html>

After

module.exports = '<html>n    
   <head>
      n        
      <title></title>
      n        
      <meta charset="UTF-8">
      n        
      <meta name="viewport" content="width=device-width">
      n    
   </head>
   n    
   <body><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA"></body>
   n
</html>';

Expose any module

The expose-loader loader allow you to bind any module to the global scope.

Installation:

npm install expose-loader --save-dev

Add the loader to the Webpack configuration:

In this example we want lodash (Underscore.js decorator) to be exposed in the global scope as _.

loaders: [{
  test: require.resolve("lodash"),
  loader: 'expose?_'
}]

Now when requiring lodash (require('lodash');) will also expose it globally. It is necessary for popular modules such as angularJs, jQuery, underscore, moment or hammerjs.