Application with Express, Node, Jade and Stylus

3)  Web Application Using Web Press Layers





1) Application with Express, Node, Jade and Stylus

Introduction

Jade is a template based UI building framework for Node. The true power of Jade is felt using the object concept of UI development and especially while creating dynamic views from complex data. Some of the key advantages of jade are:
a) Template based re-usable components.
b) Object oriented layout creations
c) Dynamic creation of templates with help with for loop construct and conditional IF patterns.

Express is a very powerful web application framework for node which helps in multiple facets such as quick project creation, installation of projects, settings up logs on different environments, setting the view for rendering, setting public folder for static HTML’s and lot more.

Stylus uses an object oriented approach to building CSS. Basically stylus is a CSS pre-processor.

Setting up the express project
1)Let us get acquainted to using some of the best practises from here on. Under you    project workspace in the CMD, hit
      a.  “npm install express -g”
      b. This will install express globally

2)Under your workspace hit “express demo4”
      a.Express would create the project with the standard directory structure for you.
      b.On the command prompt “cd demo4”

3) Observe that we have a package.json file created. This file enables us to set up and deploy a node application on a fresh environment.

4)You can add the node modules used in your application here with the versions that is required to be installed by npm. For now you can simply continue without adding any extra module and hit “npm install”

5)This will install the jade.

6)To install stylus – “npm install stylus”

7)At this point we have the dependent modules downloaded and a few installed globally and rest confined locally to the project.

8)Edit the app.js to point to a favourite port of your choice. Hit “node app.js”
9)Open the browser , hit the url as localhost:3000 and you should see the application running alright showing an Express text on the browser.

Configuring the app.js

1)Opening the app.js , you will observe the following code meant for importing the required modules.
 var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

 var app = express();


2)The next method in app.js is the app.configure

 app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
 });

 app.configure('development', function(){
  app.use(express.errorHandler());
});



This block
  a) configures the port
  b) sets the view folder to use that will hold the jade files
  c) defines jade as the view engine (alternatives are EJS to JADE)
  d) Defines the fav icons
  e) Defines the logger to use based on the environment
  f)  Defines the bodyparser. If your application is going to use its own parser you need to be careful to disable this and add it only on the request that need this parser. In use cases where you need to perform a file upload using multi part we will use our own parser and hence body parser should not be made available global. Examples of this usage will follow in next few weeks.
  g) We also define the directory to the public which holds any static html’s, javascript , CSS, assets and fonts.
  h) We define the mapping of the request URL and the route handler
  i) Server creation is done using the HTTP module.

Defining the view to render in the router

Under the index.js you will see the following code:
 exports.index = function(req, res){
   res.render('index', { title: 'Express' });
 };

We are making this function available outside this file to be able to call from app.js by specifying “exports”. We are rendering the “index.jade” upon receiving the URL “/” defined in the app.js. The title being passed is Express which is configurable on re-usable templates to provide the dynamic values.

Peek at the view index.jade

Index.jade has the following code within it:

  extends layout

  block content
  h1= title
  p Welcome to #{title}


Like I said earlier Jade supports OOP based templating. It extends from a parent template layout.jade and inherits the entire layout from it. Since the syntax is coupled tightly to white spaces, we need to use tab efficiently to ensure appropriate open and closure of blocks.

Creating our first landing page

1)Modify the app.js as follows:

/**
 * Module dependencies.
 */

 var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path')
  , nib = require('nib')
  ,stylus = require('stylus');

 var app = express();

 function compile(str, path) {
  return stylus(str)
    .set('filename', path)
    .use(nib())
 }

 app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
  app.use(stylus.middleware({ src: __dirname + '/public', compile: compile}));
 });

 app.configure('development', function(){
  app.use(express.errorHandler());
 });

 app.get('/', routes.index);
 app.get('/users', user.list);
 app.get('/landing', routes.landing);

  http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
 });
a)Basically we have added the stylus, nibs modules. In the configure enabled the dynamic compilation of the styl files to css.
b)Created a route landing and mapped it to landing routing handler.

2)Modify the routing file index.js as follows:

 /*
 * GET home page.
 */

 exports.index = function(req, res){
  res.render('index', { title: 'Express' });
 };

 exports.landing = function(req, res){
  res.render('landing', { title: 'Landing Page' });
 };
We have added the route handler for the incoming landing request.

3)Creating the Jade files:

Modify the layout file as follows:
 doctype 5
 html
 head
      title= title
      link(rel='stylesheet', href='/stylesheets/style.css')
 body
      block content
            header
                   h1 My First Jade-Node-Express App
                   .landing-content
 Footer
      p Powered by node, jade and stylus

