Check out our Angular Book Series.

Testing a Bootstrap Popup with Angular - Part 2

This is the second half of my article on testing a Bootstrap popup. Before reading this, you should read my post about creating a popup with Angular and Bootstrap, and the one about testing the popup component. This post will focus on testing the code that creates the popup.

Review Code

In my test sample, the code to create the popup is in the app.component.ts file. This is it:


onModalRequest():void {
const modalRef = this.modalService.open(PopupComponent );

modalRef.result.then((result) =>
{
console.log(result);
console.log('closed');
}).catch( (result) => {
console.log(result);
console.log('cancelling');
});
}

This is triggered by button click in the view. Create an instance of the modal using the modalService, which is an instance of the NgbModal. It saves that instance in another variable, modalRef. The modalRef.result is a promise, and we can use that to run code whenever the modal is closed or dismissed. The promise then() method represents a successful closure of the modal. The promise catch() method represents a dismissal. Since this is a test app, the close and dismiss methods don't do anything other than log items out to the console, but a real app may save data or update a view.

We're going to write a few tests against this code. The first will just verify that the modal opened. Then we'll open and close the modal, verifying that the result function was called. Then we'll open and dismiss the modal, verifying that the catch function was called.

Write the Tests

I put my tests in a file named app.component.test.ts. As always, we'll start with the imports. These are the Angular testing imports and the ng-bootstrap imports:


import {async, TestBed,ComponentFixture} from '@angular/core/testing';
import {NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap";

Now, load our custom components:


import {AppComponent} from "../../../../../src/com/dotComIt/learnWith/main/app.component";
import {PopupComponent} from "../../../../../src/com/dotComIt/learnWith/views/popup/popup.component";

We import the AppComponent, which contains the code we'll be testing and the PopupComponent which contains the code we'll be testing. Now, create a describe function to create the set of unit tests:


describe('AppComponent', function () {
});

Next, create a bunch of variables inside the describe:


let fixture: ComponentFixture<AppComponent>;
let appComponent: AppComponent;
let modalService: NgbModal;
let modalRef: NgbModalRef;

The ComponentFixture is used to create an instance of a component so you can access all properties, methods, and DOM elements of its HTML template. The appComponent is an instance of the component's class. The modalService and modalRef relate to the popup window that will be created.

Here is a beforeEach():


beforeEach(async(() =>
{
TestBed.compileComponents().then(() => {
modalService = TestBed.get(NgbModal);
modalRef = modalService.open(PopupComponent);
fixture = TestBed.createComponent(AppComponent);
appComponent = fixture.componentInstance;
spyOn(modalService, "open").and.returnValue(modalRef);
spyOn(console,'log').and.callThrough();
});
}));

It compiles the components on the TestBed. Remember the TestBed was configured in a base.test.ts file, which our scripts know to compile first. After the components are compiled, we get the modalService and create a modalRef by opening the component. The fixture instance of the AppComponent is stored as is its componentInstance.

Finally the beforeEach() creates two spyOn() methods. It looks at the open method of the modalService, and tells it to return the modalRef as a specific value. Then it spys on the console.log() method. Normally I would try to avoid spying on this, but since no real functionality exists inside our app this is the best way to determine if the close or dismiss methods will run on the modal popup.

Let's start off with an easy test, to see that the modal opened:


it('Modal Opened', function () {
appComponent.onModalRequest();
expect(modalService.open).toHaveBeenCalled();
});

This is pretty self-explanatory. It calls the appComponent's onModalRequest() creates the modal, and checks to see that the open method had been called, insinuating that the modal had been created.

Let's create the modal, then close it:


it('Modal Opened, then Closed', (done : DoneFn) =>
{
appComponent.onModalRequest();
fixture.detectChanges();
fixture.whenStable().then(() => {
modalRef.close();
fixture.whenStable().then(() => {
expect(console.log).toHaveBeenCalledWith('closed')
done();
});
});
});

First thing you notice is that a done() function is passed into the test function. This is a function that tells Jasmine to run the code asynchronously. This is a special Jasmine construct, and is different than the async or fakeAsync test beds which are Angular constructs. The Angular constructs have all sorts of issues if you use any sort of timer under the hood, and gave me lots of problems when I was writing the test code for the learn with app. This approach avoids those issues.

Next, the onModalRequest() method is called on the appComponent. Then we access the fixture to detectChanges(). This tells the component to process a digest cycle. It will redraw whatever needs redrawing. In our case, it waits for the modal to actually be created and opened. Then we wait until the fixture is stable using the whenStable() function. This means the modal was created and it is all good to continue. The whenStable() method returns a promise, and we execute the success function on it. Inside the success function we call a close() method on the modalRef value. We do not need to call the detectChanges() again, but we do need to wait until code is stable before running our assertion. The assertion excepts that console.log() will have been called with the value "closed". This is the hard coded result value inside the main app component code. Finally it calls the done() function to tell Jasmine that we are done running async code. This completes the test

To test the dismiss function, we use a similar approach, but I needed an extra level of waiting until the component fixture was stable before I could check for the dismiss function to have been called:


it('Modal Opened, then dismissed', (done : DoneFn) =>
{
appComponent.onModalRequest();
fixture.detectChanges();
fixture.whenStable().then(() => {
modalRef.dismiss();
fixture.whenStable().then(() => {
fixture.whenStable().then(() => {
expect(console.log).toHaveBeenCalledWith('cancelling')
done();
});
});
});
});

The code opens the modal with appcomponent.onModalRequest(). Then it calls fixture.detectChanges() to watch for the DOM changes. Then it uses whenStable() to make sure the modal opened. When it is open, it is dismissed. Then it waits until it's stable twice before running the assertion. The assertion checks that the console.log() method was called with the 'cancelling' string. Then it calls the done() function, finishing off this method.

Run it:


Gulp test

And you'll see results like this:

Final Thoughts

When researching how to test a popup with Bootstrap and Angular 4 I found a lot of conflicting information. But, I hobbled through it and found this approach which seemed to work well for me. I wrote a full 70 pages on Unit Testing in the bonus book to my Angular 4 series. Get it now!

Keep up to date by reading DotComIt's Monthly Technical Newsletter

Testing a Bootstrap Popup with Angular - Part 1

Last week's post showed you how to create a popup using Angular 4 and ng-bootstrap. This week, I'll show you how to test it. This post covers testing the popup component. Next week I'll test creating the popup.

Get a Testing Framework

You'll need a testing framework. I have my own scripts based on Karma, Jasmine, and karma-typescript. I write about this in full details in the companion book to my Angular 4 book series. You could also use the Angular CLI or scripts of your own choosing. Specifics of the setup is beyond the scope of this article, because I want to focus on the tesing technique.

Configure the Test Module

Angular includes a testing construct called TestBed. This is a module created for testing other modules and is considered the foundation of all Angular tests. We're going to create a base.test.ts file to set up the TestBed to parallel the main application. This will parallel the main application from our source app.

It doesn't matter where you create the base.test.ts file as long as it is loaded by your testing code, and your apps main module is ignored. I place it in the root of a testing directory. When the app runs in a browser, the index loads a shim library and a ZoneJS library that are required by Angular. But the tests are not run in a browser, so we need to import these scripts manually, like this:


import "core-js"
import "zone.js/dist/zone";
import "zone.js/dist/long-stack-trace-zone";
import "zone.js/dist/proxy";
import "zone.js/dist/sync-test";
import "zone.js/dist/jasmine-patch";
import "zone.js/dist/async-test";
import "zone.js/dist/fake-async-test";

This will prevent a lot of confused errors about uncaught reflect-metadata and class decorators. Now we need to import the Angular specific testing modules:


import { TestBed } from "@angular/core/testing";
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing";

This imports the TestBed which is the testing module. It also imports BrowserDynamicTestingModule and platformBrowserDynamicTesting. These are used to parallel the platformBrowserDynamic class which loads the initial application.

With these imported we can immediately initialize the TestBed:


TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());

