I suppose there are not so many people who do not know what Node.js is. You may love it, you may hate it, but you cannot deny the fact that more and more enterprises are using it to replace some parts of their system, previously written in Java, Rails or .Net.  Node.js runs in a lot of environments – starting from large, multi-core servers, through laptops, then microcomputers like Rasperry Pi, finishing on IoT devices. Thanks to it, JavaScript became the language used both on client-side and on the server-side, and to make it more tangled – both those ‘sides’ intermingle forming what is now called Universal / Isomorphic Applications. Another positive aspect is performance – the advantages of using async I/O are well described through the Internet, so I will not repeat it here once again (https://en.wikipedia.org/wiki/Asynchronous_I/O, https://strongloop.com/strongblog/node-js-is-faster-than-java/, http://abdelraoof.com/blog/2015/10/28/understanding-nodejs-event-loop/).

Within this article I will show you how to start developing Node.js App Service on the Microsoft Azure Platform with the use of Typescript. Let’s start!

Start by creating a directory for our new project and run

npm init

The creator will ask us some questions, needed to generate the package.json file. This file contains the metadata of our application, alongside with dependencies and scripts that can be executed during various lifecycle events of our application. The sample answers to the wizards are as follows:

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (Temp) node-azure-ts
version: (1.0.0)
description: Node.js Azure app sample written in TypeScript
entry point: (index.js) app.js
test command:
git repository:
keywords:
author: piotr.gasiorowski@epikia.eu

license: (ISC)
About to write to C:\Users\Piotr\Temp\package.json:

{
"name": "node-azure-ts",
"version": "1.0.0",
"description": "Node.js Azure app sample written in TypeScript",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "piotr.gasiorowski@epikia.eu",
"license": "ISC"
}

Is this ok? (yes)

Pressing ENTER at this moment creates the above-mentioned package.json file.

As I told you before, package.json file is responsible for managing dependencies of our application. We can divide those into two groups: Production dependencies and Development dependencies. As the names suggest Production dependencies will contain modules that are required for the application at runtime (no matter, whether it’s a production / staging / test environment) and Development dependencies contain tools, helpers, compilers, transpilers… everything that we need for development and/or build process. Knowing this, it’s high time we installed some our dependencies:

npm install --save body-parser debug express morgan

Dissecting this command into pieces:

  • npm install is the beginning of the command responsible for installing dependencies
  • –save saves the dependencies as Production dependencies in package.json
  • body-parser debug express morgan are the names of packages that our application will depend on

Similar command can be done to install Depeloment dependencies:

npm install --save-dev typescript typings

Let’s now look at what happened to package.json file:

"dependencies": {
"body-parser": "^1.15.2",
"debug": "^2.2.0",
"express": "^4.14.0",
"morgan": "^1.7.0"
},
"devDependencies": {
"typescript": "^1.8.10",
"typings": "^1.3.1"
}

The packages are there, their versions (newest stable ones are picked if version not specified explicitly) and some ‘strange’ signs before the versions. This sign (^) and (~) are both used to specify the version of the package that we allow to be installed when we will be running npm install command on the application without dependencies installed. By specifing exact version (e.g. ‘1.5.1’ you attach to this specific version). If ‘~’ proceeds your version number – it means that we don’t care about the ‘hotfix’ part of the version (e.g. ‘~1.5.1’ will match 1.5.1, 1.5.2, 1.5.3 but not 1.6.0). If you put ‘^’ before you version it means you don’t care about ‘minor’ part of the version (e.g. ‘^1.5.1 will match 1.5.1, 1.5.2, 1.6.0, 1.7.3, but not 2.0.1).

The Production dependencies are parts of famous Express framework which is both extensible and easy to start with. It’s used for building web applications and HTTP-based microservices running on Node.js. We will learn some of it’s base features a little bit later.

The more important part are actually the Development dependencies:

  • typescript is a TypeScript compiler. TypeScript is an open source programming language developed and maintained by Microsoft. It was designed with two main principles – to be a JavaScript for C# developers and to follow the future ECMAScript specifications, so that at some point in future you will only need to replace .ts (standard TypeScript source file extension) with .js and disable transpilation to JavaScript to make it work directly in the browser. The main strengths of TypeScript are type annotations and strong type interference, type system and JavaScript interoperability.
  • typings is a new manager for TypeScript Definition Files (.d.ts). What are those files? In order to maintain the interoperability between a strongly typed language and a dynamic one, there must be some layer that would describe types, interfaces, methods and properties that can be used.

This is exactly the role of TypeScript Definition Files. The example file (for JQuery) looks like this:

interface JQueryStatic {

ajax(settings: JQueryAjaxSettings): JQueryXHR;
ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR;

ajaxPrefilter(dataTypes: string, handler: (opts: any, originalOpts: JQueryAjaxSettings, jqXHR: JQueryXHR) => any): void;
ajaxPrefilter(handler: (opts: any, originalOpts: JQueryAjaxSettings, jqXHR: JQueryXHR) => any): void;

ajaxSettings: JQueryAjaxSettings;

ajaxSetup(options: JQueryAjaxSettings): void;

...

add(html: string): JQuery;
add(obj: JQuery): JQuery;

children(selector?: string): JQuery;
}

declare module "jquery" {
export = $;
}

No special knowledge is required just to note that it describes some of JQuery methods, with arguments and returned types… and yes – people are providing those for most of JavaScript libraries… and even better – you can write them yourself… or more – extend safely and seamleassly them if you provide plugins or extensions to existing JavaScript libraries.

OK. We have JavaScript files, we’re going to write in TypeScript… what do we miss? Yes – definition files.

Hopefully, we won’t need to write them ourselves, they are ready to be used, but before that some history to stop the confusion. At first all the definition files were stored in a single GitHub repository and you had to download them manually or clone the whole repo (they are still there – ), then came TSD which was basically downloading files from the specific state of git repository. At some point in time the team behind TSD decided to rewrite the tool (the reasoning behind that – ) and that how Typings came into being. Right now it supports various sources: starting from local files, through DefinitelyTyped repo and other GitHub repos, finishing with NPM and Bower.

Let’s create typings configuration file then. Just run

 .\node_modules\.bin\typings init

Why ‘.\node_modules.bin...’? – Local vs Global We implicitly decided to install as many modules, as possible locally. This approach shows us clearly what are the dependencies needed to run our application. You cannot always expect that you will have access to the console to install some global dependencies and specifying dependencies as local makes them easily installable on target environments.

This file will soon contain the required links to definition files, let’s fill it with them:

 .\node_modules\.bin\typings install dt~node --save --global

Again, dissecting the command into parts, we are running the typings application that installs the typings for node from dt (shortcut for DefinitelyTyped GitHub repository, general convention is [source]~[packagename], for more information, run typings install –help), saves this fact to the typings.json file, so that later running typings install will install it. Option –global marks the dependency typing as globally accessible (no need to require(‘..’), think of ‘global’ in the sense of ‘window’ or ‘process’), or as exposing global variables. Keep in mind that typings installer will inform you, if you’re trying to install global package as non-global:

typings ERR! message Attempted to compile "express" as an external module, but it looks like a global module. You'll need to enable the global option to continue.

Having this in mind, let’s install typings for express:

 node_modules\.bin\typings install dt~express --save --global

How to find typing? – The answer to that question if fairly easy – just run typings search to obtain the information about both typing name and the source from which to install it.

While installing typings for express you surely noticed the following information:

typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/serve-static/serve-static.d.ts" during installation from "express" (main)
typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/express-serve-static-core/express-serve-static-core.d.ts" during installation from "express" (main)

This one happens when you install typings from DefinitelyTyped GitHub repository, as some of the typings depend on others, but DefinitelyTyped repository does not have the dependency system on its own, that is why the team behind typings decided not to download any reference typings – we have to do it manually (recursively, and for all the reference package.json dependencies):

node_modules\.bin\typings install dt~serve-static --save --global
node_modules\.bin\typings install dt~express-serve-static-core --save --global
node_modules\.bin\typings install dt~mime --save --global
node_modules\.bin\typings install dt~body-parser --save --global
node_modules\.bin\typings install dt~express-debug --save --global
node_modules\.bin\typings install dt~morgan --save --global
node_modules\.bin\typings install debug --save

Ok, now we reached the point when we can actually do some coding:

Let’s create a very simple set of files:

app.ts:

import * as debugFactory from 'debug';
import * as http from 'http';
import * as express from 'express';
import * as path from 'path';
import * as logger from 'morgan';
import * as bodyParser from 'body-parser';

import sampleRoute from './routes/sample';

let debug = debugFactory('app:server');

let staticsPath = __dirname;

let app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(staticsPath, 'public')));

