TypeScript and Gulp

Introduction

As much as I enjoy using Visual Studio, I feel that TypeScript development can be a bit more streamlined. I have investigated various tools to help out, and gulp has caught my eye. Unlike grunt, which was a contender for task automation, gulp allows the creation of automation tasks via code. In this case, we can create such tasks in JavaScript. Although grunt is quite flexible, task automation is achieved via JSON configurations. It may come down to personal preference, and in my case, I chose to dive into gulp.

Today we are going to create a simple script for building and running a typical node.js application written in TypeScript. Let’s get to it.

Install Gulp

You can install gulp via npm:

$ npm install -g gulp

You can also add the following development dependencies in your project’s package.json:

"devDependencies": {
    "gulp": "^3.8.5",
    "gulp-tsc": "^0.9.1",
    "gulp-shell": "^0.2.5",
    "run-sequence":"^0.3.6"
}

This will install all the packages we will use in our gulpfile. Note that these dependencies will only be installed in a development environment:

  • gulp: The core gulp package.
  • gulp-tsc: TypeScript compiler for gulp.js
  • gulp-shell: command-line interface for gulp.js. Useful for when we want to run the application via gulp.
  • run-sequence: run a series of tasks in a certain order. For example, build and then run.

Create a gulpfile

For gulp to work properly, we need to define gulpfile.js. Here we can define all sorts of tasks to aid in building and running our application, among other things. Let’s create a basic gulpfile that can handle building and running our application that is written in TypeScript:

var gulp   = require('gulp');
var tsc    = require('gulp-tsc');
var shell  = require('gulp-shell');
var runseq = require('run-sequence');

var paths = {
    tscripts : { 
        src : [
            './server.ts',
            'app/**/*.ts', 
            'public/**/*.ts', 
            'Scripts/**/*.ts'
        ],
        dest : './' 
    }
};

gulp.task('default', ['buildrun']);

// Run

gulp.task('run', shell.task([
    'node ./server.js'
]));

gulp.task('buildrun', function (cb) {
    runseq('build', 'run', cb);
});

// Compile

gulp.task('build', ['compile:typescript']);
gulp.task('compile:typescript', function () {
    return gulp
        .src(paths.tscripts.src)
        .pipe(tsc({
            module: "CommonJS",
            sourcemap: true,
            emitError: false
        }))
        .pipe(gulp.dest(paths.tscripts.dest));
});

This file defines a few tasks:

  • build, which compiles the TypeScript code, generating the JavaScript and map files alongside their respective TypeScript files. We can define a different destination for the generated JavaScript, but we will keep it the source and destination directories the same for now.
  • run, which executes the application.
  • buildrun, which performs a build, followed by a run.

Running the command “gulp” will build the solution and run it: image

You can also run more specific commands like “gulp build”: image

and “gulp run”: image

All Done!

So we were able to get all some gulp packages together and are able to compile and run a node application that’s been written in TypeScript.

Wait!

Although this file handles a lot of scenarios quite nicely, it’s written in JavaScript. The aim is to get as much as possible written in TypeScript. So let’s keep digging… The extension typescript-require enables the use of require for modules written in TypeScript without needing them to be compiled to JavaScript beforehand. This includes gulpfiles! So we can move all the code from gulpfile.js to gulpfile.ts, and the gulpfile.js would have the following two lines:

require('typescript-require');
require('./gulpfile.ts');

Now we add a reference to the node definition file to our new gulpfile.ts:

/// <reference path='Scripts/typings/node/node.d.ts' />

So without further modifying the actual code, and taking advantage of the fact that TypeScript is a superset of JavaScript and it should work: image

Well, that’s not good. After doing a bit of digging, it appears that there’s some kind of problem with the versions of lib.d.ts used in the different packages. Running a local search and sure enough we see a problem: image

So let’s replace that with the proper version and… success! Let’s hope typescript-require gets updated soon so this step can be avoided.

After a few modifications, we can have gulpfile.ts be a bit more TypeScript-y:

/// <reference path='Scripts/typings/node/node.d.ts' />