Now import the BrowserModule which is the ng module for the browser, and the NgbModule, which contains the ng-bootstrap libraries:


import { BrowserModule } from '@angular/platform-browser';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';

Now, import the custom components from our demo:


import { AppComponent } from '../src/com/dotComIt/learnWith/main/app.component';
import { PopupComponent } from '../src/com/dotComIt/learnWith/views/popup/popup.component';

Now, configure the TestBed:


beforeEach(() =>
{
TestBed.configureTestingModule({
imports : [BrowserModule, NgbModule.forRoot()],
declarations: [ AppComponent, PopupComponent ]
}).overrideModule(BrowserDynamicTestingModule, {
set: {
entryComponents: [ PopupComponent ]
}
})
});

The first thing to notice is that I put the TestBed configuration in a beforeEach() function. What is beforeEach()? It is a special function that is part of the Jasmine testing framework. The function allows you to run code before the tests are executed. We use it to create and configure the testing module which will be used by most of our other unit tests. You can have multiple beforeEach() functions if needed, but here we only need one.

The configureTestingModule() accepts a configuration object which sets up imports for other modules and declarations for components. This is all like the @NgModule metadata in our main application. The configureTestingModule() does not support entryComponents, unfortunately. We used the entryComponents metadata to set up the component that ng-bootstrap will use to create the modal.

Thankfully there is a workaround. We daisy chain an overrideModule() method after the configureTestingModule is created to add the entryComponents metadata.

That's all we need in the base.test.ts file. Notice there is no formal export of a class. It isn't needed, since no other classes will use this explicitly. Be sure this file is compiled into your tests before your other code to avoid compile errors.

Test the Popup

Now, we're going to test the PopupComponent. There are two methods that we care to test:


onDismiss(reason : String):void {
this.activeModal.dismiss(reason);
}
onClose():void {
this.activeModal.close('closed');
}

The first is the onDismiss() method, which will occur if the user cancels the popup. It means all changes are cancelled. The second method is the onClose() method and it occurs if the user formally closes the popup with the close button.

Create a file named popup.componment.test.ts. Start with imports:


import {async, TestBed} from '@angular/core/testing';
import {NgbModal, NgbModalRef, NgbActiveModal} from "@ng-bootstrap/ng-bootstrap";
import {PopupComponent} from "../../../../../../src/com/dotComIt/learnWith/views/popup/popup.component";

It imports the async and TestBed modules. The async import is used to run a beforeEach() or it() test inside an async test zone that mocks the mechanics of asynchronous processing. Then some modal specific classes are imported from ng-bootstrap. Finally our custom PopupComponent is loaded.

Now, create a describe function:


describe('popupcomponent', function () {
});

The describe() function is a Jasmine function that defines a test suite, which is a collection of related tests. The function takes two arguments. The first argument is a string that is the name of the test suite, in this case 'Sample Tests'. The second argument is a function, which runs the tests. You can embed a describe() function inside other describe() functions if you feel it is relevant to your testing.

Create two variables inside the describe() block:


let comp: PopupComponent;
let activeModal : NgbActiveModal;

We'll define these values in a beforeEach() block and reuse them in individual tests. Look at the beforeEach() next:


beforeEach(async(() =>
{
TestBed.compileComponents().then(() => {
let modalService : NgbModal = TestBed.get(NgbModal);
const modalRef : NgbModalRef = modalService.open(PopupComponent);
comp = modalRef.componentInstance;
activeModal = comp.activeModal;
});
}));

We compile the components on the TestBed. This returns a promise, which we use to get access to the global variables our tests will need. First it creates a local instance of the modalService. It uses that modalService to open the popup and create the modalRef variable. The component instance is saved off the modalRef. And the activeModal value is pulled out of the component for easy access.

The first test:


it('should create component', () =>
expect(comp).toBeDefined() );

