NodeJS: Experiments with Middle End Part 3

Note: This is the last in a series of posts describing my experiments with constructing a Middle End. In Part 1, we discussed the concept of the middle end and its advantages. In Part 2, we constructed a very simple example.

In this post, we’re going to make that example slightly more complex by introducing dependencies within the modules. Now the code must be able to handle these dependencies for both the client side and the server side.

In the last post, we built a simple module consisting of a single function that returned a greeting:

var Greetings = function() { }
Greetings.prototype.hello = function(who) {
   return "Hello "+who;
}
module.exports = Greetings;

At this point, it would be very useful to sanitize and validate the parameter passed to the “hello” function. We could obviously build this functionality directly into the code, but this is exactly the sort of thing that should be abstracted into its own module(s).

For the purpose of this example, we’ll simply include the functionality to give the parameter passed a “trim”; after some hacking and snippet-borrowing from node-validator by Chris O’Hara, we can build another simple module called Tidy:

var Tidy = {
   whitespace: '\r\n\t\s',
 
   trim: function(str) {
      var whitespace =  '\r\n\t\s';
      str = str.replace(new RegExp('^['+this.whitespace+']+|['+this.whitespace+']+$', 'g'), '')
      return str;
   }
}
module.exports = Tidy;

We can now improve our Greetings module, including the dependency and functionality:

var Tidy = require('./tidy');
 
var Greetings = function() { }
Greetings.prototype.hello = function(who) {
   who = Tidy.trim(who);
   return this.hello(who);
}
module.exports = Greetings;

To see if this will work as expected, let’s add some spaces to the parameter passed in the NodeJS script:

var Greetings = require('./greetings');
var greetings = new Greetings();
console.log(greetings.hello('  Node   ')+"!");

When we run it, this is what we see:

$ node runner.js
Hello Node!

Good, so this works on the server side, but let’s test its behaviour on the client side. Again, we should add some spaces to the parameter passed to ensure that it is working:

<script type="text/javascript"> </script>
<script src="greetings.js" type="text/javascript"> </script>
<script type="text/javascript"> </script>

Unfortunately, we now see the following error:

require is not defined
[Break On This Error] var greetings = new Greetings();

Our attempt to “require” the dependency in the Greetings module has broken the client side. To fix this, we need to define our own require() function, much like we had to for the module object. We do this by creating a new front end-only script, which we’ll call “middle-end.js”.

var require = function(module) {
   document.write('<script src="'+module+'.js" type="text/javascript"> </script>');
}
 
var module = {
   exports: undefined
};

(Obviously we should include much more error checking, but this will be enough for our example).

We modify our html as follows:

<script src="middle-end.js" type="text/javascript"> </script>
<script type="text/javascript"> </script>
....

Now when we reload the page in the browser, all should work as expected. Huzzah!

This is just a very simple example of what can be done when JavaScript code is shared between the client and server sides—the “Middle End”. This concept becomes really exciting when you start thinking about potential approaches to form validation, session management, and even display logic. This is definitely something worth playing around with.

All of the code is available as a Gist.