var gulp   = require('gulp');
var tsc    = require('gulp-tsc');
var shell  = require('gulp-shell');
var runseq = require('run-sequence');

var paths = {
    tscripts : { 
        src : [
            './server.ts',
            'app/**/*.ts', 
            'public/**/*.ts', 
            'Scripts/**/*.ts'
        ],
        dest : './' 
    }
};

gulp.task('default', ['buildrun']);

// Run

gulp.task('run', shell.task([
    'node ./server.js'
]));

gulp.task('buildrun', (cb) => {
    runseq('build', 'run', cb);
});

// Compile

gulp.task('build', ['compile:typescript']);
gulp.task('compile:typescript', () => {
    return gulp
        .src(paths.tscripts.src)
        .pipe(tsc({
            module: "CommonJS",
            sourcemap: true,
            emitError: false
        })) 
        .pipe(gulp.dest(paths.tscripts.dest));
});

Conclusion

Today we were able to get everything together to compile and run a node application that’s been written in TypeScript, using gulp instead of the tools provided by Visual Studio. We also took the extra step to get the gulp code, traditionally written in JavaScript, ported over to TypeScript. We now have a solid basis to add more tasks according to the project’s needs.

Cheers!

Advertisements

TypeScript and the MEAN Stack: Getting started Part 3

Introduction

Up until now, we set up the main tools necessary to get TypeScript and the MEAN stack up and running. We got a basic server application running against MongoDB. Today we will dive into the client side, getting a basic front-end written up using AngularJS.

Bower

Similar to npm, bower is a package manager that aids in obtaining packages for use on the front-end. Installation can be done via npm:

$ npm install –g bower

We will create two files to have bower working nicely in our project. The file .bowerrc will allow us to specify where the packages go, and bower.json works in a similar way to package.json, but for bower instead of npm:

First, .bowerrc:

{
    "directory": "public/lib"
}

And bower.json:

{
   "name": "MeanType",
   "version": "0.0.1",
   "description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, Node.js and TypeScript",
   "dependencies": {
     "bootstrap": "~3",
     "angular": "^1.2"
   }
}

Let’s go ahead and grab angular and bootstrap by running the command:

$ bower install

Now that we have the packages installed, we need to grab the type definition files for angular, bootstrap and jQuery, since angular has a dependency on jQuery. This is the exact same process described in previous posts.

Updates on the server

Updates on User Controller

The controller on the server needs to be updated to return JSON instead of plain text. We also need a method to retrieve all the users:

import express = require("express");
import mongoose = require("mongoose");
import userModel = require("../models/userModel");
 
import IUser = userModel.IUser;
import repository = userModel.repository;
 
export function createUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.create({ name: userName }, (error, user) => {
        if (error) {
            res.send(error);
        } else {
            res.jsonp(user);
        }
    });
}
 
export function retrieveUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.findOne({ name: userName }, (error, user) => {
        if (error) {
            res.send(error);
        } else {
            res.jsonp(user);
        }
    });
}
 
export function retrieveUsers(req: express.Request, res: express.Response) {
    repository.find((error, users) => {
        if (error) {
            res.send(error);
        } else {
            res.jsonp(users);
        }
    });
}

Updates on Routes

Since we updated some logic over on the server, we need to update some routes to get the desired behaviour over to the client:

indexRoutes.ts:

import express = require('express');
 
export function index(req: express.Request, res: express.Response) {
    res.sendfile('./public/views/users.html');
};

Note that the above route is to make sure that we can fire up the application and that we go straight to the users view, which will be detailed later on.

userRoutes.ts:

import express = require("express");
import controller = require("../controllers/userController");
 
/*
 * User Routes
 */
export function list(req: express.Request, res: express.Response) {
    controller.retrieveUsers(req, res);
}
 
export function create(req: express.Request, res: express.Response) {
    controller.createUser(req, res);
};
 
export function read(req: express.Request, res: express.Response) {
    controller.retrieveUser(req, res);
};

Client code

From the client side, we will go ahead and create a page for users and a controller. Angular offers many more things, but again, we are keeping this simple for now, making sure we have basic connectivity and data retrieval out of the way. Later on we will refactor this code and follow established practices.