The it() function defines the test. It has two arguments, and the first is the descriptive name of the test. If it fails, you can use this name to determine which test actually failed. The second argument is a function that performs the test.

The test is written to be easily parsable:


expect(comp).toBeDefined()

This is called an assertion. We expect the component to be defined. This will return true if the component exists, or false if the component does not exist. This is often an easy test to run to make sure you have your configuration set up correctly.

Let's write a test for the onDismiss() method:


it('Call onDismiss()', () =>
{
spyOn(activeModal, 'dismiss');
comp.onDismiss('Some Reason');
expect(activeModal.dismiss).toHaveBeenCalled();
expect(activeModal.dismiss).toHaveBeenCalledWith('Some Reason');
});

This test uses a new command, spyOn(). The spyOn() method is used to watch an object for a method call. You can use this in tests to intercept the method and return specific values. Alternatively, you could use it to verify that a certain method was called. The spyOn() is looking at the activeModal as the first argument, and the dismiss method as the second argument. Then the onDismiss() method is called on the component. Two tests follow. One to make sure that the dismiss() function was called. And the second to make sure it was called with a specific argument, 'Some Reason'.

The test of the onClose() method operates using a similar fashion:


it('Call onClose()', () =>
{
spyOn(activeModal, 'close');
comp.onClose();
expect(activeModal.close).toHaveBeenCalled();
expect(activeModal.close).toHaveBeenCalledWith('closed');
});

Instead of spying on the dismiss method of the active modal we spy on the close method. And that is the method we check in the two assertions.

Try this out by running your tests. If you use my seed, use this:


Gulp test

And you'll see something like this:

Final Thoughts

This concludes this article, but I have another one coming out next week. It will examine the code I use to test the component that creates the popup.

If you want all this information and more, get my the bonus book to my Angular 4 book series. It shows you how to create an app from scratch, and covers Angular CLI, unit testing, debugging techniques, and how to build your own project seed.

Keep up to date by reading DotComIt's Monthly Technical Newsletter

Creating a Popup with Bootstrap and Angular

How does one create a modal window with Bootstrap and Angular 4? This post will show you how.

The Setup

First, we need a generic app. You can use the Angular CLI, or my own seed project to create one. They are all going to give you a similar code base, although the directory structure is a bit different. I'm going to continue using the seed project I created, so you may have to make minor tweaks to the setup for other options.

Next be sure to install ng-bootstrap using Node:


npm install --save @ng-bootstrap/ng-bootstrap

If using the Angular Quickstart or the DotComIt seed project, you'll have to tell SystemJS how to find it. Open the SystemJS config and add this to the map property:


'@ng-bootstrap/ng-bootstrap': 'js:@ng-bootstrap/ng-bootstrap/bundles/ng-bootstrap.js'

The seed project scripts will need to copy the Bootstrap libraries into the build directory. Just find the angularLibraries array in the config.js file and add the new entry:


'@ng-bootstrap/ng-bootstrap/bundles/ng-bootstrap.js'

Now open up the index.html file and add the bootstrap CSS:


<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" />

Create the Pop Component

Now, let's create a component that will be the popup. Create a file named popup.component.ts in src/com/dotComIt/learnWith/views/popup. First, add your imports:


import {Component} from '@angular/core';
import {NgbActiveModal} from "@ng-bootstrap/ng-bootstrap";

This imports the Component so we can create this class as a component. It also imports the NgbActiveModal. This will allow us to close the modal.

Create the @Component metadata:


@Component({
selector: 'Popup',
templateUrl : './com/dotComIt/learnWith/views/popup/popup.component.html',
styleUrls: [ './com/dotComIt/learnWith/views/popup/popup.component.css' ]
})

I named the selector Popup, although we won't need that. I also specified an external HTML template and an external CSS file. I do this as a matter of habit. The CSS file can be empty. We'll roll back to the HTML file in a bit. For now, create the class:


export class PopupComponent {
}

Not much there. Add in a constructor:


constructor(public activeModal: NgbActiveModal) {
}

