Back our Angular 4 Book on Kickstarter.

Building Angular 2 TypeScript Applications with Gulp and Browserify

I've been dealing a lot with build processes and build scripts lately. This blog post will show you how to build Angular 2 applications with Gulp discuss some of the limitations I found with the approach.

When reading the TypeScript docs, Browserify is the tool of choice for compiling TypeScript with Gulp. I wanted to see if I could get it working when dealing with Angular applications.

For the purposes of this post; I'm not going to review a TypeScript / Angular 2 application; I'm just going to use a simple Hello World from the Angular 2 docs.

The Setup

First, you'll need to install the required nodeJS Dependencies. Instead of installing everything independently, just copy this into a package.json file:


{
"name": "Angular2TypeScriptGulpBrowserifySample",
"version": "0.0.1",
"description": "DotComIt Project Sample for building Angular 2 Apps with TypeScript, Browserify, and Gulp.",
"author": "Jeffry Houser",
"license": "ISC",
"dependencies": {
"@angular/common": "~2.4.0",
"@angular/compiler": "~2.4.0",
"@angular/core": "~2.4.0",
"@angular/forms": "~2.4.0",
"@angular/http": "~2.4.0",
"@angular/platform-browser": "~2.4.0",
"@angular/platform-browser-dynamic": "~2.4.0",
"@angular/router": "~3.4.0",
"angular-in-memory-web-api": "~0.2.2",
"systemjs": "0.19.40",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.8",
"rxjs": "5.0.1",
"zone.js": "^0.7.4"
},
"devDependencies": {
"browserify": "^13.3.0",
"gulp": "^3.9.1",
"tsify": "^3.0.0",
"typescript": "^2.1.4",
"vinyl-source-stream": "^1.1.0"
},
"repository": {}
}

Run this command:


npm install

To install everything. The dependencies are all the relevant Angular 2 Modules. The devDependencies are all the node projects used in the gulp script:

  • Browserify: Browserify is a tool for concatenating JavaScript files into a single one.
  • Gulp: Gulp is our script runner tool.
  • tsify: A Browserify plugin to compile TypeScript files
  • TypeScript: The module used for compiling TypeScript.
  • Vinyl-Source-Stream: Vinyl is the format used by Gulp. This task will convert Browserify output into something Gulp can use.

With everything installed, we are ready to start writing our Gulp Scripts.

TypeScript Configuration

We'll want to configure the TypeScript compiler to make things work. Just create a file called tsconfig.json in the application's root directory:


{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
}
}

I'm not going to expand on the details of this for the purposes of this sample. I think I borrowed it from one of the samples on the TypeScript web site.

The Gulp Script

Start with an empty Gulp Script, named gulpfile.js, and import the required libraries:


var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");

Now, create a few variables. First, the source root:


var sourceRoot = "src/";

For all my projects, I put the source in a directory named src. Also, define the final minimized JavaScript file:


var javaScriptDestinationFile = 'app.min.js';

I named it app.min.js, but you can change it if you need to.

Define the final destination path:


var destinationPath = 'build';

I always build my projects into a directory named build.

Finally, we are going to define something called the entry. This is the first TypeScript file that defines the application. All other TypeScript files will be referenced from the initial application entry point:

var appEntries = [sourceRoot + 'main.ts']

The file is named main.ts.

Let's create the gulp task:


gulp.task("buildTS", function () {

}

I named the task buildTS, for Build Type Script. This is a common convention I use with a lot of project setups. Right now the task does nothing, let's add in browserify:


return browserify({
entries: appEntries
})

The Browserify task specifies the appEntry, but has no other properties in its configuration object.

By default Browserify does not handle TypeScript. That is what we use the tsify plugin for. The dot notation is used to chain other commands off the browserify object, so let's add in the plugin:


.plugin(tsify)

The plugin will know to look for the tsconfig.json file for configuration options. That is all that is needed for Browserify to support TypeScript code.

Next, create a bundle:


.bundle()

This is the browserify command to run the script and return the processed files. We need to turn that browserify return object into a Vinyl stream:


.pipe(source(javaScriptDestinationFile))

Thankfully we had a NodeJS plugin just for that. Next, specify the final destination of the file:


.pipe(gulp.dest(destinationPath));

This successfully creates the final file.

Run the task, like this:


gulp buildTS

You'll see some results like this:

Look in your application's directory and you should see a build directory like this:

Don't forget to copy the JavaScript and HTML libraries.

Even though Angular is primarily a TypeScript framework, it does rely on a few JavaScript libraries to run in the browser. We want to copy those from our node_modules directory to the build directory. This gulp script will do that:


var htmlSource = [sourceRoot + '**/*.html'];
var destinationPathForLibraries = destinationPath + '/js';
gulp.task('copyJSLibraries', function () {
gulp.src(htmlSource)
.pipe(gulp.dest(destinationPath));
gulp.src(['node_modules/core-js/client/shim.min.js'])
.pipe(gulp.dest(destinationPathForJSLibraries + '/core-js/client'));
gulp.src(['node_modules/zone.js/dist/zone.js'])
.pipe(gulp.dest(destinationPathForJSLibraries + '/zone.js/dist'));
gulp.src(['node_modules/reflect-metadata/Reflect.js'])
.pipe(gulp.dest(destinationPathForJSLibraries + '/reflect-metadata'));

});

I made it simple and it copies the three JavaScript files required by AngularJS in the browser: shim; zone; and reflect. An explanation of these libraries is beyond the scope of this article. This script also copies the HTML files from the src directory to the build directory.

Run the script:


gulp copyLibraries

You should see simple results like this:

Check the build directory to see the final files.

The hello world should run now. That's awesome.

What's Wrong Here?

I didn't cover it here; we this approach does allow us to generate source maps and run the final JS code through a minimizer. However, I stopped moving down this path because the generated JS file includes all the Angular libraries. That made it very big. I tried some experimentation, but could not get the application working when separating the Angular framework libraries from the custom application code.

I made the decision that the inability to separate the framework from my custom code was a deal breaker and abandoned this approach.

Final Thoughts

Since I gave up on this approach, what comes next? I'll be writing more about that in the coming weeks. Instead of using Browserify and tsify, I started using a Gulp TypeScript library directly to build the applications. This gave me the flexibility I needed to separate Angular and my custom code.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.