Create a new file landing.jade as follows:
 extends layout
 block-content
 p
      |This web site is built using Express, Node and Jade.

4) Creating the style.styl file

Create this file as follows that will be pre-processed:
 .main-content
  float left
  width 400px

 header
  padding 80px 10px
  color #efefef
  font-size 28px
  text-align center

 footer
  width 500px
  margin 50px auto
  border-top 1px dotted #eeee
  padding-top 5px
  font-size 14px

5)Run the node app.js

You should see the following output:



In case you had difficulty in getting the output, you can download the entire application from here.


2) File Upload Using Node.js and HTML 5 UI 



Any web application you build there is always a need to support file upload. Node brings to you one of the most efficient ways to stream in a file in chunks.

1) Create an Express - Jade Project

a) Create an express project say File_Upload. If this is your first time to creation of express project, please refer my previous post here.

b) On the command prompt traverse to the project created and hit "node app.js", test this on your favorite browser on the respective port, by default "http://localhost:3000". You should see the Express text gracefully displayed.

2) Create the HTML 5 user interface in Jade

respective On the index.jade file, create a simple "input" element of type "file". On the form submit action, assign the action to a request as "doUpload".

The code for index.jade is as follows:

extends layout
block content
                h1= title
                form(method='post', name='', action='/doUpload',enctype='multipart/form-data')
                                table.form_table(cellspacing='5', cellpadding='5', border='0')
                                                tbody
                                                                tr
                                                                                td.label File Name:
                                                                                td
                                                                                                input(type='file', name='upload-file', id='fileUploader')
                                                                tr
                                                                                td
                                                                                td(colspan='3')
                                                                                                br
                                                                                                input.button2(type='submit', value='Upload', id='fileUploadButton')
               

3) Create the request handler

In the app.js add a request handler for the "doUpload" assigning a corresponding route handler such as "routes.doUpload".

The app.js code is as follows:


var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

app.get('/', routes.index);
app.get('/users', user.list);
app.post('/doUpload', routes.doUpload);

http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});


4) Create the route handler

In the index.js under the route folder, create the route handler and deligate the functionality to a routeHelper.

The index.js code is as follows:



/*
 * GET home page.
 */
var uploadHelper = require('./uploadHelper');
exports.index = function(req, res){
  res.render('index', { title: 'Project on simple file upload using HTML 5 and Node.js' });
};

exports.doUpload = function(req,res){
                uploadHelper.doUpload(req,res);
};

5) Create the route helper for upload

a) We have deligated the entire upload logic from the post request to the route helper. Create a file under route and call it say uploadHelper.js.

b) We employ the use of multi part to parse the incoming request and stream the uploaded file to a destination.

c) We employ the "fs" module to create a write stream and write the incoming chunks.

The helper code is as follows:



var multipart = require("../node_modules/multipart-js-master/lib/multipart.js");
var fs = require("fs");
var fileName;

 /**
 * Multipart do upload
 */
 function doUpload(req, res) {
                fileName="";
                req.setEncoding("binary");
    var stream = parseMultipart(req);
    var filePath = "c://test/";
    var fileStream = null;
  
   // Hanlder for request part
    stream.onPartBegin = function(part) {
            // Form the file name
            var writeFilePath = "";
                                fileName=stream.part.filename;
                        writeFilePath = filePath + fileName;
                        // Create filestream to write the file now
                        fileStream = fs.createWriteStream(writeFilePath);
                        fileStream.addListener("error", function(err) {
                            console.log("Got error while writing to file '" + filePath + "': ", err);
                        });
                        // Add drain (all queued data written) handler to resume receiving request data
                        fileStream.addListener("drain", function() {
                            req.resume();
                        });
    };

    // write the chunks now using filestream
    stream.onData = function(chunk) {
        console.log("Writing chunk now................");
        fileStream.write(chunk, "binary");
    };

    // Create handler for completely reading the request
    stream.onEnd = function() {
        fileStream.addListener("drain", function() {
           fileStream.end();
           uploadComplete(res);
        });
    };
}


/**
 * Multipart parser for request
 */
function parseMultipart(req) {
                var parser = multipart.parser();
    // using the parsed request headers
    parser.headers = req.headers;
    // Add listeners to request, transfering data to parser to write the chunks
    req.addListener("data", function(chunk) {
        parser.write(chunk);
    });
    req.addListener("end", function() {
        parser.close();
    });
    return parser;
}

/**
 * Multipart- Upload COmplete
 */
function uploadComplete(res) {
    if(fileName!=null && fileName!="")
                {             
                                console.log("fileName uploaded ==> ...."+fileName); 
                               
    }
}




exports.doUpload=doUpload;




6) Running the application