The constructor will inject an instance of the NgbActiveModal class into this component using Angular's Dependency Injection syntax.

Finally, we'll add two methods. The first is to close the popup:


onClose():void {
this.activeModal.close('closed');
}

Closing the popup usually means the user is done interacting with it and wants to move on to other things.


onDismiss(reason : String):void {
this.activeModal.dismiss(reason);
}

Dismissing the popup means the user is cancelling the operation. Both methods will be referenced inside the HTML template. Overall there is not much to this Angular Component, because I left it simple for sample purposes. It could get as complex as you need it to.

Now look at the popup.component.html file. Start with a header:


<div class="modal-header">
<h4 class="modal-title">Test Modal</h4>
<button type="button" class="close" aria-label="Close" (click)="onDismiss('Cross click')">
<span aria-hidden="true">x</span>
</button>
</div>

The header includes a Title and an X button. When the X button is clicked, the onDismiss() method is called. Dismissing the modal is like cancelling it, whereas closing it usually means you are done with it.

Now, add a body:


<div class="modal-body">
Modal Body
</div>

Not much there, just some test text. Finally, add a footer:


<div class="modal-footer">
<button class="btn btn-primary" type="button" (click)="onDismiss('Close click')">Cancel</button>
<button class="btn btn-warning" type="button" (click)="onClose()">Close</button>
</div>

The footer includes two buttons. One is a cancel button which will dismiss the modal. The other is a close button. Both call the related methods inside the component.

That's all we need to create the component that will display inside the modal.

Modify the Main App Component

Open up the app.component.ts file. Modify the template to be like this:


template : '<button (click)="onModalRequest()">Open Modal</button>'

There is a single button which will call an onModalRequest() function. The onModalRequest() function goes in the class body of the AppComponent. But, first be sure that the constructor injects ng-bootstrap's NgbModal


constructor(private modalService: NgbModal) {
}

Now, look at the onModalRequest() method:


onModalRequest():void {
const modalRef = this.modalService.open(PopupComponent );

modalRef.result.then((result) =>
{
console.log(result);
console.log('closed');
}).catch( (result) => {
console.log(result);
console.log('cancelling');
});
}

First, the modalRef is created using the mmodalService.open() method. The PopupComponent is sent in as an argument, so be sure to import it. The modalRef.result is a promise object. If the modal is closed then the result function will be executed. If it is dismissed the failure function will execute. For both of these functions, I'm just outputting the results to the log. /

Modify the app.module

We need to tell the @NgModule about the popup component. First, review the imports:


import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import {NgbModule} from '@ng-bootstrap/ng-bootstrap';

import { AppComponent } from './app.component';
import {PopupComponent} from "../views/popup/popup.component";

The first two imports are from the angular library. The second one comes from the ng-bootstrap library. The final two imports related to our custom code.

Create the NgModule metadata:


@NgModule({
})

I started it empty. First, add the imports:


imports: [
BrowserModule,
NgbModule.forRoot()
],

It loads the BrowserM

Now the declarations:


declarations: [
AppComponent,
PopupComponent
],

The declarations tells the module which of our custom components need to be ready for use.

Next, bootstrap our app's main component:


bootstrap: [ AppComponent ],

Good to go!

And finally, add the PopupComponent the the entryComponents array:


entryComponents: [PopupComponent]

This is important because this is how we tell Angular to allow this component instance to be created on the fly with our code.

Finally, after the metadata, export the component class:


export class AppModule { }

Test It

Now you can test things. Open the app in a browser:

Now, click the Open Modal button:

Click the X or Cancel Button. You should see a message show up in the console:

Open it again, and click the close button:

You are good to go. I wrote this post as a prelude to testing Bootstrap Popups with Angular. Those articles will come over the next few weeks. In the meantime, get my new book series on Angular 4 which uses similar techniques.

Keep up to date by reading DotComIt's Monthly Technical Newsletter

Angular Unit Testing: How do I Fix a Platform with a Different Configuration Has Been Created?

I've run into this one a few times. You're setting up Unit Testing of an Angular application and get an error like this:

Uncaught Error: A platform with a different configuration has been created. Please destroy it first.

It's frustrating and a but confusing. If you Google on that error you'll find a bunch of stuff, but no explicit solution.

You've probably set up a TestBed configuration environment as part of your unit testing, probably like this:


import { TestBed } from "@angular/core/testing";
import { BrowserDynamicTestingModule,
platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing";

TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());

However, somewhere in the code, the non-testing modules have been loaded, probably like this:


import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

The error occurs because of the conflict between the platformBrowserDynamic() and the platformBrowserDynamicTesting(). Make sure that you exclude the source files the import and initialization of the non-test version of the library.

In your karma.conf.js file add an exclude property to the Karma configuration object, something like this:


exclude : "src/app/main.ts",

In my case, today, the error was related to a missing '/' in the excluded directory structure.

I hope this helps someone.

Why does reloading my Angular 2 App return a 404 error?

I've been having some issues with Angular 2 [now Angular 4] and the RouterModule. I put together this screencast to demonstrate the problem and how I fixed it:

Watch For Code Changes - Building Angular 2 Applications with Gulp - Part 10

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6, Part 7, Part 8, and Part 9.

There was one more thing I wanted to touch on for the purposes of this article. When changing code, I want the app to automatically be recompiled. Gulp provides built in functionality to make that happen. Iterative builds help improve performance, and get you reviewing your app in the browser without having to manually compile every time.

Watch for TypeScript changes

Create a task named buildWatch:


gulp.task('buildWatch', ['build'], function(){
}

The first thing this task does is build the application. The array before the function does this. This makes sure that we have the most recent code in the build directory before we start making changes.

Then we need to start watching for changes. We can use the watch() method of gulp to do this. First, the TypeScript files:


gulp.watch(typeScriptSource,['buildTS'])
.on('change', function(event){
console.log('File Path' + event.path);
})

The first argument to the watch() function is the glob array that points to the TypeScript source. The second argument is an array which represents the tasks to execute when a change is detected. In this case, the buildTS task is executed. When a change is detected, I chained an on() event after the watch() task. This outputs the name of the file that changed.

Let's try this:


gulp buildWatch

You should see something like this:

Notice that you are not sent back to the console prompt after running this. The task is waiting for something to happen. Change the main.ts file by adding something simple like this to the end:


console.log('something');

Then look at the console:

The changed file was output the console, and the buildTS was re-run. The buildTS task runs tslint before building the code; that has not changed.

Watch for HTML and JavaScript Changes

You can use the exact same approach for watching changes with HTML and the JS Libraries. Add these to the buildWatch task:


gulp.watch(htmlSource,['copyHTML']).on('change', function(event){
console.log('File Path' + event.path);
})
gulp.watch(javaScriptLibraries,['copyJSLibraries']).on('change', function(event){
console.log('File Path' + event.path);
})

As files are changed, the relevant tasks are rerun. I don't usually watch the Angular libraries because they are rarely changed or updated during development unless it is a big project decision.

Final Thoughts

Build scripts are important. When I started doing Angular 1 development with JavaScript, I could just use JavaScript directly in the browser and was able to push off dealing with build scripts to a future time. However, when using Angular 2 with TypeScript, the build process became much more important since a compile process is needed before you can test your code. I had to jump in earlier than I would have otherwise.

Remember, you can get all the code for this series in our seed project repository. Thank you for reading, be sure to sign up on our mailing list to get information like this direct to your inbox each month.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Creating a Production Build - Building Angular 2 Applications with Gulp - Part 9

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6, Part 7, and Part 8.

Sometimes I like to create a build intended for production servers which does not include source maps. To make that happen, I use a gulp-if plugin to conditionally decide whether to generate the source maps, or not. First, install gulp-if:


npm install --save-dev gulp-if

You'll see an install screen like this:

Now, import the gulp-if library as part of the gulpfile.js:


var gulpIf = require('gulp-if');

Before we modify the buildTS task, let's add a variable named devMode:


var devMode = true;

This is the variable we will use to determine whether or not to generate the source maps. It is set to true by default. Primarily we will change this variable as part of tasks, not as a configuration option. Review the buildTS task:


gulp.task("buildTS", ["tslint"], function() {
return gulp.src(typeScriptSource)
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(uglify())
.pipe(sourcemaps.write(mapPath))
.pipe(gulp.dest(destinationPath));
});

We want to use gulp-if as part of the two source map statements. First replace the source map init statement:


.pipe(gulpIf(devMode,sourcemaps.init()))

Instead of just calling sourcemaps.init(), we now wrap it in a gulpIf. This will check the devMode variable and conditionally init the source maps.

Also change the sourcemaps.write() pipe:


.pipe(gulpIf(devMode,sourcemaps.write(mapPath)))

With the buildTS task updated, we can now create a task for building a production version of the app. The purpose of this task is to set the devMode value to false; and then run the cleanBuild task:


gulp.task('buildProd', function(){
devMode = false;
gulp.start('cleanBuild')
});

We can use gulp.start() to run the cleanBuild task. Running cleanBuild will delete the build directory, and then run the build task to compile the TypeScript files, move the HTML, and move the JavaScript libraries.

Run the task:


gulp buildProd

You should see this:

Take a look at the build directory:

You'll notice that the maps directory is missing; meaning that the sourcemaps were successfully bypassed when running the cleanBuild. We can use this same approach to perform other actions as part of a build process. In the future, I plan to make changes to the buildProd script to force the Angular application into production mode, instead of development mode by default.

What's Next?

I have one final entry prepared for this blog series. The next one will talk about recompiling code as you make changes.

Get our white paper for even more information:

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Creating a Clean Build - Building Angular 2 Applications with Gulp - Part 8

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6, and Part 7.

This part of the series will show you how to delete the build directory and produce something that I call a clean build. This is important when refactoring code, which may leave remnants of old files in the build directory.

Delete the Build Directory

To delete a directory, we can use the NodeJS Plugin, del. This isn't a Gulp plugin, but can be wrapped in a gulp task. First, install it:


npm install --save-dev del

You'll see the install screen, like this:

Next, you can load the del library inside your gulpfile.js:


var del = require('del');

Create a glob array with everything that needs to be deleted:


var deletePath = [destinationPath + '/**']

The destinationPath variable is used, with a wild card after it. This tells the del task to delete everything. Next, create the task:


gulp.task('clean', function () {
return del(deletePath);
});

The task is named clean. It calls the del() module with the deletePath value. Run the task:


gulp clean

You'll see this:

Check your project directory:

The build directory is noticeably absent, which is exactly what we want.

Run Clean, then Build

Let's combine the clean task with the build path. To do that we'll want to run the two tasks in sequence, as we don't want the clean task to delete files the build task is creating. To do that we'll use a gulp plugin named run-sequence.

Install the plugin:


npm install --save-dev run-sequence

You'll see this:

With it installed, we can create an instance of it in the gulpfile.js:


var runSequence = require('run-sequence');

Then, create the task:


gulp.task('cleanBuild', function () {
runSequence('clean', 'build');
});

I named the gulp task, cleanBuild. It uses the runSequence library to run the clean task--which deletes everything in the build directory, and the build task--which will create a fresh build.

Run the task:


gulp cleanBuild

You'll see something like this:

You see that the clean task is run first; and after it is finished the build tasks start. This will delete the build directory and all other relevant files, and then re-generate using the other tasks we wrote about earlier in this chapter.

What's Next?

The next part of this series will create what I call a production build. The final part will show you how to watch directories for changes while the code is in development.

Sign up to our mailing list to get an expanded version of this series.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Creating a Simple Build Task - Building Angular 2 Applications with Gulp - Part 7

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6.

In previous parts of this series, we created a lot of different build tasks. One for validating the TypeScript, one for compiling the TypeScript, and a few tasks for copying JavaScript and HTML files. What if we want to run them all in one command? This article will show you how.

It is pretty simple to create a Gulp task which will run multiple other Gulp tasks:


gulp.task("build", ['buildTS', 'copyJSLibraries',
'copyAngularLibraries','copyHTML']);

This creates a new Gulp task named build. The argument to the task is an array and each element of the array is a string which represents another Gulp task. We saw this approach with buildTS task built in Part 3. In that part, the tslint task was executed as part of the buildTS task. In this case, the build task does not have its own functionality it just combines together the existing tasks.

Run this task:


gulp build

You'll see something like this:

All the tasks are run, creating a build.

What's Next?

The next part of this series will show you how to delete everything in the build directory before creating the build. I call this approach a clean build.

All the information is already available, so sign up for our newsletter to start reading right away.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Minimizing the JavaScript Code - Building Angular 2 Applications with Gulp - Part 6

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, and UglifyJS. An important aspect of modern HTML5 development is to make your JavaScript files as small and optimized as possible. The minification process shortens variable names, removes whitespace, and deletes comments. It can perform other optimizations too. The purpose is to provide a smaller download to the end user. The process can, sometimes, be significantly especially with larger applications. UglifyJS is my preferred minimizer, so we'll use that.

Install gulp-uglify

The first step is to install the gulp-uglify module. Run this command:


npm install --save-dev gulp-uglify

You'll see feedback like this:

We are ready to use Uglify in our script.

Modify Gulp Script

First, load the gulp-uglify script in the gulpfile.js:


var uglify = require('gulp-uglify');
] Now, jump to the buildTS task. Here it is in the current state:


gulp.task("buildTS", ["tslint"], function() {
return gulp.src(typeScriptSource)
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(sourcemaps.write(mapPath))
.pipe(gulp.dest(destinationPath));
});

We want to run Uglify before the source map is written, but after the TypeScript is converted. Add a single line, like this:


.pipe(uglify())

The line should be placed in the script before the source maps are written:


return gulp.src(typeScriptSource)
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(uglify())
.pipe(sourcemaps.write(mapPath))
.pipe(gulp.dest(destinationPath));

The pipe() after tsProject() calls the uglify() method. We could configure the Uglify Script with various options, but for the purposes of this sample I used the default setup.

Review the Minimized Code

Run the updated script:


gulp buildTS

See it run:

The directory structure will not have changed, but the contents of the custom JS files have. Assuming you're using our default hello world application, take a look at the app.module.js:


"use strict";var __decorate=this&&this.__decorate||function(e,o,r,t){var p,n=arguments.length,c=n<3?o:null===t?t=Object.getOwnPropertyDescriptor(o,r):t;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)c=Reflect.decorate(e,o,r,t);else for(var a=e.length-1;a>=0;a--)(p=e[a])&&(c=(n<3?p(c):n>3?p(o,r,c):p(o,r))||c);return n>
3&&c&&Object.defineProperty(o,r,c),c},core_1=require("@angular/core"),platform_browser_1=require("@angular/platform-browser"),app_component_1=require("./app.component"),AppModule=function(){function e(){}return e}();AppModule=__decorate([core_1.NgModule({imports:[platform_browser_1.BrowserModule],declarations:[app_component_1.AppComponent],bootstrap:[app_component_1.AppComponent]})],AppModule),exports.AppModule=AppModule;

This is a minimized version of the translated TypeScript code. It includes some SystemJS configuration that we didn't write manually--that was added by the TypeScript compilation. If you look closely, you see a lot of the function arguments are changed into single character values. White space and line breaks are removed. Other optimizations can be made by the Uglify library, such as variable definition optimizations. Such things are not present in the existing code.

Run the final code in the browser, and you'll find it still runs as expected, and the source maps still work.

What's Next

The next few article in this series will talk about different build techniques, and some tasks I write to handle different options. The final article of this series will show you how to build a script that will recompile your code as changes are made on the fly.

All the information is already available, so sign up for our newsletter to start reading right away.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

More Entries

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.