Mikael's blog

A developers seventh time trying to maintain a blog

The Gift of Source Code

I’m not sure if anyone is interested in my source code for this blog, but since I’ve already posted some bits and pieces of it from time to time, I thought, why not release it all?

If your browser has a width of more than 720 pixels, you will see a new button in the menu labeled “Source code”. Feel free to browse, and enjoy!

DISCLAIMER: Not all of my code is that pretty and I’ve been meaning to refactor some of it.

In other news, I’m leaving for the west coast tomorrow morning, so this might be my last post this year. It all really boils down to how tired I will be after playing with all my lovely nephews and nieces all weekend.

Merry Christmas and Happy New Year!

by Mikael Lofjärd

A Tiny Bug

I’ve been using (and still am in production) an old JavaScript function called parseInt when parsing my DateTimes for comments and posts. For some reason it showed some weird behavior today.

I noticed a comment that was written on December 0. I looked it up in the database and it turns out it was actually written on December 8. Now the 8 should have been parsed from the DateTime 2011-11-08 ... into the string "08" and then I assumed parseInt should have gotten rid of that extra 0 for me.

I found my problem in the parseInt documentation over at w3schools.

The parseInt() function parses a string and returns an integer.

The radix parameter is used to specify which numeral system to be used, for example, a radix of 16 (hexadecimal) indicates that the number in the string should be parsed from a hexadecimal number to a decimal number.

If the radix parameter is omitted, JavaScript assumes the following:

If the string begins with “0x”, the radix is 16 (hexadecimal)
If the string begins with “0”, the radix is 8 (octal). This feature is deprecated
If the string begins with any other value, the radix is 10 (decimal)

parseInt works fine for the strings “01” through “07” and of course for any string beginning with a “1”. The deprecated “string begins with a zero”-feature was the culprit.

So today I learned something new; use Number() instead.

by Mikael Lofjärd

Client-side JavaScript Initialization

Yesterday I started using the BundleController with my JavaScript files on the client-side. I also deployed my ViewManager so that all my views now uses the bundled and minified JavaScript file produced when I start (or restart) my Node.js server.

This meant that all my JavaScript was being run on every page in the blog, and while it isn’t that much JavaScript yet I still wanted to improve on it.

I decided to make use of some closure magic and built something like this:

if (typeof(BlogPageFunctions) == 'undefined') {
  BlogPageFunctions = {};
}

BlogPageFunctions.admin = function () {

  // query some objects with jQuery here,
  // bind up some events etc.
  ...

}

I use the above pattern on all my page specific JavaScript code. For now, this amounts to two functions living on the BlogPageFunctions object, admin and comments. I made these regular functions instead of IIFEs because I only want them to run on their respective pages.

So how do I make them load? I could of course just written some script code into the template itself, but that would have created a lot of copy-and-paste code since it would have to include jQuery’s if-document-ready-stuff on every page and I wanted to keep the intrusion of JavaScript inside my templates as minimal as possible.

If you remember my BundleController it had a sorting function in it that was used to prioritize certain JavaScript and CSS files so that they would load before others. I used that to make sure that if I have a JavaScript file named init.js then I would add it AFTER all my other files in the bundle.

Inside init.js is where I execute the initialization code for each page:

$(document).ready(function () {

  if (typeof(BlogPageMetaData) != 'undefined') {
    for (var i in BlogPageMetaData.init) {
      BlogPageFunctions[BlogPageMetaData.init[i]]();
    }
  }

});

But what’s this BlogPageMetaData thing you ask? That’s what I put into my templates for the pages that need some kind of JavaScript on them. This code is from the top of my admin page template:

{{>header}}
  <script>
    if (typeof(BlogPageMetaData) == 'undefined') {
      var BlogPageMetaData = {};
    }
    BlogPageMetaData.init = ['admin'];
  </script>
  <section class="admin">
  ...

I create a BlogPageMetaData object (if it doesn’t exist already for some reason) in the global scope and then I add an array of function names for init.js to call when the page has finished loading.

This way I get the best of two worlds; I get to have ONE JavaScript file that is cachable by the browser, and I don’t run unnecessary JavaScript code on pages that doesn’t need it.

