MEAN.TS: Getting Started

Introduction

After putting aside some time to play around with MeanJS, I wanted to share my thoughts on getting my environment set up for migrating the JavaScript code over to TypeScript.

Get MeanJS running locally

My first task was to make sure I had everything needed to run the MeanJS code as-is from GitHub. I was fortunate to have all the prerequisites installed, including node and MongoDB, but if any further information is needed, the readme provides plenty of help.

To get everything running, I simply ran the following commands in the project’s directory:

$ npm install

$ bower install

$ grunt

If everything went well, you should be greeted with the following page on localhost:3000:

image

Add type definitions

Now that we know the code works, let’s get started with mixing in some TypeScript. We’ll start by automating the retrieval of type definition files:

$ tsd init

$ tsd query node --save --action install

$ tsd query express --save --action install

For more information on automatic retrieval of type definition files, refer to my previous post on the topic.

Create Visual Studio project and solution

Next I created new project and chose the option to use existing Node.js code:

image

Once I accept the options I just hit “Finish” when the wizard appears. Once the solution and project are created, you are greeted with the generated solution.

Just to test the compiler, we’ll just change article.server.model.js to article.server.model.ts and give it the following code:

'use strict';

/**
* Module dependencies.
*/
import mongoose = require("mongoose");
var Schema = mongoose.Schema;

/**
* Article Schema
*/
var ArticleSchema = new Schema({
   created: {
      type: Date,
      default: Date.now
   },
   title: {
      type: String,
      default: '',
      trim: true,
      required: 'Title cannot be blank'
   },
   content: {
      type: String,
      default: '',
      trim: true
   },
   user: {
      type: String, // Schema.ObjectId,
      ref: 'User'
   }
});

/**
* Article Interface
*/
export interface IArticle extends mongoose.Document {
   created: Date;
   title: string;
   content: string;
   user: string; //IUser;
}

mongoose.model<IArticle>('Article', ArticleSchema);

So let’s compile and… failed.

Well that didn’t go very well. My suspicion is that the compiler under Visual Studio is doing some strange things which I will need to investigate further. In the meantime, I’ll just use a gulp file similar to one discussed earlier to compile the project… and success!

Conclusion

So we hit a bit of a snag in getting the environment set up. Alongside with the compilation not working under Visual Studio, The IDE was very sluggish with the node project open. Although the node tools are still in beta, it is still quite disappointing considering that Visual Studio is my IDE of choice and would very much like to keep it that way. I will continue to work on this and hopefully come up with some more interesting points for discussion in the future.

Oh, and my first attempts will be up on GitHub as soon as I can make more substantial progress in my migration efforts.

Cheers!

Advertisements

My summer project: MEAN.TS

Now that I have spent several weeks looking into TypeScript and the MEAN stack, I have decided to spend the next few weeks to attempt and create a more complete application stack beyond a simple “hello world” application.

After looking at the various MEAN solutions out there, I chose to use MEAN.JS as a basis for the project. This is a popular option with great documentation and a growing community.

My plan from here is:

  1. To convert portions of the server-side code to TypeScript.
  2. To convert portions of the client-side code to TypeScript.
  3. To convert any remaining JavaScript code, such as tests, to TypeScript.

Over the following weeks, I will use this blog to track my progress, but also to share the challenges and topics of interest encountered. The code will be open source and available on GitHub.

This may end up as an interesting proof-of-concept boilerplate application, or as a catastophic mess. Nonetheless, I would not consider the outcome a failure, as the aim is to at gain some further insight in using TypeScript along with Node.js, Angular.js and Express.js. If others will find this journey interesting, then even better!

Now to create the fork and start coding…

Cheers!

Server-Side Testing with Mocha, Chai and TypeScript

Introduction

As applications grow in complexity, being able to run automated tests becomes more and more important. In this post, I will go through the basics of writing and running some tests using TypeScript, along with the help of Mocha and Chai. Although this environment can be used to run on node.js and the browser, the focus today will be on the node.js scenario.

Get everything installed

First, let’s install the npm packages we need:

$ npm install mocha --save-dev
$ npm install chai --save-dev

Let’s not forget the TypeScript definition files:

$ tsd query mocha --save --action install
$ tsd query chai --save --action install

By default, Mocha looks for tests in the “test” directory, so let’s go ahead and create it:

$ mkdir test

Create some tests

Now let’s create a basic set of tests. Let’s create a TypeScript file in the test directory with the following code:

/// <reference path="../typings/mocha/mocha.d.ts" />
/// <reference path="../typings/chai/chai.d.ts" />

/**
 * Module dependencies.
 */
import chai = require('chai');

/**
 * Globals
 */

var expect = chai.expect;

/**
 * Unit tests
 */
describe('User Model Unit Tests:', () => {

    describe('2 + 4', () => {
        it('should be 6', (done) => {
            expect(2+4).to.equals(6);
            done();
        });

        it('should not be 7', (done) => {
            expect(2+4).to.not.equals(7);
            done();
        });
    });
});

Notice how we make our assertions. Chai allows for the standard TDD-style assert, but it also allows the use of BDD styles, which can be more expressive and understandable, especially to those that aren’t concerned with the specifics of the underlying implementation.

Run the tests

After we successfully compile the code, we just need to run the following command:

$ mocha

Doing so will run all the tests that Mocha can find:

mocha

Now, let’s make a test fail. We’ll grab the second test and make an expectation that 2+4 would not equal 6:

it('should not be 6', (done) => {
    expect(2+4).to.not.equals(6);
    done();
});

Running mocha again should give the following result:

mocha-fail

Conclusion

Today we were able to setup a test environment for TypeScript code, using Mocha as a test runner, along with the BDD-style syntax provided by Chai. This provides a great approach to testing code that resides in node.js applications.

Cheers!

Some TypeScript links of interest

I was out of town over the weekend, so this is going to be a bit of a filler-post. Nonetheless, I wanted to share some links that may be of interest if you want some more information on TypeScript and tools:

  1. Introduction to TypeScript: https://www.youtube.com/watch?v=5UPMqtrbw7E
  2. The Definitive guide to TypeScript: http://www.sitepen.com/blog/2013/12/31/definitive-guide-to-typescript/
  3. TypeScript CodePlex site: http://typescript.codeplex.com/
  4. TypeScript at Build 2014: http://channel9.msdn.com/Events/Build/2014/3-576
  5. TypeScript support in Web Essentials: http://vswebessentials.com/features/typescript

Cheers!

Automating retrieval of TypeScript definition files with TSD

Introduction

In previous posts, I have described how definition files can be retrieved via the Definitely Typed website, which leads you to their GitHub repository. This is all well and good if we need to retrieve a small number of definition files, but it can be a hassle if we want to get several definition files.

Automating definition file retrieval

Thankfully, there is a node package that helps retrieve definition files in a more automated way, So let’s go ahead and install this package, known as tsd:

$ npm install -g tsd

Querying definition files

Now that we have tsd installed, we can run queries to see if we can find definition files:

image

Installing definition files

Let’s go ahead and give it a shot with a definition file. To install the definition file for, say, mongoose, we run the command:

$ tsd query mongoose --action install

If it all goes well we should get the following:

image

By default, you will find the definition file in typings/mongoose/mongoose.d.ts.

Tracking all installed definition files

We can take this all a step further and create a tsd.json file to track what definitions we have installed. If this route is chosen, it is worth removing all previously installed definition files and proceed in the following manner:

Create the tsd.json:

$ tsd init

Opening the json file will give us a few settings:

{
  "version": "v4",
  "repo": "borisyankov/DefinitelyTyped",
  "ref": "master",
  "path": "typings",
  "bundle": "typings/tsd.d.ts",
  "installed": {} 
}

The fields of interest are as follows:

  • path: Path of where the definition files will be installed.
  • bundle: Path to a .d.ts file that contains references to all installed definition files.

To install a definition file, we can run the command:

$ tsd query mongoose --save --action install

Opening the file tsd.json we get the following:

{
  "version": "v4",
  "repo": "borisyankov/DefinitelyTyped",
  "ref": "master",
  "path": "typings",
  "bundle": "typings/tsd.d.ts",
  "installed":
  {
    "mongoose/mongoose.d.ts": {
      "commit": "e6a11b3cf228eacc13006558e6c9903ac7b4975b"
    }
  }
}

Looking at the file tsd.d.ts, we can see references to all definition files:

/// <reference path="node/node.d.ts" />
/// <reference path="mongoose/mongoose.d.ts" />

We can update all installed definition files with the command:

$ tsd update -so

image

Conclusion

We have successfully been able to automate the retrieval of definition files. We can query, install and update definition files for use in TypeScript projects.

Cheers!

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!

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!