In this tutorial I am going to explain you how to use the Node Package Manager (NPM) to package and deploy your own Node.js application. I assume that you have already installed the Node.js and NPM in your local system to run this example.
In my previous post I showed you how to authenticate with Twitter and also make use of Twitter API to retrieve tweets. I have made use of several Node packages to achieve what I intended to. But what if someone wants to take the source code and run it in their machine? For example one of the readers have copied the source code and they now just want to run the application without knowing what all dependencies are there from the code and then installing them individually. Is this even possible in Node.js? Is there something like Maven where in we just mention the dependencies and the mvn
automatically downloads the dependencies and can also launch the application.
The answer for the above questions is Yes, the solution for the above problmes is the Node Package Manager(NPM). Just like maven can host libraries which are reused in applications, even NPM can host libraries which are reused in your Node.js applications. NPM comes bundled with Node.js, so you can download Node.js from here and install it to also get NPM.
Now let us pick the sample app developed in this post, and create a deployable package which any user can download and run it in his environment.
The following Node packages are used in that sample app:
Creating an Empty Node.js Code Base
I am creating a new directory by name: node_packaging
and in that directory execute the following command:
npm init
When you run the above command, after that it will ask you a series of questions (just like when you are initializing project using maven). The series of questions are asked so as to create and populate a new package.json
file (think of it as your pom.xml
in maven). If you want to know more about package.json and its attributes, visit here. The below is how it looks after initializing using NPM. Look at the below screen and input the answers which shown in the screenshot. These values are used by the NPM to create a package.json file.
After that you can see a file by name package.json created with the following content:
{ "name": "node-packaging-demo", "version": "1.0.0", "description": "Demo to show node packaging", "main": "social_signin.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
I can edit/update the package.json, for example add the author details as shown below:
{ "name": "node-packaging-demo", "version": "1.0.0", "description": "Demo to show node packaging", "main": "social_signin.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Mohamed Sanaulla", "license": "ISC" }
Adding Dependencies using NPM
All the dependencies of the application are declared in package.json. One either edit the file directly or make use of the npm
tool to update the dependencies in package.json
. The below code adds the required dependencies to our app:
npm install --save express express-handlebars request querystring
The above command along with installing the mentioned packages, adds them as a dependency in pakcage.json. Let us now look at the contents of package.json:
{ "name": "node-packaging-demo", "version": "1.0.0", "description": "Demo to show node packaging", "main": "social_signin.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Mohamed Sanaulla", "license": "ISC", "dependencies": { "express": "^4.12.4", "express-handlebars": "^2.0.1", "querystring": "^0.2.0", "request": "^2.57.0" } }
In the above the highlighted lines are the dependencies of our application and the number against it is the version of the package we are using. If no version is mentioned while executing npm install --save
then the latest in NPM repository is used.
And when you list the files in your project folder you would see a folder by name node_modules. This is where all your modules get downloaded to.
Building the Node.js Application
The below is the directory structure of the application:
|--social_signin.js |--views |--home.handlebars |--my.handlebars |--layouts |--main.handlebars
This directory structure is relative to the directory we created first i.e node_packaging.
Following is the source code of our application
File: social_signin.js
//FileName: social_signin.js var express = require('express'); //NPM Module to integrate Handlerbars UI template engine with Express var exphbs = require('express-handlebars'); //NPM Module to make HTTP Requests var request = require("request"); //NPM Module To parse the Query String and to build a Query String var qs = require("querystring"); var app = express(); //Declaring Express to use Handlerbars template engine with main.handlebars as //the default layout app.engine('handlebars', exphbs({defaultLayout: 'main'})); app.set('view engine', 'handlebars'); //URL To obtain Request Token from Twitter var requestTokenUrl = "https://api.twitter.com/oauth/request_token"; //To be obtained from the app created on Twitter var CONSUMER_KEY = "GET_IT_FROM_TWITTER"; var CONSUMER_SECRET = "GET_IT_FROM_TWITTER"; //Oauth Object to be used to obtain Request token from Twitter var oauth = { callback : "http://localhost:3000/signin-with-twitter", consumer_key : CONSUMER_KEY, consumer_secret : CONSUMER_SECRET } var oauthToken = ""; var oauthTokenSecret = ""; app.get('/', function (req, res) { //Step-1 Obtaining a request token request.post({url : requestTokenUrl, oauth : oauth}, function (e, r, body){ //Parsing the Query String containing the oauth_token and oauth_secret. var reqData = qs.parse(body); oauthToken = reqData.oauth_token; oauthTokenSecret = reqData.oauth_token_secret; //Step-2 Redirecting the user by creating a link //and allowing the user to click the link var uri = 'https://api.twitter.com/oauth/authenticate' + '?' + qs.stringify({oauth_token: oauthToken}) res.render('home', {url : uri}); }); }); //Callback to handle post authentication. app.get("/signin-with-twitter", function(req, res){ var authReqData = req.query; oauth.token = authReqData.oauth_token; oauth.token_secret = oauthTokenSecret; oauth.verifier = authReqData.oauth_verifier; var accessTokenUrl = "https://api.twitter.com/oauth/access_token"; //Step-3 Converting the request token to an access token request.post({url : accessTokenUrl , oauth : oauth}, function(e, r, body){ var authenticatedData = qs.parse(body); console.log(authenticatedData); //Make a request to get User's 10 latest tweets var apiUrl = "https://api.twitter.com/1.1/statuses/user_timeline.json" + "?" + qs.stringify({screen_name: authenticatedData.screen_name, count: 10}); var authenticationData = { consumer_key : CONSUMER_KEY, consumer_secret : CONSUMER_SECRET, token: authenticatedData.oauth_token, token_secret : authenticatedData.oauth_token_secret }; request.get({url : apiUrl, oauth: authenticationData, json:true}, function(e, r, body){ var tweets = []; for(i in body){ var tweetObj = body[i]; tweets.push({text: tweetObj.text}); } var viewData = { username: authenticatedData.screen_name, tweets: tweets }; res.render("my", viewData); }); }); }); app.listen(3000, function(){ console.log('Server up: http://localhost:3000'); });
File Name: main.handlebars
<!-- FileName: main.handlebars--> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example App</title> </head> <body> {{{body}}} </body> </html>
File Name: home.handlebars
<!-- FileName: home.handlebars--> <h1>SignIn With Twitter Sample</h1> <a href="{{url}}">Signin with Twitter</a>
File Name: my.handlebars
<!-- FileName: my.handlebars--> <h1>Welcome {{username}} </h1> <h3>Your tweets</h3> <ul> {{#tweets}} <li>{{text}}</li> {{/tweets}} </ul>
Running the Node.js Sample Application
G:\node\node_packaging>node social_signin.js Server up: http://localhost:3000
Navigating to http://localhost:300 gives use a page with “Sign with Twitter” link. Clicking on it shows us the latest 10 tweets.
Pushing the code to Github
Now I am going to push the code to Github and then show you how packaging using NPM and package.json helps in sharing the application among other developers. Before carrying out the below task, install Git on your machine.
Carry out the following steps to push the code to github:
- Create a new repository on github.com
- Run
git init
in your project folder to initialize a new git repository locally. - Run
git status
in your project folder, you will see the following output:$ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) node_modules/ package.json social_signin.js views/ nothing added to commit but untracked files present (use "git add" to track)
We need to remove node_modules folder from getting committed to Github. So we create a new .gitignore file in the project root folder i.e in node_packaging folder. The content of .gitignore file is:
$ cat .gitignore node_modules
Run
git status
again, this time you will see that the node_modules folder is not listed in the files to be committed:$ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore package.json social_signin.js views/ nothing added to commit but untracked files present (use "git add" to track)
- Add the Github repository you created in Step-1 as a remote repository to the local repository you created in Step-2. This can be done using the following command:
git remote add origin GITHUB_REPO_URL
. You can get the GITHUB_REPO_URL from GitHub Repository page you created in Step-1 - Now commit and push your changes to the Github repository. It can be done as follows:
$ git add -A $ git commit $ git push origin master
Now the code should be available in your Github repository. Mine is at: https://github.com/sanaulla123/nodejs-package-demo
Advantage of Node.js Packaging
So we have setup everything for any developer to just clone the Github repository and start running the application locally. Let us also try to clone the repository in another location and see if this packaging really works!!
Mohamed@SANA-LAPTOP /g/node/node_packaging (master) $ cd .. Mohamed@SANA-LAPTOP /g/node $ mkdir node_packaging_clone Mohamed@SANA-LAPTOP /g/node $ cd node_packaging_clone/ #Cloning the Github repository Mohamed@SANA-LAPTOP /g/node $ git clone https://github.com/sanaulla123/nodejs-package-demo.git Mohamed@SANA-LAPTOP /g/node/node_packaging_clone $ ls nodejs-package-demo Mohamed@SANA-LAPTOP /g/node/node_packaging_clone $ cd nodejs-package-demo/ #There is no node_modules folder!! Mohamed@SANA-LAPTOP /g/node/node_packaging_clone/nodejs-package-demo (master) $ ls package.json social_signin.js views #This command picks up the dependencies from package.json and installs them to the local project folder. Mohamed@SANA-LAPTOP /g/node/node_packaging_clone/nodejs-package-demo (master) $ npm install #The node_modules folder got created after the above command. Mohamed@SANA-LAPTOP /g/node/node_packaging_clone/nodejs-package-demo (master) $ ls node_modules package.json social_signin.js views
Now you should be able to run the application as before. This was a small introduction to packaging your node.js applications. Hope you found it easy to understand and beneficial. If you have any questions on Node.js Application Packaging, please write it in the comments section. Enjoy reading more tutorials about Node.js in our blog.