by Mikael Lofjärd

Architecture in JavaScript - Closures

Today is Tuesday, which for me means I’ve held another tutorial at work. Today it was less hands-on and more of me just talking and showing examples on the projector using the wonderful jsfiddle JavaScript quick-hack-tool.

My talk today was mostly about closures, so I thought I should write something here on the subject as well.

I find that it’s not that easy to explain closures using just words, but if I were to try it would go something like this.

  • A closure is a functions variable scope that still exists after the function has executed.
  • A closure only exist as long as something else has a reference to something that needs it.
  • A closure is created when an outer function has inner functions.

If you have no idea what I meant with any of that, then I hope these examples will clear things up: (I know they did for me)

Example 1

function saySomeThing(something) {
  var text = 'Hello ' + something;
  var innerFunction = function () {
    alert(text);
  };
  return innerFunction;
}

var say = saySomeThing('World');

When saySomeThing('World') is called, it returns an inner function. A closure is created that lets innerFunction access the text variable even after saySomeThing has finished executing.

If we were to run say(); after this it would popup an alert with the text Hello World.

Now, if you’re used to languages without closures, it would be easy to think that innerFunction has been “pre-compiled” into alert('Hello World'); but that is not the case. In fact, if we were to run say.toString(); the output would be function () { alert(text); } even though our say variable is clearly not in the same scope as text. But it works because the function pointer to innerFunction that saySomeThing returns contains a reference to the closure created when we executed saySomeThing('World');.

Every call to saySomeThing would create a new closure. If the old closure is no longer referenced, for example if we were to run say = saySomeThing('Goodbye'); then the old closure previously reference by the say variable would be garbage collected.

Example 2

var AlertNumber, IncreaseNumber, SetNumber;

function setupGlobals() {
  var num = 10;

  AlertNumber = function () { alert(num); }
  IncreaseNumber = function () { num++; }
  SetNumber = function (x) { num = x; }
}

In the above code, every call to setupGlobals would create a new closure and thus create a new num variable with the value 10, but a call to IncreaseNumber would reference the current closure and increase the internal num variable by 1.

Closures in C#

A question that I got today was: “What other languages uses closures?“. I know there are a few I’ve read about somewhere on the internet but I couldn’t really name them right there and then.

But then on my way home I started thinking about C# and I had an idea. Wouldn’t closures be possible now that C# has anonymous functions (lambdas), anonymous objects and the Action<> and Func<> types? And it is. If I would have googled it instead of trying for myself I would have found that out in about 2 seconds, but where’s the fun in that?

public object Closure()
{
  var number = 10;

  Action showNumber = () => MessageBox.Show(number.ToString());
  Action increaseNumber = () => number++;
  Action<int> setNumber = (i) => number = i;
  return new { showNumber, increaseNumber, setNumber };
}

dynamic a = Closure();

This is almost the same example as before, but in C#. If we were to call a.showNumber() it would show a message box with the value 10 in it. And it would increase number by 1 every time we call a.increaseNumber(). It also creates a new closure every time we call Closure().

In C# this same functionality would probably be easier to understand if turned into a class instead, but having a deeper understanding about how closures work is almost a requirement if you’re going to do any kind of serious JavaScript development. At least that is my opinion.

by Mikael Lofjärd

Handling Views in node.js

This weekend, my wife and daughter have been away up north, visiting my in-laws. I thought this would be a great opportunity for me to buffer up on some blog posts, but it seems like my inspiration mostly left with them.

Last Tuesday at my weekly tutorial at work we did a bit of work with jQuery and Mustache. On my blog I use Mustache, not only on the client side, but on the server side as well. As I enjoy using the MVC pattern, I have tried to implement it to the best of my extent.

First things first

Mustache is a light weight templating engine with emphasis on simplicity. It’s been implemented for a lot of languages and one of them is JavaScript.

In Mustache, a template looks like this:

Hello, my name is {{name}}!

In my case the templates involve a lot of HTML, but nevertheless it’s simply a string with {{ and }} used for marking up where the values should be inserted.

The JavaScript Mustache library has only one single method exposed; to_html.

