A TypeScript Angular2 starter project walkthrough – putting it all together with Express and LiveReload

by
Tags: , , ,
Category:

Note – this is an out of date article and is being kept online for historical purposes. Some of the tools in this section are useful regardless of the version of Angular 2.x alphas or betas they are referring to, but things like the router have long since been replaced. The repository is located at github.com/angular-seed-typescript.

The Express web server is here to serve up our JavaScript and other
static front-end files. We can also use it to do far more, such as
serve up routes and JSON endpoints. But for this blog post we'll
just configure it to serve the AngularJS files and libraries.

Tell the project that we want the express and live-reload libraries
by issuing another npm install:

npm install tiny-lr connect-livereload express

(The tiny-lr library and live-reload work together in this server
detect a change in the filesystem and to notify the browser to
reload itself)

To get that to work, we have to do some heavier gulp configuration.
But it's all worth it. First, we need to write a function that
conforms to a built-in gulp watcher method's callback function.

The watcher method is gulp.watch, and the function we are
going to call looks like this (replace the stub version of this function
in gulpfile.js from the previous article with the contents below):

function notifyLiveReload(event) {
  var fileName = require('path')
                  .relative(__dirname + '/web',
                            event.path);
  tinylr.changed({
    body: {
      files: [fileName]
    }
  });
}

This little event handler recieves the notification from gulp.watch that the source code has changed, and it then notifies the tinylr plugin, which then sends a web socket alert to any connected browser that the file in question needs to be reloaded.

Configuring the Express web server

Let's serve our files. Add the following task to launch Express:

gulp.task('express', function() {
  var express = require('express');
  var app = express();
  app.use(require('connect-livereload')({
    port: 35729
  }));
  app.use(express.static(__dirname + '/web'));
  app.listen(4000, '0.0.0.0');
});

This snippet launches the Express server on port 4000, serving the
./web directory for content, and adds the connect-livereload
Express middleware, which will communicate with our LiveReload server when
the files in the application change. This represents the Server’s way of
telling LiveReload to reload all open browsers when we, as developers,
save our changes.

We also need to create a task to launch Live Reload itself,
which we do via another gulp task, livereload:

gulp.task('livereload', function() {
  tinylr = require('tiny-lr')();
  tinylr.listen(35729);
});

This small live-reload server sits on another port on your computer
(port 35729 in this case, the standard Live Reload port),
which does two things:

  • Opens a web server on port 35729
  • Establishes a web socket communication between itself and browsers (based on a simple script tag we’ll include in the application’s HTML file)

If the connect-livereload middleware is told to reload a given asset (page, CSS file, JavaScript that is compiled by TypeScript),
LiveReload:

  • sends a message to all of the LiveReload client pages about the change
  • each page script will be given a chance to force a browser page reload (we'll see that in a few steps).

And then in this way we’ll be able to keep a browser open as web developers while
we make changes incrementally to the application, compile TypeScript, and perform other
activities.

We have one more thing to do – provide the sample Angular2 application and its host
index.html page – you’ll see that we embed a script tag at the end of the
application HTML file to connect it up to LiveReload.

A simple Angular2 application for our testing

When we fire this application up, we’re going to need a basic Angular2 application.
In the src/ directory, create a new file, hello-app.ts.
Fill it with the following contents:

// The new ES6 module syntax - load
// these three objects from the
// module stored at the module search
// path under the angular2 folder,
// with a module named angular2
import { Component, View, bootstrap }
  from 'angular2/angular2';
// define the settings of the component
// (except view settings)
@Component({
  selector: 'app'     // look up the app
})
// define view-specific settings
@View({
  template: 'Hello yourself!'
})
// now define the class that will be
// used to create the instance of the
// app. This is the class file that has
// the annotations of Component and View
// on it. You can consider these classes
// as if they are controllers in Angular1.
export class HelloApp {
  constructor() {
    console.log('I am alive!');
  }
}
// tell Angular2 to fire up the application
// using this app as the root component
bootstrap(HelloApp);

The Angular app’s host page

Next, we’ll fill in the application launch page. Create index.html in
src/, and follow along with the steps below:

We'll start off
with a typical preamble, I'm attaching bootstrap (which I'd loaded
to css/bootstrap.css) and a custom app css file.

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
       content="width=device-width, initial-scale=1">
    <title>Hello, Angular 2</title>
    <link rel="stylesheet" href="css/bootstrap.css"/>
    <link rel="stylesheet" href="todo/app.css"/>
</head>

Next, we'll develop our app container area.

<body>
<div class="container">
    <h1>Say hello, Angular2!</h1>
    <app>Please wait...</app>
</div>
</body>

Now, we have to bootstrap our libraries for Angular. We'll need to
install system.js, the es6-shim for providing any ES6 JavaScript
components your app may need, and a reflection library used by
our reactive library in a later app:

<!-- ES6-related imports -->
<script src="lib/system.js"></script>
<script src="lib/es6-shim.js"></script>
<script src="lib/Reflect.js"></script>

Oh, we are also using Bootstrap, so we'll need jQuery.

<script src="../lib/jquery.js"></script>

Now we're ready to boot up our Angular2 application. Unlike
AngularJS, Angular2 requires a bootstrapping mechanism to load the
module loader and configure any dynamically loaded sources. We're
going to provide that in two scripts. First, one that configures
the System.JS loader to map certain module names to physical files.

<script>
    //configure system loader
    System.config({
        map: {
            'angular2/angular2': 'lib/angular2.dev.js',
            'angular2/http': 'lib/http.dev.js',
            'angular2/router': 'lib/router.dev.js'
            '@reactivex/rxjs': 'lib/Rx.js'
        },
        defaultJSExtensions: true
    });
</script>

Finally, we have to provide the ES5, System.JS version of any Angular2 library:

<script src="lib/angular2.dev.js"></script>
<script src="lib/http.dev.js"></script>
<script src="lib/router.dev.js"></script>
<script src="lib/Rx.js"></script>

And kick off the application itself. And from this point forward,
every other script file and asset will be loaded by the module
loader:

<script>
    //bootstrap the Angular2 application
    System.import('./js/todo/hello-app.js')
          .catch(console.log.bind(console));
</script>

Don’t forget LiveReload on the page itself

I lied, we also need the live-reload stub on our page – it’s just a
simple script tag pointing to an URL on the tiny live-reload page:

<script>document.write('<script src="http://'
    + location.host.split(':')[0]
    + ':35729/livereload.js"></'
    + 'script>')</script>

This is a toy example. We begin writing about
Angular itself in the next blog entry. However,
if this application displays 'Hello Yourself'
on the page, when we fire up the server and browse
to it, we're ready to move on to the next
step.

Final testing

If you’re ready to give this a shot, go ahead and type the following commands:

gulp setup
gulp

Go ahead and browse to localhost:4000 and see if you
can get the application to say hello to you. Feel free to save changes to the index.html file and
the application TypeScript file, and exercise modifying CSS or other assets in the src directory.

If you can get all of this to work, congratulations! You’re working on an Angular2 project!