Let’s go ahead and create the necessary files and folders in the folder public:

image

The Controller

For the sake of brevity, we will create the User class, the controller and relevant interfaces in a single file in userClientController.ts:

/// <reference path="../../Scripts/typings/angular/angular.d.ts"/>
 
module MeanUsers {
 
    export class User {
        name: string;
    }
 
    export interface IUserScope extends ng.IScope {
        vm: UserClientController;
    }
 
    export class UserClientController {
        users: User[];
        newUserName: string;
 
        $http: ng.IHttpService;
 
        static $inject = ['$scope', '$http'];
 
        constructor($scope: IUserScope, $http: ng.IHttpService) {
            $scope.vm = this;
            this.$http = $http;
 
            this.getUsers();
        }
 
        getUsers = () => {
            this.$http.get<User[]>("/users")
            .success((retrievedUsers, status) => {
                this.users = retrievedUsers;
            });
        }
 
        createUser = () => {
            var user = new User();
            user.name = this.newUserName;
            this.$http.post<User>("/users/" + user.name, user)
            .success((createdUser, status) => {
                this.users.push(createdUser); 
            }); 
        }
    }
}

The View

And now a basic view for users.html:

<!DOCTYPE html>
<html data-ng-app ="meanType">
  <head>
     <title>Users</title>
     <script type="text/javascript" src="../lib/angular/angular.js"></script>
     <script type="text/javascript" src="../app.js"></script>
     <script type="text/javascript" src="../controllers/userClientController.js"></script>   </head>
   <body>
     <div data-ng-controller="MeanUsers.UserClientController">
      <form class="form-horizontal" ng-submit="vm.createUser()">
         <input type="text" ng-model="vm.newUserName" size="30"
                placeholder="user name">
         <button class="btn" type="submit" value="add">
                     +
         </button>
       </form>
       <table class="table table-striped table-hover" style="width: 500px;">
         <thead>
           <tr>
             <th>Name</th>
           </tr>
         </thead>
         <tbody>
           <tr data-ng-repeat="user in vm.users">
             <td>{{user.name}}</td>
           </tr>
         </tbody>
       </table>
     </div>
   </body>
</html>

Putting everything together

Almost ready to go. Let’s hook up everything in app.ts:

/// <reference path='controllers/userClientController.ts' />
 
module meanExample {
     var appModule = angular.module("meanType", []);
     appModule.controller("UserClientController", ["$scope", "$http", ($scope,$http)
         => new MeanUsers.UserClientController($scope, $http)]);
}

Run the application

Once we run the application, we should be greeted with this simple view:

image

We can now enter a name and hit the “+” button. The user “angular” should appear on the list.

image

Let’s check to see what’s happening on the server. Having a look at some node output, we see a post made:

image

And finally, having a look at what’s in MongoDB:

image

 

Great! So we go a (very) basic application working!

Conclusion

Now we have successfully hooked up an application that has a Node/Express back-end, an Angular front-end, and a MongoDB data store. The application itself is very basic, having been used as an opportunity to dig into TypeScript, but is a decent starting point for further investigation. I will continue digging into these concepts, aiming to flesh out the core idea into a more fully-fledged stack for various projects.

Cheers!

TypeScript and the MEAN Stack: Getting started Part 2

Introduction

In my previous post, we got a brief idea on what TypeScript and the MEAN stack are. We installed the essential tools and put together a simple node/express application. Here, we will continue from where we left off, connecting the application to MongoDB.

Some Quick Housekeeping

Before we get started with hooking up the application with MongoDB, let’s make the following file and folder changes:

  1. Create new folder called app at the root level of the project.
  2. Move the routes and view folders to the app folder.
  3. Rename app.ts to server.ts.
  4. Rename index.ts and user.ts in the app/routes folder to indexRoutes.ts and userRoutes.ts respectively. Module dependencies should also be updated.
  5. Create a new folder called controllers in the app folder and add a new TypeScript file userController.ts to it.
  6. Create a new folder called models in the app folder and add a new TypeScript file userModel.ts to it.

The app folder should have the following structure:

image