let port = process.env.PORT || 3000;

app.set('port', port);

app.use('/', sampleRoute);

app.use(function(req, res, next) {
var err = new Error('Not Found');
(err).status = 404;
next(err);
});

var server = http.createServer(app);
server.listen(port);
server.on('error', function(err) {
console.error(err);
});
server.on('listening', function () {
var port = server.address().port;
debug('Listening on ' + port);
});

routes/sample.ts

///

import * as express from 'express';
let router = express.Router();

/* GET home page. */
router.get('/', function {
res.json({
title: 'Hello Express'
});
});

export default router;

This is a basic rewrite of the standard express-generator project, with a lot of things removed for the sake of simplicity. It should not make any trouble for anyone knowing JS / TS to read this code. The most interesting part is in the first line of those files – the  /// <reference…  is needed for IDE to do proper code intelisense (Visual Studio Code needs it until first compilation, Visual Studio 2015 does not, not sure about the others).

So you would like to compile the source (TypeScript) files into a proper JavaScript? For this you would need another config file – this time it’s tsconfig.json. This file basically describes the TypeScript compiler behavior. The very basic structure that you need is:

{
"compilerOptions": {
"module": "commonjs"
},
"exclude": [
"node_modules"
]
}

where we only specify the type of JavaScript module system (Node.js uses CommonJS), then we can either specify the list of files to include or files to exclude. For this example, we would like to inform TypeScript compile not to look into node_modules for sources.

