Webpack Angular ES6

A boilerplate for writing modular Angular 1.X in ES6 using Webpack.

Quick start

Install dependencies

npm install  

Dev

npm run dev  

In your browser, navigate to: http://localhost:8080/

Test

npm run test  

Production

npm run build  

Copy everything in build/ folder to the server.

Demo

Demo

Angular Modules

Instead of using the great AngularJS Seed Project, which is using Horizontal Modules, provided by the AngularJS team, I am using Vertical Modules, which is highly inspired by MEAN.JS. This helps us divide the project logic into modules that represent individual logical units and scale well for bigger projects that are more maintainable in the long term. The following Module structure and folder structure use demo example to demonstrate how it works.

Modules Structure

Application
HomeModule PostModule CommentModule UserModule
HomeController PostController CommentController UserController
HomeDirective PostDirective CommentDirective UserDirective
HomeService PostService CommentService UserService
HomeFilter PostFilter CommentFilter UserFilter
HomeRoutes PostRoutes CommentRoutes UserRoutes
HomeView PostView CommentView UserView

Folder Structure

This structure allows clear separation of functionality and concerns.

|-sass
|-images
|-modules
|---home
|-----config
|-----controller
|-------tests
|-----directive
|-------tests
|-----service
|-------tests
|-----filter
|-------tests
|-----view
|-----sass
|---post
|-----config
|-----controller
|-------tests
|-----directive
|-------tests
|-----service
|-------tests
|-----filter
|-------tests
|-----view
|-----sass
|---comment
|-----config
|-----controller
|-------tests
|-----directive
|-------tests
|-----service
|-------tests
|-----filter
|-------tests
|-----view
|-----sass
|---users
|-----config
|-----controller
|-------tests
|-----directive
|-------tests
|-----service
|-------tests
|-----filter
|-------tests
|-----view
|-----sass

Basic Usage

This boilerplate comes with a blog example. I am taking post module as an example to illustrate how the Angular work with Webpack in ES6.

API

Using JSONPlaceholder for fake Online REST API for Testing and Prototyping

Controller

export default class PostController {  
  constructor($stateParams, $location, post, user, comments) {
    this.$stateParams = $stateParams;
    this.$location = $location;
    this.post = post;
    this.user = user;
    this.comments = comments;
    this.author = 'Yang Zhao';
  }
}

PostController.$inject = ['$stateParams', '$location', 'post', 'user', 'comments'];

Directive

/*@ngInject*/
export default class Menu {  
  constructor() {
    this.template = require('../view/menu.html');
    this.restrict = 'E';
    this.scope = {};
    this.controller = HomeController;
  }

  // optional compile function
  compile(tElement) {
    return this.link.bind(this);
  }

  // optional link function
  link(scope, element, attributes, controller) {
    scope.isActive = function(viewLocation) {
      return viewLocation === controller.$location.path();
    };
  }
}

Service

/*@ngInject*/
export default class PostService {  
  constructor($http) {
    this.$http = $http;
  }

  getPosts() {
    return this.$http.get('http://jsonplaceholder.typicode.com/posts');
  }

  getPost(postId) {
    return this.$http.get('http://jsonplaceholder.typicode.com/posts/' + postId);
  }

  getUser(usreId) {
    return this.$http.get('http://jsonplaceholder.typicode.com/users/' + usreId);
  }

  getComments(postId) {
    return this.$http.get('http://jsonplaceholder.typicode.com/posts/' + postId + '/comments');
  }
}

Filter

export default () => {  
  return (input) => {
    return input + ' <a href="mailto:' + input + '"><i class="fa fa-reply" aria-hidden="true"></i></a>';
  }
}

Routes

/*@ngInject*/
export default ($stateProvider) => {  
  $stateProvider
    .state('listPosts', {
      url: '/posts',
      template: require('../view/posts.html'),
      controller: 'PostsController',
      controllerAs: 'posts',
      resolve: {
        posts: (PostService) => {
          return PostService.getPosts().then((object) => {
            return object.data;
          });
        }
      }
    })
    .state('post', {
      url: '/posts/:postId',
      template: require('../view/post.html'),
      controller: 'PostController',
      controllerAs: 'post',
      resolve: {
        post: (PostService, $stateParams) => {
          return PostService.getPost($stateParams.postId).then((object) => {
            return object.data;
          });
        },
        user: (PostService, post) => {
          return PostService.getUser(post.userId).then((object) => {
            return object.data;
          });
        },
        comments: (PostService, post) => {
          return PostService.getComments(post.id).then((object) => {
            return object.data;
          });
        }
      }
    });
}

Test (Controller)

describe('PostController', () => {  
  let controller;
  let service;
  beforeEach(() => {
    angular.mock.module(post);
    angular.mock.inject(($injector, $controller, $stateParams, $location) => {
      service = $injector.get('PostService');
      controller = $controller('PostController', {
        $stateParams: $stateParams,
        $location: $location,
        post: service,
        user: service,
        comments: service
      });
    })
  });


  it('should have correct author name', () => {
    assert.equal(controller.author, 'Yang Zhao', 'PostController has correct author name');
  });
});

Index (Post Module)

import routes from './config/routes';  
import PostService from './service/service';  
import PostController from './controller/post';  
import PostDirective from './directive/post';  
import PostFilter from './filter/post';

export default angular.module('post')  
  .config(routes)
  .service('PostService', PostService)
  .controller('PostController', PostController)
  .directive('PostDirective', () => new PostDirective())
  .filter('PostFilter', PostFilter)
  .name;

Application

import home from './modules/home';  
import post from './modules/post';  
import comment from './modules/comment';  
import user from './modules/user';

/*@ngInject*/
angular.module('app', [home, post, comment, user]);  

Download
Fork me on GitHub

Yang Zhao

Read more posts by this author.


Comment