Hooking up the application to MongoDB

We are going to create a simple entity and attempt to create and retrieve some instances, using MongoDB for persistence. There are quite a few ways to achieve this, but for the time-being, we are going to use mongoose.

Install mongoose

We can add mongoose via npm. After the package is retrieved, let’s get the mongoose definition file from the definitely typed repository and add it to Scripts/typings/mongoose.

Update server.ts

The module dependencies in server.ts should be as follows:

/*
 * Module dependencies.
 */
import express = require('express');
import routes = require('./app/routes/indexRoutes');
import user = require('./app/routes/userRoutes');
import http = require('http');
import path = require('path');
import mongoose = require('mongoose');

In the same file, we should add that we want to connect to the database:

/*
 * Main application entry file.
 * Please note that the order of loading is important.
 */
mongoose.connect('mongodb://localhost/mean-type-dev');
 
var app = express();

Create the schema and interface

For the purposes of this session, we will create a User entity with the field “name”. The file userModel.ts will contain the following:

import mongoose = require("mongoose");
 
export var userSchema = new mongoose.Schema({
    name: String
});
 
export interface IUser extends mongoose.Document {
    name: string;
}
 
export var repository = mongoose.model<IUser>("User", userSchema);

There is a bit of duplication here. Mongoose requires the use of schema definition code for data validation, type casting, etc. In TypeScript, we also need to define interfaces that extend mongoose documents. This is not ideal, and it would obviously be better if we can get the two aspects working better together. This is a topic that would require further investigation. For the time being, this will have to work.

Create the controller

My aim is to keep the controller as the entry point of the web requests and to maintain whatever application logic is needed. The controller will take the request, process the data in some meaningful way via the repository, and depending on the result, provide a suitable response.

So userController.ts will look like this:

import express = require("express");
import mongoose = require("mongoose");
import userModel = require("../models/userModel");
 
import IUser = userModel.IUser;
import repository = userModel.repository;
 
export function createUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.create({ name: userName }, (error) => {
        if (error) {
            res.send(400);
        } else {
            res.send("user " + userName +" created");
        }
    });
}
 
export function retrieveUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.findOne({ name: userName }, (error, user) => {
        if (error) {
            res.send(400);
        } else {
            res.send("user with name " + user.name + " retrieved");
        }
    });
}

Update routes

To keep the aforementioned idea, the routing files should be kept as simple as possible. This was kept in mind for the new operations in the controller that need to be exposed via userRoutes.ts:

import express = require("express");
import controller = require("../controllers/userController");
 
/*
 * User Routes
 */
export function list(req: express.Request, res: express.Response) {
    res.send("respond with a resource");
};
 
export function create(req: express.Request, res: express.Response) {
    controller.createUser(req, res);
};
 
export function read(req: express.Request, res: express.Response) {
    controller.retrieveUser(req, res);
};

Back on server.ts, let’s update the routing code:

app.get('/', routes.index);
app.get('/users', user.list);
app.get('/users/:name', user.read);
app.post('/users/:name', user.create);

Tools

We’re almost set to give it a spin. Let’s go ahead and grab some more tools that will help us with testing:

  • Any REST client. I use Postman and it suits my needs.
  • Any MongoDB management tool. My preference here is Robomongo.

Some tests

Now we can run the application and fire up a REST client. Again, keeping things simple, let’s go ahead and add the URL below and setting the method to POST. Sending the request will give us a response that the user was created:

image

Now that we created a user, we can also retrieve with the same URL and with the GET method:

image

So far, so good. Let’s just check to see that we do have something stored in our database. Using Robomongo, we add our local connection, which should appear automatically in the connections dialog:

image

The database “mean-type-dev” should be found, along with the collection users. Looking at the users collection, we find a user, which is in fact the user we created:

 

image_thumb.png

So there you have it. We now have a node application that can play nicely with MongoDB, with everything written up in TypeScript.

Conclusion

Today we were able to hook up our application with MongoDB via mongoose and perform some basic database operations. My next post will focus more on the client side, digging into angular.

Cheers!

TypeScript and the MEAN Stack: Getting started Part 1

Introduction