a) restart the application

b) On the browser hit "http://localhost:3000"

c) Select a file to upload and hit the submit button.

d) On the server residing system, navigate to "c:\test", you should see the uploaded file.

e) Ensure the encoding is set to binary to ensure the data coming in is supported for multi lingual applications.

3) Easy File Upload Using Node.js and HTML 5 using Body Parser

I found the previous example gets messy when you commence to use a Log in that employes cookieparser in node. The parallel usage of body parser and cookie parser lead to lot of complex issues. I thought it is a cleaner approach to implement the file upload using Body Parser.

1) Create an Express - Jade Project

a) Create an express project say Node_File_Upload. If this is your first time to creation of express project, please refer my previous post here.

b) On the command prompt traverse to the project created and hit "node app.js", test this on your favorite browser on the respective port, by default "http://localhost:3000". You should see the Express text gracefully displayed.

2) Create the HTML 5 user interface in Jade

On the index.jade file, create a simple "input" element of type "file". On the form submit action, assign the action to a request as "doUpload".

The code for index.jade is as follows:

extends layout
block content
                h1= title
                form(method='post', name='', action='/doUpload',enctype='multipart/form-data')
                                table.form_table(cellspacing='5', cellpadding='5', border='0')
                                                tbody
                                                                tr
                                                                                td.label File Name:
                                                                                td
                                                                                                input(type='file', name='uploadFile', id='fileUploader')
                                                                tr
                                                                                td
                                                                                td(colspan='3')
                                                                                                br
                                                                                                input.button2(type='submit', value='Upload', id='fileUploadButton')
               

3) Create the request handler

In the app.js add a request handler for the "doUpload" assigning a corresponding route handler such as "routes.doUpload". 

The app.js code is as follows:


var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

app.get('/', routes.index);
app.get('/users', user.list);
app.post('/doUpload', routes.doUpload);

http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});


4) Create the route handler

In the index.js under the route folder, create the route handler and deligate the functionality to a routeHelper.

The index.js code is as follows:



/*
 * GET home page.
 */
var uploadHelper = require('./uploadHelper');
exports.index = function(req, res){
  res.render('index', { title: 'Project on simple file upload using HTML 5 and Node.js' });
};

exports.doUpload = function(req,res){
                uploadHelper.doUpload(req,res);
};

5) Create the route helper for upload

a) We have deligated the entire upload logic from the post request to the route helper. Create a file under route and call it say uploadHelper.js.

b) We employ the use of body parser for the incoming request and stream the uploaded file to a destination.

c) We employ the "fs" module to create a write stream and write the incoming chunks.

The helper code is as follows:




var fs = require("fs");
var util = require('util');

var fileName;

 /**
 *  do upload
 */
 function doUpload(req, res) {
                fileName = req.files.uploadFile.name;
                req.setEncoding("binary");
    var filePath = "c://test/";
    var fileStream = null;
                var serverPath = filePath + req.files.uploadFile.name;
                var is = fs.createReadStream(req.files.uploadFile.path)
                var os = fs.createWriteStream(serverPath);

                util.pump(is, os, function(error) {
                    fs.unlinkSync(req.files.uploadFile.path);
                    if(error) {
                res.send(JSON.stringify({
                    error: 'Error occurred in File Upload'
                }));
                return;
            }
            upload_complete(req, res);
         }
                );


}


function upload_complete(req,res) {
    console.log("Request complete for upload and calling the dot net service for Parsing...................................");
    res.send("FILE UPLOAD COMPLETED ..................");
}





exports.doUpload=doUpload;



6) Running the application

a) restart the application

b) On the browser hit "http://localhost:3000"

c) Select a file to upload and hit the submit button.

d) On the server residing system, navigate to "c:\test", you should see the uploaded file.

e) Ensure the encoding is set to binary to ensure the data coming in is supported for multi lingual applications.

8 comments:

  1. Thank you for that - really nice :-)

    ReplyDelete
  2. EDIT:npm install -g express-generator@4
    To make express work globally

    ReplyDelete
  3. Very nice. The express modifications to include nib with stylus really helped me.
    Thanks.

    ReplyDelete
  4. There are lots of information about latest technology and how to get trained in them, like this have spread around the web, but this is a unique one according to me.
    node js developer london

    ReplyDelete
  5. Excellent ! I am truly impressed that there is so much about this subject that has been revealed and you did it so nicely
    Thanks
    Anika Digital Media
    seo services in UK
    web design development company in UK
    graphic design
    affordable seo services london

    ReplyDelete
  6. very nice blog thanks for the valuable information, i got some idea
    Node JS Online training
    Node JS training in Hyderabad

    ReplyDelete