build bricks

Gulp for Angular 1


We focus on orchestrating the build process on Gulp. I prefer gulp because it provides full flexibility on the tasks content.

The build process is based on a file structure similar to the angular guidelines

We will cover all the required tasks and required libraries that an Angular 1.x project needs in order to perform the following gulp tasks:
* Build a development environment.
– Auto refresh on js change.
– Auto css injection on less change.
* Distribution environment.

Take a look on the entire gulp file

Compile Less

The app.less file includes all the necessary less files that are required in order to build the stylesheet of the project. Our next steps are easy.

  • Keep track of source maps
  • Compile the less files
  • Concatenate them on a single file
gulp.task('compile-less', function () {
  return gulp.src('app/less/app.less')
      paths: ['app/bower_components/', 'app/less', 'app']

Application Required Files

Application Javascript

The requirement is to load firstly the pure js files and then the angular components. This is because a component mainly consists of a angular component componentName-{service/controller/...} and a module registration componentName. If we include the angular component firstly, it will try to add the component on the registered module. The registrated module does not exists yet, so it will throw an error. Our Javascript inclusion order should guarantee that it will firstly include all the pure Javascript and module registrations and secondly all the components.

Our Angular components, are postfixed by the Angular component type. This is the only way to separate the files. We should firstly include all the Javascript files that does not postfixed by the component type, and finally the Javascript files that are postfixed by the component type.

globby is all we need for our file inclusion.


function getAppScripts() {
  return globby.sync([
    '!{frontend/app,frontend/app/!(bower_components)/**}/*{' + NG_SUFFIXES.join(',') + '}.js',
    '{frontend/app,frontend/app/!(bower_components)/**}/*{' + NG_SUFFIXES.join(',') + '}.js',

Third-party Javascript/Css

We usually download all the third-party required packages using a package manager. We use Bower for package management tool. Hence, all the packages are downloaded under bower_components folder.

Each third-party library consists of an arbitrary structure. For instance, Angular contains the angular.js file in the root folder, bootstrap contains the javascript on /dist/js/bootstrap.js and the css on /dist/css/bootstrap.css.

In order to specify the paths of the third party libraries, we use two configuration files. One for Javascript and one for css.

// frontend/lib-info/scripts.json
    "name": "angular",
    "path": "frontend/app/bower_components/angular/angular.js"
    "name": "bootstrap",
    "path": "frontend/app/bower_components/bootstrap/dist/js/bootstrap.js"

All Together

We talked about creating and gathering all the application required files. We can now easily create a function that provides all those paths.

var THIRD_PARTY_SCRIPT_INFO = require('./frontend/lib-info/scripts.json');
var THIRD_PARTY_CSS_INFO = require('./frontend/lib-info/css.json');

function getIndexArgs() {
  var indexArgs = {
    appCss: 'project-name.css',
    appScripts: getAppScripts()
  return indexArgs;

Compile Index Page For Development

The main idea is to automatically assembly the index page by injecting all the required files. In order to add the paths in the index page, we use a template language that injects the dependencies as strings. We choose mustache for templating.

// frontend/app/index.mustache

<html ng-app="" lang="en">
    <link rel="stylesheet" href="{{#stripBase}}{{{.}}}{{/stripBase}}"/>
  <link rel="stylesheet" href="{{{appCss}}}"/>
      <script src="{{#stripBase}}{{{.}}}{{/stripBase}}"></script>
      <script src="{{#stripBase}}{{{.}}}{{/stripBase}}"></script>

The next step is trivial. We have to include the index.mustache and run the mustache engine, providing all the required files.

gulp.task('compile-index', function () {
  return gulp.src('frontend/app/index.mustache')
    .pipe(mustache(getIndexArgs(), {extension: '.html'}))

Development Build

Our need for an useful and elegant build during the development process is to serve the index page from localhost providing automations:

  • Refresh the page when a js or a html file is changed
  • Compile the less files when a less file is changed
  • Inject the css file on the index page (without reload) when the css files is changed
  • Compile the index page and reload the application when the index.mustache page is changed

For our needs, we will use a lightweight server that has the ability to:
* Server the files
* Refresh the current page
* Inject string on the header of the current page

Browersync provides exactly what we need.

gulp.task('serve-dev', ['compile-dev'], function() {
    port: 8000,
    server: {
      baseDir: 'frontend/app'

  gulp.task('reload', function (cb) {
  });'frontend/app/**/*.less', ['compile-less']);['frontend/app/**/*.js', '!frontend/app/project-name.js'], ['compile-js']);['frontend/app/project-name.js', 'frontend/app/**/*.html'], ['reload']);'frontend/app/project-name.css', function () {
      .pipe(browserSync.reload({stream: true}));
  });'frontend/app/index.mustache', ['compile-index']);

Distribution Build

We already talked about gathering all the required files. The extra steps that a distribution build requires is to concatenate and minify all the javascript and css files. Additionally, we should create a /dist folder that is isolated from the other folders and will contain all required files that the application needs to run. We can briefly list all the necessary steps that we need, all the files will be created on the /dist folder:

  • Collect all third party scripts, concatenate, minify (vendors.js)
  • Collect all application scripts, ng-inject, concatenate, minify (project-name.js)
  • Collect all third party css, concatenate, minify (vendors.css)
  • Collect the application css, minify (project-name.css)
  • Build index page, providing the above files (vendors.js, project-name.js, vendors.css, project-name.css)
  • Copy the html files in the dist folder, keeping the same folder structure
  • Copy all the assets (imgs, fonts, etc.)

All the above could potentially create 7 additionally tasks on the gulpfile. We almost never run the tasks of distribution build separately. We usually want to execute one gulp task and create the /dist folder. Thus, we will use a stream concatenation library.

gulp.task('compile-dist', function (cb) {
  var indexArgs = getIndexArgs();
  return eventStream.concat(
      gulp.src(['frontend/app/**/*.html', '!frontend/app/index.html'])
        .pipe(mustache(getDistIndexArgs(), {extension: '.html'}))

More actions on distribution build

We cover the basic steps that a distribution build requires. We can create a more powerful distribution build that is based on the above. The purpose of the post is to give the basic idea of building an Angular application. So, i will intuitively list some of those steps:

  • Minify images
  • Convert images to sprites
  • Versioning on files
  • Minify html, when it is possible

Take a look on the entire gulp file

About the author: John Apostolidis

Frontend developer

Leave a Reply

Your email address will not be published.