to_html can take 2-4 arguments where the first is the template string and the second is the object with the values in it. In the JavaScript case that is a JSON object which suits me just fine since that what I use everywhere else in the blog. The other two arguments are used for partials and streaming the rendered template.

The ViewManager

This is what my ViewManager looks like:

/*****************************************
 *   View Manager
 *****************************************
 *   Author:  mikael.lofjard@gmail.com
 *   Website: http://lofjard.se
 *   License: MIT License
 ****************************************/

var ViewManager = (function () {

  var fs = require('fs');
  var path = require('path');
  var mu = require('mustache');

  var env = require('./environmentManager').EnvironmentManager;

  var templatesCached = false;
  var templates = {};
  var partials = {};

  return {

    init : function (templatePath) {

      if (!templatesCached) {
        console.log('ViewManager: Populating template cache');
        templates = {};
        var allTemplateFiles = fs.readdirSync(templatePath);

        for (var file in allTemplateFiles) {
          console.log(' - Adding ' + allTemplateFiles[file] + ' to template store');
          var filePath = path.resolve(templatePath, allTemplateFiles[file]);
          templates[allTemplateFiles[file]] = fs.readFileSync(filePath, 'utf-8');
        }
        partials.header = templates['header.partial.mu'];
        partials.footer = templates['footer.partial.mu'];

        templatesCached = true;
      }
    },

    renderView : function (response, viewName, model) {
      if (typeof(model.header) == 'undefined') {
        model.header = {};
      }
      model.header.trackingCode = env.trackingCode();
      model.footer = {};

      env.info('ViewManager: Rendering view ' + viewName);
      response.writeHead(200, { "Content-Type" : "text/html" });
      var html = mu.to_html(templates[viewName + '.mu'], model, partials, function (line) {
        response.write(line);
      });
      response.end();
      return;
    }
  };
    
}());

typeof(exports) != 'undefined' ? exports.ViewManager = ViewManager : null;

Upon initialization, I read all my template files from disk into memory. I also assign my partial templates to a partials object to pass on to Mustache. My partials are mainly what comes before and after themain content of each page on the blog. The other templates just contain the main content for each page.

This is the template for when you click on one of the tags in the tag cloud:

{{>header}}
  <section class="comments">
    <header>
      Posts tagged with {{tag}}
    </header>
    <div class="taggedposts">
    {{#posts}}
      <div class="taggedpost">
        <header><a href="/post/{{readableKey}}">{{title}}</a></header>
        {{outtake}}
        <footer>written on {{readableDateTime}} by {{author}}</footer>
      </div>
    {{/posts}}
    </div>
  </section>
{{>footer}}

The {{>header}} and {{>footer}} tags are what renders the partials. Each partial uses a property on the model as its context so my renderView method assigns properties calles header and footer to my model.

The {{#posts}} and {{/posts}} tags are iterator tags. The template code between them gets run for every object in the posts array in my model.

How to use it

Well how to use it is really up to you, but here’s how I do it from my controllers:

tag : function (request, response) {
  var tag = request.params.tag;

  db.view('posts/byTagAndDateTime', {
    startkey : [tag, 1],
    endkey : [tag],
    descending : true
  }, function (err, doc) {
    if (err) {
      env.info("CouchDB: DB Read error");
      staticFileController.error(request, response, 404);
      return;
    }

    var model = {};
    model.posts = new Array();

    for (var i in doc) {
      var post = doc[i].value;
      post.readableDateTime = misc.prettyDate(doc[i].key[2]);

      model.posts.push(post);
    }

    model.tag = tag;
    viewManager.renderView(response, 'tag', model);
    return;
  });
}

Line 26 is where the action is.

If you want to read more about Mustache, the check out its GitHub page and that of its JavaScript implementation.

by Mikael Lofjärd

Automatic Minification and Bundling with node.js

Scott Guthrie recently wrote about the new minification and bundling process that has been built for ASP.Net 4.5.

I read his blog post, liked what I read and then I though of doing the same thing for my blog. I’ve been looking at minification programs for a while but I’ve put it off so far because I didn’t want to add another step to my manual deployment process. Now I’m thinking I don’t have to have another step. I could do it “automagically”.

The BundleController

/*****************************************
 *   Bundle Controller
 *****************************************
 *   Author:  mikael.lofjard@gmail.com
 *   Website: http://lofjard.se
 *   License: MIT License
 ****************************************/

var BundleController = (function () {
    
  var url = require('url');
  var fs = require('fs');
  var path = require('path');

  var cssmin = require('cssmin');
  var jsmin = require('uglify-js');

  var env = require('../environmentManager').EnvironmentManager;
  var dm = require('../domainManager').DomainManager;

  var config = null;
  var staticFileController = null;
    
  function sortCss(a, b) {
    if (a === 'normalize.css')
      return -1;
    if (b === 'normalize.css')
      return 1;
    if (a === 'shCore.css')
      return -1;
    if (b === 'shCore.css')
      return 1;
    return (a &lt; b) ? -1 : ((a &gt; b) ? 1 : 0);
  }

  function sortScripts(a, b) {
    if (a === 'lofjard.js')
      return -1;
    if (b === 'lofjard.js')
      return 1;
    return (a &lt; b) ? -1 : ((a &gt; b) ? 1 : 0);
  }

  function createCssBundle() {
    var wwwRoots = dm.getAllWwwRoots();

    for (var i in wwwRoots) {
      var cssPath = path.join(wwwRoots[i], config.css.path);
      var bundleFilePath = path.join(cssPath, '_bundled.css');
      console.log('BundleController: CSS bundle path is ' + bundleFilePath);
      try {
        fs.unlinkSync(bundleFilePath);
      } catch (ex) {}

      var files = fs.readdirSync(cssPath);
      files.sort(sortCss);
      var bundleData = '';

      for (var filename in files) {
        console.log(' - Bundling CSS ' + path.join(cssPath, files[filename]));
        var file = fs.readFileSync(path.join(cssPath, files[filename]), 'utf-8');
        bundleData += (file + '\n');
      }

      if (config.css.minimize) {
        bundleData = cssmin.cssmin(bundleData);
      }

      fs.writeFileSync(bundleFilePath, bundleData, 'utf-8');
    }
  }

  function createScriptsBundle() {
    var wwwRoots = dm.getAllWwwRoots();
    for (var i in wwwRoots) {
      var jsPath = path.join(wwwRoots[i], config.scripts.path);
      var bundleFilePath = path.join(jsPath, '_bundled.js');
      console.log('BundleController: JavaScript bundle path is ' + bundleFilePath);

      try {
        fs.unlinkSync(bundleFilePath);
      } catch (ex) {}

      var files = fs.readdirSync(jsPath);
      files.sort(sortScripts);
      var bundleData = '';

      for (var filename in files) {
        console.log(' - Bundling JavaScript ' + path.join(jsPath, files[filename]));
        var file = fs.readFileSync(path.join(jsPath, files[filename]), 'utf-8');
        bundleData += (file + '\n');
      }

      if (config.scripts.minimize) {
        var ast = jsmin.parser.parse(bundleData);
        ast = jsmin.uglify.ast_mangle(ast);
        ast = jsmin.uglify.ast_squeeze(ast);
        bundleData = jsmin.uglify.gen_code(ast);
      }

      fs.writeFileSync(bundleFilePath, bundleData, 'utf-8');
    }
  }

  return {
    init : function (configInit, staticFileControllerInit) {
      config = configInit;
      staticFileController = staticFileControllerInit;
      createCssBundle();
      createScriptsBundle();
    },

    bundleScripts : function (request, response) {
      request.url = path.join(config.scripts.path, '_bundled.js');
      env.info('BundleController: Rewriting request as ' + request.url);
      staticFileController.file(request, response);
      return;
    },

    bundleCss : function (request, response) {
      request.url = path.join(config.css.path, '_bundled.css');
      env.info('BundleController: Rewriting request as ' + request.url);
      staticFileController.file(request, response);
      return;
    }
  };
    
}());

typeof(exports) != 'undefined' ? exports.BundleController = BundleController : null;

Nothing wierd here. It just bundles my scripts in alphabetical order, except for a few scripts and css files that are prioritized. Normalize.css gets top place in the bundling process and so would jQuery if I would host it myself.

I use node-cssmin for CSS minification and UglifyJS for JavaScript minification. None of this is in the production code yet since it was completed about 15 minutes ago and I need to do more testingon the JavaScript side, but on the development server the CSS bundling and minification works like a charm and has cut my CSS size by one third, but most importantly it has replaced 4 http requests with just one and cut the time for fetching css by 3/4.

The BundleController gets its configuration from index.js and it looks like this:

var bundleConfig = {
  scripts: {
    path: '/scripts',
    minimize: true,
    compress: true
  },
  css: {
    path: '/css',
    minimize: true,
    compress: true
  }
}

For now I don’t act on the compress property, but when I find a good way to send gzip files if the client supports it through node-static then at least I already have it configured.

I also added two new routes to my configuration:

routes['blog:/scripts'] = masterController.bundleScripts;
routes['blog:/css'] = masterController.bundleCss;

That’s really all there is to it. If I request lofjard.se/css/normalize.css I get the regular, untouched CSS file, but if I go to lofjard.se/css I get the minified version of all CSS files in the /css directory.

by Mikael Lofjärd

Architecture in JavaScript - Inheritance

There’s been a lot of debate over the years about whether JavaScript is an object-oriented language or not. Most of these discussions seem to pan out into arguments over inheritance.

JavaScript, by design, lends itself well to inheritance through extension. However, JavaScript can support lots of different types of inheritance. I’m going to talk about a few of them today.

Consider the following code:

function Car() {
  this.color = "Blue";
  this.brand = "unknown";  
}

function Ford() {
  var o = new Car();
  for(var i in o) {
    this[i] = o[i];
  }
  this.brand = "Ford";
}

var myCar = new Car();
var myFord = new Ford();

The myCar object would have the properties color and brand. The Ford() constructor method creates inheritance by creating a Car and copying all its properties. It then sets its brand property to a new value.

Ford now inherits from Car. But what if we want it to be able to inherit things in a more flexible way?

function Car() {
  this.color = "Blue";
  this.brand = "unknown";  
}

function Train() {
  this.color = "Red";
  this.brand = "unknown";  
}

function Ford(F) {
  var o = new F();
  for(var i in o) {
    document.write('  - i: ' + i + ' -   ');
    this[i] = o[i];
  }
  this.brand = "Ford";
}

var myCar = new Car();
var myFord = new Ford(Car);
var myOtherFord = new Ford(Train);

Now we would have a blue Ford car and a red Ford train. This could be done in another way:

function Car() {
  this.color = "Blue";
  this.brand = "unknown";  
}

function Train() {
  this.color = "Red";
  this.brand = "unknown";  
}

function Ford(o) {
  function F () {}
  F.prototype = o;
  var a = new F();
  a.brand ="Ford";
  return a;
}

var myCar = new Car();
var myTrain = new Train();
var myFord = new Ford(myCar);
var myOtherFord = new Ford(myTrain);

Oh My God! Now we’re inheriting from objects instead! And using prototype! Why don’t we go a step further?

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

function Car() {
  this.color = "Blue";
  this.brand = "unknown";  
}

function Train(o) {
  var a = new object(o);
  a.color = "Red";
  a.brand = "Märklin";
  return a;
}

function Ford(o) {
  var a = new object(o);
  a.brand ="Ford";
  return a;
}

var myCar = new Car();
var myFord = new Ford(myCar);
var myTrain = new Train(myFord);

Now we have objects inheriting objects inheriting objects. How object-oriented isn’t that?

Of course, for these extremely simplified cases, why would I need inheritance anyway? In fact, I can’t really figure out what I would need inheritance for anyway in JavaScript. Prototype extensions seem much more flexible to me. But if, in the future, I ever find a use for it, I’ll make sure to write about it here.

Also, make sure you read Mr. Crockford’s old (2001) post on Classical Inheritance in JavaScript. There are quite a few really funny ways to do this in there although I would not use them myself.

So to sum it up; if you think you need inheritance then please look closer at prototype extensions as an alternative. If you really need inheritance then know that it can be achieved.

by Mikael Lofjärd

The Logarithmic Tag Cloud

A few days ago I sat down and tagged all my posts. Last night I decided to write a tag cloud.

The first try

I started out with a simple linear scale:

var countDiff = maxCount - minCount;
var sizeDiff = maxSize - minSize;
if (countDiff == 0) countDiff = 1; // no divide by zero

for (var i in doc) {
  var weight = (doc[i].value - minCount) / countDiff;
  var size = minSize + Math.round(sizeDiff * weight);
  model.tags.push( { tag: doc[i].key, size: size , count: doc[i].value } );
}
  • maxCount - The highest occurance of any tag.
  • minCount - The lowest occurance of any tag.
  • maxSize - The biggest allowed font size.
  • minSize - The smallest allowed font size.
  • doc[i].key - The name of the current tag.
  • doc[i].value - The occurance of the current tag.

It rendered, but something looked odd. The linear scale isn’t really that pretty in a tag cloud. Especially not when a few tags (in my case #blog and #nodejs) has a substantially bigger weight than the rest. I wanted things to be readable with a minimum font size and a maximum font size set by me so that it couldn’t break the page layout.

I fiddled around for a while with a few other (not so successful) algorithms and then I almost gave up.

Logarithms to the rescue

I finally thought of the logarithmic scale and after a couple of attempts it looked like my idea of a nice tag cloud.

var countDiff = Math.log(maxCount) - Math.log(minCount);
var sizeDiff = maxSize - minSize;
if (countDiff == 0) countDiff = 1; // no divide by zero

for (var i in doc) {
  var weight = (Math.log(doc[i].value) - Math.log(minCount)) / countDiff;
  var size = minSize + Math.round(sizeDiff * weight);
  model.tags.push( { tag: doc[i].key, size: size , count: doc[i].value } );
}

If you haven’t noticed it in the top menu yet you can check it out here.

by Mikael Lofjärd

A Simple Routing Solution with Node.js

A few days ago I wrote about not reinventing the wheel. Today I’m going to talk about the opposite.

If you’re building an ‘enterprise’ grade application, reinventing the wheel is almost always the wrong thing to do. This blog however is something I do just for fun, and reinventing the wheel can sometimes be the best way to learn how stuff works. It’s one of the reasons Ayende had for writing yet another document database, and it’s the reason why I decided to write my own routing engine.

Sure enough I could have used the very popular Express framework, but where’s the fun in that?

What I wanted

As you might know, I work almost exclusively with the .Net stack at my job and I really like how routing is handled in ASP.Net MVC.

routes.MapRoute(
  "Default",	// Route name
  "{controller}/{action}/{id}",	// URL with parameters
  new { controller = "Home", action = "Index", id = "" }	// Parameter defaults
);

I wanted something similar in my blog; easy to read, easy to configure and abstracted away from all that goes on when the http request happens.

What I ended up with

This is my routing configuration (from index.js):

var routes = {};
// blog routes
routes['blog:/'] = masterController.page;
routes['blog:/post/{id}'] = masterController.getPost;
routes['blog:/comment'] = masterController.comment;
routes['blog:/page'] = masterController.page;
routes['blog:/page/{key}'] = masterController.page;
routes['blog:/archive'] = masterController.archive;
routes['blog:/admin'] = masterController.admin;
routes['blog:/admin/get/{id}'] = masterController.getPostAsJSON;
routes['blog:/admin/submit'] = masterController.submitPost;

// default static file route
routes['file'] = masterController.file;

I don’t have any complicated routes but never the less I wanted to have nice URLs. It also has support for virtual hosts which means I can have equal routes do different things depending on what sub domain I’m on.

If your’e wondering what the masterController is, it’s just a wrapper controller thats responsible for initializing all my other controllers so I can keep index.js a little less cluttered.

My virtual host configuration (from index.js):

var virtualDomains = {};
virtualDomains['lofjard.se'] =               { routeId: 'blog', wwwRoot: './content/lofjard' };
virtualDomains['www.lofjard.se'] =           { routeId: 'blog', wwwRoot: './content/lofjard' };
virtualDomains['xn--lofjrd-eua.se'] =        { routeId: 'blog', wwwRoot: './content/lofjard' };
virtualDomains['www.xn--lofjrd-eua.se'] =    { routeId: 'blog', wwwRoot: './content/lofjard' };
virtualDomains['foto.lofjard.se'] =          { routeId: 'foto', wwwRoot: './content/foto' };
virtualDomains['foto.xn--lofjrd-eua.se'] =   { routeId: 'foto', wwwRoot: './content/foto' };

I needed this since I have a photo site on a different sub domain that gets handled by the same node server.

And this is the router code:

/*****************************************
 *   Router
 *****************************************
 *   Author:  mikael.lofjard@gmail.com
 *   Website: http://lofjard.se
 *   License: MIT License
 ****************************************/

var Router = (function() {
  var url = require('url');
  var path = require('path');
  var querystring = require('querystring');

  var env = require('./environmentManager').EnvironmentManager;

  var resolveExcludes = ['.html', '.js', '.css', '.png', '.jpg', '.gif', '.ico', '.txt'];
  var virtualDomains = {};
  var routeTable = {};

  function buildRouteTable(routes) {
    for (var route in routes) {
      console.log('Server: Building route table entry for: ' + route);
      var routeSplit = route.split(':');
      var routeId = routeSplit[0]
      var routeName = routeSplit[1];

      if (routeName == null) routeName = route;

      var handle = routes[route];
      var pathName = routeName.split('/{')[0];
      var regexRoute = new RegExp(routeName.replace(/{\w+}/g, '{(\\w+)}') + '&#36;', '');
      var regexPath = new RegExp(routeName.replace(/{\w+}/g, '([^\/]+)') + '&#36;', '');
      routeTable[route] = {
        routeId : routeId,
        handle : handle,
        pathName : pathName,
        regexRoute : regexRoute,
        regexPath : regexPath
      }
    }
    return;
  }

  return {

    init: function(virtualDomainsInit, routes) {
      virtualDomains = virtualDomainsInit;
      buildRouteTable(routes);
    },

    route: function(request, response) {
      var pathName = url.parse(request.url).pathname;
      var hostName = request.headers['host'].split(':')[0];

      // if request is for unknown sub domain, let the file handler handle it
      if (typeof(virtualDomains[hostName]) === 'undefined') {
        routeTable['file'].handle(request, response);
        return;
      }

      if (resolveExcludes.indexOf(path.extname(pathName)) === -1) {
        env.info('Router: About to route a request for ' + pathName);

        for(var route in routeTable) {
          if (virtualDomains[hostName].routeId === routeTable[route].routeId &&
              routeTable[route].regexPath.test(pathName)) {
            var attributes = routeTable[route].regexRoute.exec(route);
            var values = routeTable[route].regexPath.exec(pathName);

            var qs = {};

            if (attributes.length > 1) {
              for (var i = 1; i < attributes.length; i++){
                qs[attributes[i]] = values[i];
              }

              request.url = routeTable[route].pathName + '?' + querystring.stringify(qs);

              env.info("Router: Rewrote request url as " + request.url);
            }

            routeTable[route].handle(request, response);
            return;
          }
        }
      }

      env.info('Router: Static file request for ' + pathName);
      
      // default fallback on static file handler if no route matched the request
      routeTable['file'].handle(request, response);
    }
  };
	
}());

typeof(exports) != 'undefined' ? exports.Router = Router : null;

Upon initialization it traverses all routes in the configuration and creates two regular expressions for each route. One RegEx is used for getting the attribute names and the other is used for fetching the attribute values.

When the request comes in I get the host name for the request and check if it exists in my virtual domain list. If it doesn’t I just hand things over to the static file handler which will serve up a 404.

I then check if the URL that was requested has a file ending that I know is a static file. If so I skip the routing code and my fallback static file handler takes care of the request.

If it’s not a known static file extension, then the fun begins. I traverse all the routes checking if it matches the RegEx for getting attributes and if the route id matches the one set up for the current virtual domain.
If it matches I extract the attributes and values, if any, and attach them to the request object as a querystring. I might rewrite this part in the future so that I just extend them as properties to the request object instead of using the querystring.

Then I execute the assigned function for that route. Done.

by Mikael Lofjärd

Node.js Development Server Strategy

When I started building this blog my server was the production environment and my laptop was the development environment. This all changed when I added the database and started doing more UNIX specific stuff such as path resolving and such. So from then until yesterday my production environment was also my development environment. Not the best strategy I admit.

Yesterday when I rewrote the architecture I also decided that I needed to set up a separate node.js instance as a development environment on the server.

The first problem I had to solve was configuration. My configuration was scattered all over the code base so I moved it all into index.js which is the file I execute with node when I start the server.

I also did not want to have to change my configuration before I deploy (copy) from development to production, thus my code somehow needed to be aware of whether it was production code or development code.

Moving files around

Node.js has a global process object that holds information about the running node.js process. In the API for process is a method called cwd() that stands for Current Working Directory. It’s default value is the folder from where you called node.js when you started it.

Based on this I made my file structure as such:

  • /dev
  • /dev/content
  • /dev/controllers
  • /dev/views
  • /stable
  • /stable/content
  • /stable/controllers
  • /stable/views

There are a few other folders but these are the important ones.

The /dev and /stable folders are where my main code resides and where I execute node.js from. In the underlying /content folders, all of my CSS, images and client JavaScript resides.

In the last few years I’ve been doing a lot of ASP.Net MVC at work, and the MVC pattern was something that I felt really comfortable with, so I also created /controllers and /views folders. As all my data gets passed around as JSON, and JavaScript doesn’t have any classes, there are no Models to speak of so they didn’t get folders.

All in all, /stable is a mirror of /dev and I just copy all files from /dev to /stable when I feel that the code is stable.

Enter the EnvironmentManager

To make use of my new folder structure and process.cwd() I built the EnvironmentManager. Its sole purpose is to deal with environmental factors that differ from development and production.

It looks like this:

/*****************************************
 *   Environment Manager
 *****************************************
 *   Author:  mikael.lofjard@gmail.com
 *   Website: http://lofjard.se
 *   License: MIT License
 ****************************************/

var EnvironmentManager = (function() {

  var fs = require('fs');

  var misc = require('./misc').Misc;

  var currentEnvironment = null; // development or production
  var trackingCodeScript = null;

  return {

    init: function(trackingCodePath) {
      var cwdSplit = process.cwd().split('/');
      var cwdBase = cwdSplit[cwdSplit.length - 1];
      console.log('EnvironmentManager: Base dir is ' + cwdBase);

      if (cwdBase === 'dev') {
        currentEnvironment = 'development';
      } else {
        currentEnvironment = 'production';
        trackingCodeScript = fs.readFileSync(trackingCodePath);

        process.on('uncaughtException', function(err) {
          var log = fs.createWriteStream('exceptions.log', {'flags': 'a'});
          log.write(misc.getDateTimeNow() + ' - ' + err + '\n');
        });
      }
    },
		
    info: function(logMessage) {
      if (currentEnvironment === 'development') {
        console.log(logMessage);
      }

      return;
    },
		
    trackingCode: function() {
      if (currentEnvironment === 'production') {
        return trackingCodeScript;
      }
			
      return '';
    },
		
    httpPort: function() {
      return (currentEnvironment === 'development') ? 8080 : 80
    },
		
    httpsPort: function() {
      return (currentEnvironment === 'development') ? 8081 : 443
    }
  };

})();

typeof(exports) != 'undefined' ? exports.EnvironmentManager = EnvironmentManager : null;

It is initialized from index.js and checks if the current working directory is /dev. If it is, then we’re in the development environment, if not, we’re in production.

Here’s what it’s used for:

  • Upon initialization (in production) it adds a listener to the uncaughtException event on process so that instead of crashing (and getting restarted by supervisor) it logs the exception to disk.
  • It has a wrapper function around console.log(...) so that no logging to console is done in production.
  • If we are in production it can give me my Google Analytics tracking code that I give to the ViewManager to insert into views. That way I don’t polute my visitor statistics as I’m the only one using the development server.
  • It also gives me the port numbers to start the servers on depending on which environment we’re in.

The EnvironmentManager has been a nice addition to my code base as now I can deploy my development code to production without altering a single line of code. Hopefully this will lead to less downtime.

by Mikael Lofjärd

Sorry, sharing is not available as a feature in your browser.

You can share the link to the page if you want!

URL