Too simple? – For more information about tsconfig.json please visit https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

Let’s compile our code then – all you need to do is run:

.\node_modules\.bin\tsc

Now start the application:

node app.js

Let’s visit http://localhost:3000 just to see:

![It's running]

 

Great – we have it working locally, now let’s put it as Azure App Service.

There’s more! Everything concerning Node.js and TypeScript that we created in the course of this article is provided to you as the starter pack on my GitHub account:

For that we need to install a tool called ‘Azure CLI’ – a multiplatform Azure management tool. This time (and only this time) we will install it globally:

npm install -g azure-cli

After a while the tool is ready to rock… Well not exactly, as the App Services need to be deployed using Resource Manager (or so called Azure v2), we need to swich the mode of Azure CLI to RM, which can be simply done by:

azure config mode arm

If this or command fails with with ‘unauthorized’ error you will need to login with:

azure login

Let’s now create Azure Resource Group for our Appliaction Service. A Resource Group is a logical grouping of Azure-based assets used by application / department, optimally deployed at billed as one. For this let’s run:

azure group create node-azure westeurope

Besides the obvious parts of the command, you should supply the name of the Resource Group and it’s location.

Now let’s create the App Service Plan now. The App Service Plan is the Web Server Farm that will host our App Service:

azure resource create node-azure node-azure-server "Microsoft.Web/ServerFarms" -l westeurope -o "2015-06-01" -p "{\"sku\":{\"tier\": \"Standard\", \"name\": \"S1\"}, \"properties\": {\"numberOfWorkers\": 1, \"workerSize\": 0} }"

That one is even more complicated. It is because of the fact that Azure CLI does not allow us to create the App Service Plan with a dedicated command – we need to do it by creating generic resource in our Resource Group (node-azure), in the same location as the resource group and specify the API version (could not make version “2015-08-01” to work) and specifying the options in the JSON file. For more information, please visit https://azure.microsoft.com/pl-pl/documentation/articles/azure-web-sites-web-hosting-plans-in-depth-overview/

Now, let’s create the App Service itself at last:

azure webapp create node-azure azure-node-ts-test westeurope node-azure-server

After having created all the necessary Azure resources, this command should be self-explanatory. Let’s check https://portal.azure.com/ to see whether it created the App Service:

![Azure Portal]

So we have the Node.js application (transpiled from TypeScript to JavaScript) and the Azure App Service, now we need to setup deployment of the App Service. For now, we will try the simplest solution – we will be deploying from local Git repository. There are multiple options available – like deployment using VSTS, deployment from GitHub or BitBucket, but for now, let’s keep it simple.

In order to configure local Git deployment for our App Service we need to visit Azure Portal, go to our App Service’s Settings, scroll down to see ‘Deployment source’ and choose ‘Local Git Repository’ as depicted in the screenshot below:

![Azure Portal]

Note the change on the App Service’s card – new deployment information is show there. Please also change the Deployment Credentials (to setup the password that will be used to deploy App Service to Azure).

Provided that our App Service is in the Git repository (if not  git init  then git commit -a -m “Initial Commit”) we need to setup Azure App Service deployment source as Git remote origin:

git remote add origin https://DEPLOYMENT_USER@azure-node-ts-test.scm.azurewebsites.net:443/azure-node-ts-test.git

and push it to origin

git push origin master

After a while, you will be able to see that the deployment is complete. Curious to run the App Service? Let’s try… Two things may happen now:

  1. If you added .js files to .gitignore, you will not be able to run the App Service
  2. If you did not – the App Service will show you the same output as for local environment

Let’s not concentrate on point 2. as this is not a correct situation (you probably don’t want to keep the output of the transpilation inside your git repository). Curious reader might have observed that when the git push command sent finished sending files, it looks for app.js/server.js file (we intentionaly named the entry point to our App Service as app.ts – transcompiled to app.js) and runs npm install –production. You think – still no place for transpilation? – you may be wrong. NPM supports scripts executed at various points of application lifecycle and one of them is called postinstall, let’s do the compilation at that point, and modify the package.json file to reflect this change:

"scripts": {
"postinstall": "typings install && tsc"
},

Let’s commit this change, push it to origin and… at this point, you will notice the mistake that we made in the early stage of our development. Both typescript and typings packages are Development Dependencies and will not be installed on production environment. For the sake of this tutorial – let’s move them to Production Dependencies. The other thing that may fail is the Node.js version – by default it’s 4.2.2. This article was created using Node.js 6.2.2 and this fact needs to be explicitly set in package.json:

"engines": {
"node": "6.2.2"
}

Commit the changes and push them to origin to observe the working App Service on Azure:

![Node TS on Azure]In this article we walked the long road starting from creating the Node.js + TypeScript application and it’s simple build workflow and finishing with publishing this application as Azure App Service. There are still some improvements to be done, but this article should give you some insight on the interesting topic of creating and running Node.js applications on Azure.

4 comments

  1. Comment by Nikola Stjelja

    Nikola Stjelja Reply 15 July 2016 at 08:09

    Love the article. By why use Node.js on Azure App Services while we have good old ASP.NET MVC?

    • Comment by Piotr Gasiorowski

      Piotr Gasiorowski Reply 15 July 2016 at 14:42

      The reasons for using Node.js instead of ASP.Net MVC are numerous. The ones I can now think about are:
      1. Performance (especially on environment where you have 1 or 2 processor cores) + Async I/O
      2. More APIs for ‘non-dot-net’ solutions (not always stable, but still…)
      3. Memory footprint
      4. ‘JavaScript everywhere’ or Isomorphic / Universal JavaScript (about which I’m going to write in the next post).

  2. Pingback: dotnetomaniak.pl

  3. Comment by Piotr Gasiorowski

    Piotr Gasiorowski Reply 22 September 2016 at 09:50

    As we are experiencing some problems with markdown rendering, we had to change some parts of sample code (replacing arrow functions with the ‘classic functions’). In all the places when you see ‘classic functions’, those can be replaced with arrow functions.

Your thoughts?

Close
Go top