Two areas that have gained my attention lately are TypeScript, Microsoft’s offering in making JavaScript more attractive for use in large-scale applications, along with the MEAN stack, a collection of open-source libraries that allows the use of JavaScript for web application development. I think it would be an interesting experiment to implement a basic MEAN stack in TypeScript instead of JavaScript.Today I will delve into what it takes to get the essentials working on a Windows development environment and create a simple project in Visual Studio.

Install the essentials

Prerequisites

There is a lot of information get the MEAN stack up and running on Linux and Mac environments and less information for Windows environments, even though the process is quite straightforward. At least for this tutorial, I assume you have a machine with some version of Windows installed, along with your favourite IDE. I have Windows 7 (Not yet ready/willing to jump to 8 yet) along with Visual Studio 2013. My plan is to start with the Node.js tools for Visual Studio (More on that below) and then move on to another IDE such as Sublime Text.

Git

Git will be used for source control. Git’s popularity can’t be ignored, and I hope to release a reasonable take sometime in the near future. Git for Windows provides all the necessary tools to get Git running on Windows, along with a nice bash shell. Despite being a sucker for Windows, I’ve always enjoyed the Unix-style commands over the command prompt.

MongoDB

MongoDB provides the data storage component of the MEAN stack. More specifically, it is a document-oriented NoSQL database. Along with the benefits of availability and scalability that we get from most NoSQL databases, all data is stored in JSON-like documents, providing a nice fit with JavaScript.

Once MongoDB is installed, we can run MongoDB as a Windows Service (Make sure you run as administrator):

$ mongod --logpath "C:\path\to\logfile" --dbpath "C:\path\to\dbdir" --install

And to remove the service:

$ mongod –remove

Node.js

Node.js is a platform that allows the development of scalable server-side applications with JavaScript. In our case, node will run the compiled TypeScript code on the server. node also comes with npm, which provides a vast collection of modules that expand on what node can provide.

Packages can be installed locally to a specific project:

$ npm install <package>

Packages can also be installed globally:

$ npm install -g <package>

TypeScript

For this tutorial, Visual Studio 2013 will be used to create and compile the project. TypeScript is available with Visual Studio 2013 Update 2. In the future, command-line tools will be used, so it’s worth installing now:

$ npm install –g typescript

Node Tools

Node.js Tools for Visual Studio is still in beta, but it provides an excellent starting point for putting together a node project, especially if you are familiar with using Visual Studio.

Create a Project

Once everything is installed, we’ll create a Basic Express Application in Visual Studio:

image

Upon generating the application, we get the following project:

image

If you’re coming from a pure .NET world, there’s some new things for you:

  • The views generated are not in html, but in Jade. Jade files will be discussed in a future post.
  • Style-sheets is not written in CSS, but in a pre-processor language called Stylus.
  • The file package.json contains information on the npm packages the project depends on.

So a few things different from a standard node/express project. Obviously, there are no JavaScript files, with TypeScript files taking their place. Another point of interest are the typing files. For each of the installed npm packages, there is a type definition file, which allows the use of the npm packages with stronger type definitions in TypeScript. A vast collection of type definitions for several popular packages can be found at the Definitely Typed website. Seeing that we are there. I grabbed the latest versions of the definition files that I will be using in the project.

I see Express

If you look at the npm packages, you can see that Express is already installed as a dependency. Express sits on top of node and provides a framework to run node as a more complete web application, including the use of views, routing, etc.

I don’t see Angular

Angular is not an npm package, but it’s a framework that will be used client-side. Since the focus has been on server-side, Angular was not discussed. Angular will get its due in a future post.

Run the application

Once the npm packages are downloaded for the project we can hit F5 and see what happens. the TypeScript files are compiled into JavaScript and we get the following in a browser:

image

Success! We have a decent starting point, but we have quite a bit ahead. This is a good a place to take a breather.

Conclusion

Today we got all the necessary tools to get a simple node/express application written in TypeScript running in a Windows environment, along with having git and MongoDB installed. In part 2, I will attempt to hook up my application with MongoDB and in part 3, get angular working on the client-side.

Cheers!