Angular 2 : Organization Using {barrels}

a2barrels

The import statements in Angular 2 can get pretty cumbersome if you're using a lot of services, models, directives etc in any specific component.

Looking at the basic "QuickStart", the app.component.ts doesn't seem very obtuse.

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '<h1>Quickstart</h1>'
})
export class AppComponent { }  

However, looking at the Tour of Heroes example:

import { Component } from '@angular/core';  
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from '@angular/router-deprecated';

import { HeroService } from './hero.service';  
import { DashboardComponent } from './dashboard.component';  
import { HeroesComponent } from './heroes.component';  
import { HeroDetailComponent } from './hero-detail.component';

@Component({
  selector: 'my-app',
  template: `
    <h1>{{title}}</h1>
    <nav>
      <a [routerLink]="['Dashboard']">Dashboard</a>
      <a [routerLink]="['Heroes']">Heroes</a>
    </nav>
    <router-outlet></router-outlet>
  `,
  styleUrls: ['app/app.component.css'],
  directives: [ROUTER_DIRECTIVES],
  providers: [
    ROUTER_PROVIDERS,
    HeroService
  ]
})
.
.
.

You can see how as additional parts of the application are adding to the import area, especially if a clean / readable code approach is taken.

In a recent project, adding the Material Design 2 components caused what I call "import noise" so I used barrel to organize and reduce the impact.

import noise - this is an issue seen in languages where there are dependencies that need to be "imported", "required", or "included" and the first (1 - n) lines are non functional code.

Barrels

In the Angular 2 docs, a barrel is defined as:

"A barrel is a way to rollup exports from several modules into a single convenience module. The barrel itself is a module file that re-exports selected exports of other modules."

Material Design Example

Adding all of the components of material design takes the quickstart app.component.ts to this:

import {Component} from '@angular/core';  
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from '@angular/router-deprecated';  
import {MD_SIDENAV_DIRECTIVES} from '@angular2-material/sidenav';  
import {MdToolbar} from '@angular2-material/toolbar';  
import {MdButton} from '@angular2-material/button';  
import {MdCheckbox} from '@angular2-material/checkbox';  
import {MdRadioButton} from '@angular2-material/radio';  
import {MdRadioDispatcher} from '@angular2-material/radio/radio_dispatcher';  
import {MdSpinner} from '@angular2-material/progress-circle';  
import {MdProgressBar} from '@angular2-material/progress-bar';  
import {MD_CARD_DIRECTIVES} from '@angular2-material/card';  
import {MD_INPUT_DIRECTIVES} from '@angular2-material/input';  
import {MD_LIST_DIRECTIVES} from '@angular2-material/list';

@Component({
  moduleId: __moduleName,
  selector: 'my-app',
  providers: [ROUTER_PROVIDERS, MdRadioDispatcher, MdRadioButton],
  templateUrl: 'devsticky.component.html',
  styleUrls: ['devsticky.component.css'],
  directives: [ROUTER_DIRECTIVES, 
    MD_SIDENAV_DIRECTIVES,
    MD_CARD_DIRECTIVES,
    MdToolbar,
    MdButton,
    MdCheckbox,
    MdRadioButton,
    MdSpinner,
    MD_INPUT_DIRECTIVES,
    MD_LIST_DIRECTIVES,
    MdProgressBar],
  pipes: []
})
@RouteConfig([
])

That's 12 lines of just import noise. Quick fix is to create another file, in this case it'll live in a folder called /material-design named index.ts

Simply take all of the related modules and move the import statements from the app.component.ts file and mark them as "export * from"

export * from '@angular2-material/toolbar';  
export * from '@angular2-material/button';  
export * from '@angular2-material/checkbox';  
export * from '@angular2-material/sidenav';  
export * from '@angular2-material/radio';  
export * from '@angular2-material/progress-circle';  
export * from '@angular2-material/progress-bar';  
export * from '@angular2-material/input';  
export * from '@angular2-material/list';  
export * from '@angular2-material/card';  
export * from '@angular2-material/radio/radio_dispatcher';  

This is an import/export of the module. Now go back to the app.component.ts file and just add

import {MdButton, MdCheckbox, MdRadioButton, MdRadioDispatcher, MdToolbar, MdSpinner, MdProgressBar, MD_CARD_DIRECTIVES, MD_INPUT_DIRECTIVES, MD_LIST_DIRECTIVES, MD_SIDENAV_DIRECTIVES} from './material-design';  

This takes the 12 lines to one really long line; which could be reduced further.

import * as md from './material-design';  

That's pretty reduced! The * as md imports all of the modules and aliases as md. Depending on your editor, errors/warnings may show in the directives: portion of the component because it cannot find MD_SIDENAV_DIRECTIVES for instance.

Fix is to add the alias -> md.MD_SIDENAV_DIRECTIVES to this and any of the material design dependencies being used.

Using barrels will help make your code readable and maintainable. The Angular 2 source heavily uses these, browse through the code and you'll see this in places like @angular/core.

Enjoy.

Tweet Post Share Update Email RSS

Hi, I'm Shayne Boyer, I write this site, work on ASP.NET Core content and Open Source, speak at national and community events while helping teams architect web and cloud applications.

Tags:
angular2 materialdesign typescript