Tag Archives: iisnode

First few tweaks to default Express app

Every time I create a new Express app, I make sure a few changes to fit my need. In this post, I will focus on starting from scratch on fundamentals towards publishing to Azure.

First of all I create a Node.js app, and install Express.

npm init
npm i --save express
express app-name

To run, simply execute:

npm start

My viewpoint on view engines

I don’t like Jade view engine or any other view engines for that matter in Node.js apps, because to me it’s a overkill, plus there’s not a great deal of tooling support in many cases. I use Visual Studio Code which I think the best slickified code editor I have ever used as I previously have used Brackets and Sublime. Visual Studio Code has the support for super cool Emmet snippets, which allows you to generate tons of HTML code by using simple CSS expressions, although I don’t spend whole day writing a lot of HTML. Here’s an example:

html>head>title{formdata : collect data on all devices}^>body>div.container>div.header

The above CSS expression will generate the following HTML:

<html>
<head>
	<title>formdata : collect data on all devices</title>
</head>
<body>
	<div class="container">
		<div class="header"></div>
	</div>
</body>
</html>

This is not the best example to showcase the true power of Emmet snippets, but you get the idea.

VS Code

Getting rid of the default Jade view engine

I have removed all views/*.jade files and created an index.html instead, and then executed the following to install the ejs view engine instead:

npm i --save ejs

And now I’ve replaced the following line in the index.js / app.js:

app.set('view engine', 'jade');

With the following:

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

Moving routing to another file

The main (index.js/app.js/whatever) js file becomes crowdy very quickly. Therefore, it’s always a best practice to move out the routing code to some other file. I have created framework/routes.js file and moved all the routing code including error handlers like below:

module.exports = function(app)
{
  app.get('/', function(req, res, next) {
    res.render('index', { title: 'Hello World.' });
  });  

  // catch 404 and forward to error handler
  app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    res.render('error', {
      message: err.message,
      error: err
    });
    next(err);
  });

  // error handlers
  // development error handler
  // will print stacktrace
  if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
      res.status(err.status || 500);
      res.render('error', {
        message: err.message,
        error: err
      });
    });
  }

  // production error handler
  // no stacktraces leaked to user
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: {}
    });
  });
};

Now that the routing code is moved, we need to tell the app where to look up once an URL request comes up to the server. That’s a single line hooking:

require('./framework/routes')(app);

Making Bower to work inside public folder

By default, when Bower is installed, bower_components folder will be created at the same level as node_modules which makes it useless for the views, because for the views to use bower_components, it needs to live inside public/views folder. Obviously, bower_components are static resources, therefore, it’s only right to keep it inside public folder because they need no server-side processing. Assuming that Bower was installed and initialized like below:

npm i --save bower
bower init

Now that we have a bower.json file created which is essentially the configuration file for the bower, ignore this. Lets create another file called .bowerrc where we can tell Bower to point to the right folder where we want it to install the components with the following contents, in this case:

{
      "directory": "public/bower_components"
}

Now go ahead and install bootstrap:

bower install bootstrap

You will notice that the bootstrap component was installed inside public folder, now you can go ahead and refer to these resources from your views.

Making it run on Azure

It’s often a painful experience partially due to lack of documentation on how to make Node.js apps run on Azure. You have written a perfectly alright Node.js app and your expectation is that it would run as-is after deploying to Azure, but it wouldn’t. Often times, you will end up with this annoying and at the same time frustrating message: “The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.” or some other HTTP 500 error message. However, there’s a blessing in it. Because it has failed and I will be covering the solution in a bit, it opens up a door to configure Node.js apps in even more ways. Lets take a look.

IIS hosted on Azure has this IIS module installed called iisnode, which facilitates the Node.js runtime. Azure also offers ASP.NET style web.config file to configure a Node.js app. I have created such web.config file and pointed that our entry point for the app should be a server.js file. The following is the web.config which essentially tells IIS to let server.js handle all the dynamic requests and handle the static resources as they are. This contains ton of configurations as comments which you can enable/disable as you see fit for your need:

<!--
     This configuration file is required if iisnode is used to run node processes behind
     IIS or IIS Express.  For more information, visit:

     https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->

<configuration>
     <system.webServer>
          <handlers>
               <!-- indicates that the app.js file is a node.js application to be handled by the iisnode module -->
               <add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
          </handlers>
          <rewrite>
               <rules>

                    <!-- Don't interfere with requests for node-inspector debugging -->
                    <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
                        <match url="^server.js\/debug[\/]?" />
                    </rule>

                    <!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
                    <rule name="StaticContent">
                         <action type="Rewrite" url="public{REQUEST_URI}"/>
                    </rule>

                    <!-- All other URLs are mapped to the Node.js application entry point -->
                    <rule name="DynamicContent">
                         <conditions>
                              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
                         </conditions>
                         <action type="Rewrite" url="server.js"/>
                    </rule>

               </rules>
          </rewrite>
          <!-- You can control how Node is hosted within IIS using the following options -->
        <!--<iisnode
          node_env="%node_env%"
          nodeProcessCommandLine="&quot;%programfiles%\nodejs\node.exe&quot;"
          nodeProcessCountPerApplication="1"
          maxConcurrentRequestsPerProcess="1024"
          maxNamedPipeConnectionRetry="3"
          namedPipeConnectionRetryDelay="2000"
          maxNamedPipeConnectionPoolSize="512"
          maxNamedPipePooledConnectionAge="30000"
          asyncCompletionThreadCount="0"
          initialRequestBufferSize="4096"
          maxRequestBufferSize="65536"
          watchedFiles="*.js"
          uncFileChangesPollingInterval="5000"
          gracefulShutdownTimeout="60000"
          loggingEnabled="true"
          logDirectoryNameSuffix="logs"
          debuggingEnabled="true"
          debuggerPortRange="5058-6058"
          debuggerPathSegment="debug"
          maxLogFileSizeInKB="128"
          appendToExistingLog="false"
          logFileFlushInterval="5000"
          devErrorsEnabled="true"
          flushResponse="false"
          enableXFF="false"
          promoteServerVars=""
         />-->
        <iisnode watchedFiles="*.js;node_modules\*;routes\*.js;views\*.jade"/>
     </system.webServer>
</configuration>

The contents of server.js is extremely simple:

require('./bin/www');

It simply redirects the request to Express. Do you recall when Express was installed it also created a bin/www file where it does the server-side infrastructure handling?

Advertisements