-
Notifications
You must be signed in to change notification settings - Fork 52
NodeJs
Node is a JavaScript platform and compiler and a set of accompanying libraries. You can create general purpose JavaScript programs with Node, but it is especially designed to help you build networked applications that link a distributed architecture.
For Windows, the node install is found here:
<http://nodejs.org/>
If you want to install the latest version of node and npm on Linux, do this:
sudo apt-get install curl
curl -sL https://deb.nodesource.com/setup | sudo bash -
sudo apt-get install -y nodejs
It is not recommended to use the following, because it installs a very old version of nodejs. Maybe someday it will start working again:
sudo apt-get install nodejs npm
On Linux, you can use the which command to find the location of a program. For instance:
$ which nodejs
/usr/bin/nodejs
If that does not work, then NodeJs is probably not properly installed.
Reference from the Node GitHub site and other key links:
Node does not come installed on most systems, but it is easy to check if it is already on your system. Here is one simple test to see if it is installed:
node --help
Alternatively, you can try:
nodejs --help
If you don't get an error message, then it is installed. In particular, you should see output showing available commands.
It is always possible that Node is installed on your system but is not on your path. On Windows you can generally look for Node in the start menu. There should be a link to start a Node Command prompt, or to run Node interactively.
On Linux, Node is usually installed here:
/usr/bin/node
/usr/bin/nodejs
If Node is not installed, then go here and install install it:
##NPM Global Packages
NPM is the Node Package Manager. Many of the libraries that you will want to use with Node are best installed using NPM. Node and NPM are closely linked: I can't imagine using Node without NPM and vice versa. The default Node install includes NPM.
Most NPM packages are installed only for a particular project. They have local scope and are not found on your PATH. However, there are a few libraries that I like to install globally so that they are always on my path. These include:
- karma-cli
- grunt-cli
- jasmine-node
- express-generator
- nodemon
- mocha
On Windows, install them like this:
npm install -g karma-cli
npm install -g grunt-cli
npm install -g jasmine-node
npm install -g express-generator
npm install -g nodemon
npm install -g mocha
On Windows, this typically installs express into your AppData/Roaming directory.
To issue the same commands on Linux, you need to do some setup:
mkdir ~/npm
npm config set prefix ~/npm
Then add this to the bottom of your .bashrc:
export PATH="$PATH:$HOME/npm/bin"
###What's Globally Installed? {#whatsGlobal}
To see what is installed globally, issue the npm list command with -g and --depth=0 as arguments:
npm list -g --depth=0
/home/charliecalvert/npm/lib
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
The -g bit ensures that we look only at globally installed packages. We use --depth=0 to ensure we see only the packages we have explicitly installed, and not the packages that those packages rely upon.
###Configure Global Install {#configGlobal}
To make sure npm is configured correctly, type the following:
npm config list
One Windows, it might look something like this:
>npm config list
; cli configs
registry = "https://registry.npmjs.org/"
user-agent = "npm/1.4.21 node/v0.10.30 win32 x64"
; builtin config undefined
prefix = "C:\\Users\\charlie\\AppData\\Roaming\\npm"
; node bin location = C:\Program Files\nodejs\\node.exe
; cwd = C:\Src\Git\JsObjects\JavaScript
; HOME = C:\Users\charlie
; 'npm config ls -l' to show all defaults.
On Linux, the same command yields these results on one of my VMs:
$ npm config list
; cli configs
registry = "https://registry.npmjs.org/"
user-agent = "npm/1.4.28 node/v0.10.35 linux x64"
; userconfig /home/charlie/.npmrc
prefix = "/home/charlie/npm"
; node bin location = /usr/bin/node
; cwd = /home/charlie
; HOME = /home/charlie
; 'npm config ls -l' to show all defaults.
After making changes to .bashrc you either restart your shell or type: source ~/.bashrc. In either case, your .bashrc file will be processed and any changes you made should take effect.
Now you can issue the npm install commands shown above. The packages will be installed in your ~/npm directory.
NOTE: On JsObjects there is a script that will perform most of the actions described above, though it will not automatically update your .bashrc file.
NOTE: You might also want to look in this hidden directory for additional details about your NPM installation: ~/.npm.
You can use NPM to install local libraries that you will use in your node programs. These libraries are installed in the same directory as your project. In particular, they are placed in a folder called node_modules.
Many node program rely on a library called express. Express is not built into Node. Instead, it is a library that you must install.
NOTE: Express gets installed twice. Above you saw how to globally install the express-generator. Here you are learning how to install express itself, which is a local library.
To install express, we typically issue the following command from the root of our project:
npm install express --save
This will install a local copy of express in a directory called node_modules. The --save switch saves the command to install express into a file called package.json. Once express is saved into package.json you can reinstall it by simply typing npm install. You can --save multiple packages into package.json. Then you can reinstall them at any time by simply typing npm install. You would want to do this if you move the project to a new system, or if you deleted the node_modules directory. The package.json file also helps if you give your project to another developer. Then they can install all the needed libraries by just type npm install.
NOTE: It is generally not appropriate to include the node_modules directory when you give a project to another developer or when you check it into source control. The reason for this is simple: the node_modules directory can be huge if you include a lot of npm packages in your project. As a result, we --save the libraries into package.json and then let the user install them with npm install. This is why we put node_modules in our .gitignore files.
Any other libraries you install will also end up in this directory. For instance, if you want to installed the openid library, you would issue this command:
npm install openid --save
Now the node_modules directory will contain libraries: express and openid.
To link express into your project, go to the root of your project and type the following:
npm link express.
To update node, type the following
sudo npm install npm -g
##Using package.json {#packageJson}
All your projects should include a file called package.json. To create one from scratch, go to the root of your project and issue this command:
npm init
You will be presented with a series of prompts to fill out. Just step through them one by one, leaving the ones that don't interest or confuse you blank. When you are done, there will be a file called package.json in your current directory.
To add packages to package.json, issue a command like this:
npm install require --save
This installs the package called require into a folder called node_modules. It also saves a command to install the package into package.json. To reinstall require later, just type this command:
npm install
This command processes package.json and automatically installs all the packages you saved into it. You can, of course, save information about many packages into a single package.json file.
You may have a project that depends on express. In such cases, the author of the project will probably create a file called package.json that will contain a reference to express. If this file exists, you can just type the following to install express and any other libraries that the project depends upon:
npm install
Here is the contents of a simple package.json file that installs both express and openid as well as a library called mdirp:
{
"name": "OpenId04",
"version": "0.0.1",
"private": true,
"dependencies": {
"openid": "latest",
"express": "latest",
"mkdirp": "latest"
}
}
To put the thing you installed in package.json:
npm install "karma-script-launcher" --save-dev
The key point to remember is that npm install processes the contents of the file called package.json. It installs all the libraries listed in that file in a local directory called node_modules. By locally, I mean that the directory is now included in your project.
If you follow the link to package.json for BridgeSailor you will see that karma is listed in that file:
"devDependencies": {
"requirejs": "^2.1.11",
"karma": "^0.12.14",
"karma-jasmine": "^0.2.0",
"karma-requirejs": "^0.2.1",
"karma-chrome-launcher": "^0.1.3",
"karma-firefox-launcher": "^0.1.3"
}
This means that running npm install will install all the files listed above, including the karma library.
The point of npm install and package.json is that they work together to install a series of libraries, rather than asking you to type the following series of individual commands:
npm install requirejs
npm install karma
npm install karma-jasmine
npm install karma-requirejs
npm install karma-chrome-launcher
npm install karma-firefox-launcher
Typing all of the above commands is time consuming, error prone and repetitious. Therefore we use package.json, which needs to be configured correctly once, and works automatically thereafter.
##Adding entries to package.json
Usually all you need to do is process package.json by typing npm install. However, you may occassionally. want to add your own dependency to package.json. Here is how to put a library called karma-script-launcher in package.json:
npm install "karma-script-launcher" --save-dev
The command shown above first installs karma-script-launcher into node_modules. It then adds an entry for it to package.json. Then next time you run npm install the karma-script-launcher package will be installed automatically because it is now included in package.json.
Consider this command:
npm install karma --save-dev
This command installs the library, and saves the library name into package.json if it is not already there.
Command | Result |
---|---|
npm install | process package.json and install all packages it references into node_modules |
npm install chai | install chai into node_modules |
npm install chai --save | install chai into node_modules and add chai to package.json |
npm install chai --save-dev | install chai into node_modules and add chai to package.json in a section listing packages used during development. |
##More on Node and Package.json
NPM related issues are specific to node, not to Linux. If you were using node on Windows or the Mac, npm behaves in a very similar fashion.
npm is the Node Package Manager. It installs libraries that are used by Node projects. Some of the libraries, such as fs (the File System package) are built into node, but most are open source projects hosted on GitHub.
Here are a few node packages (libraries) that I often install globally:
/usr/lib
├─┬ [email protected]
├─┬ [email protected]
├─┬ [email protected]
├─┬ [email protected]
├─┬ [email protected]
├─┬ [email protected]
└─┬ [email protected]
These are stored here on a typical Linux system:
$ ls -l /usr/lib/node_modules/
total 28
drwxr-xr-x 5 nobody charlie 4096 Apr 21 12:24 express-generator
drwxr-xr-x 6 nobody charlie 4096 Apr 20 09:57 grunt-cli
drwxr-xr-x 9 nobody charlie 4096 Apr 21 16:02 jasmine-node
drwxr-xr-x 4 nobody charlie 4096 Apr 26 15:43 js-beautify
drwxr-xr-x 6 nobody charlie 4096 Apr 21 18:31 jshint
drwxr-xr-x 4 nobody charlie 4096 Apr 27 10:23 karma-cli
drwxr-xr-x 9 root root 4096 May 5 07:56 npm
We install these global packages by typing something like:
sudo npm install -g karma-cli
Where karma-cli is the package we want to install.
Each project also has packages that it uses. Each individual project might rely on a particular version of a package. For instance, one express project might use express 3.5.1, while another might use express 4.0.0. As a result, we don't install these packages globally. Instead, we install them inside the project we are currently using. This way, a particular project can rely on a particular version of a package. Specifically, we install them in a folder called node_modules.
Here, for instance, are the packages installed for a project called Week02Jade:
charlie@MountainStreamsLinux:~/Git/Prog282/Week02Jade
$ ls -l node_modules/
total 28
drwxrwxr-x 3 charlie charlie 4096 Apr 26 16:44 body-parser
drwxrwxr-x 5 charlie charlie 4096 Apr 26 16:44 cookie-parser
drwxrwxr-x 3 charlie charlie 4096 Apr 26 16:44 debug
drwxrwxr-x 5 charlie charlie 4096 Apr 26 16:44 express
drwxrwxr-x 5 charlie charlie 4096 Apr 26 16:44 jade
drwxrwxr-x 3 charlie charlie 4096 Apr 26 16:44 morgan
drwxrwxr-x 2 charlie charlie 4096 Apr 26 16:44 static-favicon
These packages get installed when we type npm install. This action causes npm to process the contents of package.json, and to install the packages listed there:
$ cat package.json
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "DEBUG=my.application node ./bin/www"
},
"dependencies": {
"express": "~4.0.0",
"static-favicon": "~1.0.0",
"morgan": "~1.0.0",
"cookie-parser": "~1.0.1",
"body-parser": "~1.0.0",
"debug": "~0.7.4",
"jade": "~1.3.0"
}
}
Do you see that the directory listing is the same as the packages listed in package.json? The bottom line is that we need to think in terms of both global and local versions of our npm packages.
You can find all the npm packages here:
In many cases, and certainly in most classes I teach, your life will be simpler if both Node and NPM are always on your path. Your install of Node may set things up that way for you automatically. If not, make sure they are on your path:
http://www.elvenware.com/charlie/os/windows/faq.html#environment
Typically, on Windows, this is the item I want to add to my path:
- <C:\Users\Charlie\AppData\Roaming\npm>
Your milage may differ, particularly in regard to the user name, but that should provide a start for you.
Use the following syntax to identify the latest version of a package:
npm show [PackageName] version
This is not showing the version you have installed, but the latest version that is available on the net.
For instance:
G:\Src\Git\MyStuff>npm show voxel-engine version
npm http GET https://registry.npmjs.org/voxel-engine
npm http 200 https://registry.npmjs.org/voxel-engine
0.16.3
This means that the package voxel-engine is at version 0.16.3.
To find the owner of a package, enter the following:
npm owner ls [package]
For instance:
G:\Src\Git\voxel-hello-world>npm owner ls voxel-hello-world
npm http GET https://registry.npmjs.org/voxel-hello-world
npm http 200 https://registry.npmjs.org/voxel-hello-world
maxogden <EMAIL ENDS UP HERE>
To update all the packages you have installed globally:
npm update -g
To update a specific global package such as grunt:
npm update -g grunt
To update a local package such as grunt:
npm update grunt
Remember that your globally installed file are placed in your AppData | Roaming | npm folder. The path on your system might look something like this:
C:\Users\Charlie\AppData\Roaming\npm\node_modules
It is nice to know that your project is using the latest packages. You can do this by running the npm outdated command:
npm outdated
If you first delete your node_modules folder, and then run it, you might see output like this:
charlie@mongovbox:~/Git/writings/Tech/Games/ThreeFloor$ npm outdated
npm http GET https://registry.npmjs.org/morgan
npm http GET https://registry.npmjs.org/cookie-parser
npm http GET https://registry.npmjs.org/body-parser
npm http GET https://registry.npmjs.org/debug
npm http GET https://registry.npmjs.org/serve-favicon
npm http GET https://registry.npmjs.org/express
npm http GET https://registry.npmjs.org/jade
npm http 304 https://registry.npmjs.org/morgan
npm http 304 https://registry.npmjs.org/body-parser
npm http 304 https://registry.npmjs.org/serve-favicon
npm http 304 https://registry.npmjs.org/express
npm http 304 https://registry.npmjs.org/debug
npm http 304 https://registry.npmjs.org/jade
npm http 304 https://registry.npmjs.org/cookie-parser
Package Current Wanted Latest Location
morgan MISSING 1.3.2 1.4.1 morgan
body-parser MISSING 1.8.4 1.9.2 body-parser
serve-favicon MISSING 2.1.6 2.1.6 serve-favicon
express MISSING 4.9.8 4.10.1 express
debug MISSING 2.0.0 2.1.0 debug
jade MISSING 1.6.0 1.7.0 jade
cookie-parser MISSING 1.3.3 1.3.3 cookie-parser
Here you can see that our package.json file requests morgan 1.3.2. We can see that by opening up package.json and looking:
{
"name": "Test05",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "nodemon ./bin/www"
},
"dependencies": {
"express": "~4.9.0",
"body-parser": "~1.8.1",
"cookie-parser": "~1.3.3",
"morgan": "~1.3.0",
"serve-favicon": "~2.1.3",
"debug": "~2.0.0",
"jade": "~1.6.0"
}
}
As you can see, we are explicitly asking for 1.3.0. But npm outdated tells us that there is a newer version. So we just update package.json so that it asks for the latest, which is 1.4.1:
"morgan": "~1.4.1",
We can do the same for all the packages we are using. Then run npm update after you have updated your package.json file. That will ensure that the installed versions of the files in node_modules are up to date. If the call to npm update fails, you can always just delete the files in your node_modules directory and run npm install.
You get the same output if you run npm outdated if you have a node_modules directory, but you may see reports on the nested packages in the node_modules. That information may not be useful. As a result, it might be best to start by deleting the folder:
rm -r node_modules
You may have trouble with npm, and find that you have an older versions installed. For instance, version 1.4.28. We should be able to update it fairly. Here is the standard technique, but don't do this quite yet:
sudo npm update -g npm
But that may not work in our case. The issue, I believe, is that many of us have set npm to perform updates locally to our npm folder, so that we don't have to worry sudo permissions. We set that up by typing the following command:
npm config set prefix ~/npm
This sets where we install global files as explained here: https://docs.npmjs.com/misc/config#prefix.
We want to do this. It is a best practice. However, when we type npm update -g npm it updates our ~/npm version of npm and not the one in /usr/bin. Of course, the one in /usr/bin/ is the one that is on our path. So now we have outdated version of NPM that we can reach and an updated version that we can't access. I suppose we have two solutions. The first looks like this, where we begin by updating the local copy of NPM:
npm update -g npm
sudo rm /usr/bin/npm
sudo ln -s ~/npm/bin/npm /usr/bin/npm
That should create a symbolic link to the copy of NPM in our /usr/bin folder to the one in our ~/npm/bin/npm. Then we should be on the latest. At the time of this writing, that looks like.
$ npm --version
2.4.1
Alternatively, I think we could temporarily set the prefix to /usr/bin:
npm config set prefix /usr/bin
sudo npm update -g npm
Then check your work:
$ npm --version
2.4.1
Then set the prefix back to ~/npm
npm config set prefix ~/npm
##Error: Cannot find module One of the classic Node errors looks like this:
node Server.js
module.js:340
throw err;
^
Error: Cannot find module XXX
In this case, XXX is usually the name of a library, such as Express, Morgan, Walk, etc. This error usually occurs because you have not typed the following command:
npm install
This command processes the list of libraries found in the file package.json. The package.json file is usually part of any node program. There are few cases when you will not need package.json and in such cases its absence is not significant. In those cases, you need only type something like node Server.js to start the program. If, however, you get a cannot find module error, and package.json is not present, then you either do not have a complete copy of the program, or the program itself is not complete.
###Error: Couldn't Read Dependencies
Sometimes you may also see this error:
npm install
npm ERR! install Couldn't read dependencies
npm ERR! package.json ENOENT, open '/home/charlie/package.json'
etc...
This errror occurs, needless to say, because a copy of package.json is not found. As mentioned above, there are cases when a node program does not rely on any libraries, and hence package.json does not exist. But the error above usually occurs because you are not in the proper directory. For instance, you are in your home directory, and the program you want to run is in ~/Git/JsObjects/JavaScript/Design/SimpleQueue.
To return to our main point: the primary problem that developers encounter when the see this error is simply forgetting to type npm install.
###Error: Address in Use EADDRINUSE {#EADDRINUSE}
The EADDRINUSE (Error Address In Use) message usually means that the port is in use by another program. For instance, you left an instance of a program running on the port where you want to launch your node server. Usually, fixing this is just a matter of finding the SSH or Windows command prompt where the server is running, and pressing Ctrl-C to stop the server:
C:\Git\P282\CanvasGrid>node server.js
Listening on port :30026
^C <== Here I press Ctrl-C
C:\Git\P282\CanvasGrid>
An important variation on this error can occur if you are running upstart. Details about that variant of the EEADDRINUSE error are discussed below.
###NODE_PATH and Cannot Find Modules {#nodePath}
A related issue occurs when you cannot find modules that you installed globally with NPM. Usually there is no need to install modules globally. However, in some cases it can be useful. Suppose you globally install walk:
>npm install -g walk
npm http GET https://registry.npmjs.org/walk
etc...
At this point, you would normally be all set to use walk in your program. But sometimes you get an error like the following, even after your install walk globablly:
>node Server.js
module.js:340
throw err;
^
Error: Cannot find module 'walk'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
The problem could be that you don't have the environment variable called NODE_PATH set up correctly. To fix the problem, simply add the correct path to your global node_modules directory to your path:
set NODE_PATH=C:\\Users\\Charlie\\AppData\\Roaming\\npm\\node_modules
Or, if you want, use the environment dialog as explained above.
Below you will find some sample node programs. Here are the steps for using them.
- Create a directory to host your project. (mkdir MyFirstNodeServer) You might for instance, create the directory in a Git repository.
- Navigate into that directory (cd MyFirstNodeServer)
- Create a file called server.js and use a text editor to place one of the sample programs shown below inside your file.
- Then run your program by typing node server.js.
For instance, you might type something like this:
C:\Git\Prog282-Calvert>mkdir MyFirstNodeServer
C:\Git\Prog282-Calvert>cd MyFirstNodeServer
Now create server.js as described below. Then run the server:
C:\Git\Prog282-Calvert\MyFirstNodeServer>node server.js
Once the server starts, go to your browser, and type the following:
http://localhost:30025
Here is the first, hello world style, node program that you can place in the server.js file:
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('It works!\n');
}).listen(30025);
console.log('Server running at http://127.0.0.1:30025/');
Here is another hello world type of program. Again, place it in a file called server.js. You might for instance, create a directory called MySecondNodeServer, and put this second server.js file in that directory:
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/html'});
response.end('<p>It works</p>');
}).listen(30025);
console.log('Server running at http://127.0.0.1:30025/');
And here is one more:
var http = require('http');
var fs = require('fs');
http.createServer(function (request, response) {
var html = fs.readFileSync('index.html');
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(html);
response.end();
}).listen(30025);
console.log('Server running at http://127.0.0.1:30025/');
Notice that this last program depends on the presence of a file called index.html, where index.html can be any valid HTML file.
Here is how to get the server to specify the port:
var port = process.env.PORT || 30025;
By default, we use port 30025 in my Bellevue College classes.
You can find the HelloExpress program on JsObjects:
https://github.com/charliecalvert/JsObjects/tree/master/JavaScript/NodeCode/HelloExpress
To get started, create a directory called HelloExpress and then switch into that directory:
mkdir HelloExpress
cd HelloExpress
The next step will be to install the express library on which this project relies. You can do this one of two ways. Both involve issuing commands at the shell (command) prompt. You should issue the command in the same directory where you place your project. The simplest command looks like this:
npm install express
When you are done, you should have a folder called node_modules with the contents of the express library in it. You can also choose to download a global copy of express that you can use in multiple projects:
npm install -g express
npm link express
After issuing these last two commands, you are set to use Express with your current project. If you create another project that uses express, you can give it access to the Express library by again issuing this command:
npm link express
This will link in express using the global copy downloaded earlier. This technique saves disk space, as it means you need only one copy of Express on your system.
Here is the server for the HelloExpress program:
var express = require('express');
var app = express();
var fs = require('fs');
var port = process.env.PORT || 30025;
app.get('/', function(req, res) {
var html = fs.readFileSync(__dirname + '/Public/index.html');
res.writeHeader(200, {"Content-Type": "text/html"});
res.write(html);
res.end();
});
app.use("/", express.static(__dirname + '/Public'));
app.listen(port);
console.log('Listening on port :' + port);
This code has a method called app.get. It defines a default route that will be called when the user browses to Port 30025:
http://localhost:30025
The app.get method shown here reads in a file called index.html, then publishes it on the Node web server. When reading in the file, it uses a library called fs (FileSystem) and a method called readFileSync.
To make this program work, create a directory called Public. In it, put a very simple HTML file such as this one:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<title>Express Hello</title>
</head>
<body>
<h1>Hello Experss</h1>
<p>A simple Node Express program</p>
</body>
</html>
The file shown above is the one that will be read in by the node readFileSync method, and then served up by the node web server.
Now start the node webserver by running this command:
node server.js
Here is another NODE example that uses express:
var express = require('express');
var app = express();
var fs = require('fs');
var port = process.env.PORT || 30025;
app.get('/', function(req, res) {
console.log("root request sent");
var html = fs.readFileSync(__dirname + '/public/index.html');
res.writeHeader(200, {"Content-Type": "text/html"});
res.write(html);
res.end();
});
app.get('/dirname', function(req, result) {
result.send({'result': __dirname});
});
app.get('/port', function(request, result) {
result.send({'result': port});
});
app.use(express.static(__dirname + '/public'));
app.listen(port);
console.log('Express server started on port %s', port);
The first three lines are like import or include statements in other languages such as Java, C# or C++:
var express = require('express');
var app = express();
var fs = require('fs');
The first line asks that we load in a library called Express. The second line creates an instance of the express object. The third line brings a library called fs (filesystem) that is built into node.
The next line establishs the port that your project will run on:
var port = process.env.PORT || 30025;
The words process.env.PORT refers to the environment variable called PORT. On many machines this will not be set, so our code specifies the value for PORT if PORT is not assigned. If you need help with environment variables, see this page:
The next lines of code defines the action that our program will take if the user goes to the root of our site. For instance, if we are running on localhost, then the following method is called when the user goes to http://localhost:30025:
app.get('/', function(req, res) {
console.log("root request sent");
var html = fs.readFileSync('public/index.html');
res.writeHeader(200, {"Content-Type": "text/html"});
res.write(html);
res.end();
});
This code logs a debug message to the console. Then it reads in an HTML file from the file system and packages it up using the HTTP protocol. It then sends it to the user. In a typical scenario, the user invoked this method by typing a URL in the address bar of a browser. Therefore the HTTP packet is delivered to a browser and rendered there so the user can read it.
The following two lines of code mirror back the current directory and PORT on which the node server is running:
app.get('/dirname', function(req, result) {
result.send({'result': __dirname});
});
app.get('/port', function(request, result) {
result.send({'result': port});
});
These commands are invoked when the user types one of the following URLS
http://localhost:30025/dirname
http://localhost:30025/port
The express library matches up the route designated by the URLs to the app.get or app.post method that corresponds to it. For instance, the following URL designates a route called dirname:
http://localhost:30025/dirname
This method is called when Express detects that the user designated the dirname route:
app.get('/dirname', function(req, result) { etc...
Express knows how to handle by HTTP get verbs and HTTP post verbs:
app.post('/dirname', function(req, result) { etc...
For now, you can Read more here:
We used to use a tool called bodyParser() when working with post. But now we should use connect:
npm install connect --save
And in your code:
var connect = require( "connect" );
app.use(connect.urlencoded());
app.use(connect.json());
And then use it:
app.post('/add', function(request, response) {
console.log('add called');
console.log(request.body);
var operandA = parseInt(request.body.operandA);
var operandB = parseInt(request.body.operandB);
var result = addingMachine.myObject.add(operandA, operandB);
response.send({ "result": result });
});
Example code is found here:
There is one more very important line is the code sample shown in the previous section:
app.use(express.static(__dirname + '/public'));
As you recall, our default route for this node script loads a file called index.html that is stored in a folder called public:
var html = fs.readFileSync(__dirname + '/public/index.html');
The app.use command shown above ensures that Express knows to look in the public directory for your files. If you don't employ app.use to make directories known to express, then your program may not be able to locate your files.
Inside of index.html, you may want to reference JavaScript and CSS files. If you place them in the public directory, then you should reference them like this:
<script src="/public/jquery.js"></script>
Finally, let's think for a moment about how to load index.html in our default handler. In many cases the following code will work, using a relative path to find the public directory:
var html = fs.readFileSync('public/index.html');
However, the following code is preferred:
var html = fs.readFileSync(__dirname + '/public/index.html');
This code references the path to the directory where your node program was launched, and then adds public/index.html to it. For instance, if your server.js file were in a directory called C:\src\ then the following path would be used by readFileSync:
C:\src\public\index.html
If your program were in subdirectory of your home directory on Linux, then the path used by readFileSync might look like this:
/home/sally/src/public/index.html
Once you have some of the core concepts behind Express under your belt, it is time to move on to full Express application. To get started, be sure you have both Express and a template library called Jade installed:
npm install -g express
npm install -g jade
Make sure the express application is on your path. It is usually found in AppData/Roaming. For instance, the Express executable is found here on my system:
C:\Users\Charlie\AppData\Roaming\npm\node\_modules.bin
On some systems it is here:
C:\Users\Charlie\AppData\Roaming\npm\
In either case, you are looking for a program called express and express.cmd. Make sure they are on your path.
It may also be available here in your generated applications:
node_modules.bin
Now let Express generate the framework for your application. For instance, the following command generates an application called MyApp01:
express MyApp01
This command creates a directory called MyApp01. Inside it you will find one main file and three subdirectories:
MyApp01
MyApp01/app.js // We usually call this file server.js
MyApp01/public
MyApp01/routes
MyApp01/views
Alternatively, you can do something like this, which provides a library called stylus for use with CSS files:
express -c stylus MyApp02
You can read about stylus in more depth later in this document.
By default, Express applications run on port 3000. Since we typically run our applications on port 30025, the first thing you might do is open app.js and modify the line that specifies the default port:
app.set('port', process.env.PORT || 30025);
##Jade
Jade is a template library like Handlebars. It also is a bit like Markdown, in that it provides a shorthand syntax for composing HTML pages.
Here is an example of how to layout a Jade template:
doctype 5
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
nav
ul
li
a(href="/") page01
li
a(href="/page02") page02
li
a(href="/page03") page03
h1 #{title}
block content
In the next few paragraphs I describe how Jade templates get linked in to our applications. Much of the code I describe is autogenerated for you when you first create the express application. However, some of the code you have to write yourself. Of course, whether the code is autogenerated, or created automatically, you should be sure that you understand all the pieces and what they do.
We can integrate our Jade template pages by creating a JavaScript file (often called index.js) in our Routes directory that defines our routes. These routes detail how the templates should be rendered. We also add code to our main express JavaScript file. Here is an example:
exports.index = function(request, response){
response.render('index', { title: 'Margie', foo: 'bar' });
};
exports.page02 = function(request, response){
response.render('page02', { title: 'Margie', foo: 'bar' });
};
exports.page03 = function(request, response){
response.render('page03', { title: 'Margie', foo: 'bar' });
};
The code shown above defines some template variables called title and foo. It also links in three Jade templates from the views directory. The templates referenced in the above code are called:
- index.jade
- page02.jade
- page03.jade
In our app.js file we link in the views directory and Jade like this:
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
And then in app.js we also include the following code:
// Link in the routes directory where index.js lives
var routes = require('./routes');
// Link in the routes themselves.
app.get('/', routes.index);
app.get('/page02', routes.page02);
app.get('/page03', routes.page03);
Some resources:
Stylus is a library that allows you to create CSS pages using a technique that is a bit reminicescent of a template library or of markdown. In other words, it provides an alternative syntax for composing CSS pages, as well as a syntax for working with variables and parameters while composing CSS pages.
When you add stylus to a node express page, the following line of code should be present in your main express file:
app.use(require('stylus').middleware(__dirname + '/public'));
Here is a Simple Styl Page
border-stuff()
border solid thin black
body
background-color #00AA00
padding: 50px
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif
a
color: #004400
nav
background-color #00CC00
border-stuff(0)
padding 25px
ul
list-style none
li
display inline
border-stuff(0)
margin 10px
padding 5px
background-color #00FF00
First install jasmine-node:
sudo npm install -g jasmine-node
You will also want to install request locally with one of the following:
npm install request
npm install request --save-dev
The second option saves your command into package.json, if package.json already exists.
Create a simple route you want to test:
app.get('/hello', function(request, response) { 'use strict';
response.send('Hi there.');
});
Define a basic Jasmine-Node test by saving the following as Tests/SimpleSpec.js:
var request = require('request');
describe("A suite", function() {
it("should respond with hello world", function(done) {
request("http://localhost:30025/hello", function(error, response, body) {
expect(body).toEqual("Hi there.");
done();
});
});
});
Now start your server running in one shell:
node Server.js
Then open a second shell and run your tests:
jasmine-node Tests/
Voila! You are done.
Install nodemon:
npm install -g nodemon
Now use it to start your application:
nodemon server.js
Now you won't have to restart your application each time you change the source.
Here is how to debug outside of Eclipse:
Though it is not necessary for debugging, this is a good time to check that you have JsHint installed. If you don't have it installed, or if you are at all unclear how to install new software into Eclipse, then please see this link:
Just to review, here is the URL for JsHint:
After you choose Help | Install New Software and click the add button, you fill in the dialog like this:
Let's now start talking about debugging inside Eclipse. You need to Install V8 into Eclipse. Choose Help | Install Software as above, and enter this URL:
Next you need to install Node Eclipse. Again Choose Help | Install Software and this time use this URL:
Start the program like this:
node --debug-brk server01.js
Regardless of the port that you told your program to run on, the debugger runs on port 5858:
G:\Git\OpenId03>node --debug-brk server01.js debugger listening on port 5858
When starting the server in the browser, however, you should still use the port you assigned:
http://localhost:30025
In Eclipse set up a Debug run configuration. First bring up the Debug Run Configuration dialog:
Then set up the configuration for the V8 engine on port 5858:
I am not able to set breakpoints using the tools. Instead, I have to go into the code and manually type the word debugger; on the line where I want the debugger to break. Then I do the following:
- type node --debug-brk server01.js at the command line
- start the debugger in Eclipse, press F8 once to get passed the first breakpoint.
- launch my program in in the browser: http://localhost:30025
The program will then stop at my breakpoint:
You can step through the debugger with the following keys:
- F5 (Step into)
- F6 (Step over)
- F8 (Continue - run)
UpStart is a Linux utility that ships with recent Ubuntu releases. It can be used to ensure that your node servers or other program stay in memory even after you have closed your shell. It will even restart the programs automatically if the OS is rebooted.
Note that this project includes a file called ExpressSend.config. You can use this file to ensure that your application is launched when your OS boots, and that it will stay running, even if it temporarily crashes.
In JsObjects, there is a program called ExpressSend:
JsObjects/JavaScript/NodeCode/ExpressSend
If you open ExpressSend.config in an editor, you will see a few portions of the line that begins with the word exec that you might want to edit to convert them for use in your own programs. For instance, seee the line that begins like this:
exec /usr/bin/nodejs /home/charlie/ExpressSend/server.js
If your version of the server is located elsewhere, then change the line as necessary. For instance:
exec /usr/bin/nodejs /home/belinda/bin/server.js
Note that I replaced charlie/ExpressSend with belinda/bin. You should edit your version of ExpressSend.config to reflect that paths and file names on your system.
You can create a symbolic link to a deeply nested directory like this:
ln -s /home/ubuntu/Git/Prog282-Hints/CanvasGrid03 CanvasGrid
If you give that command in your home directory, then you will end up with a directory that looks like this:
/home/ubuntu/CanvasGrid
The point, of course, is that this new directory is an alias, soft link to the CanvasGrid03 directory.
Place ExpressSend.config in the /etc/init directory:
/etc/init/ExpressSend.config
The command to copy it to appropriate directory would be:
sudo cp ExpressSend.config /etc/init/.
Once the file is in the /etc/init directory, you can start your program by typing the following:
sudo start ExpressSend
You can stop it with following command:
sudo stop ExpressSend
When you reboot the system, your program will start automatically.
Error messages and other output from your program are recorded in the following location:
/var/log/node.log
If you examine the script, you can see that this file name is configurable.
You should create one script of this type for each program that you want to launch.
In your node program, you may need to alter paths to your files so that they include the __dirname variable:
var html = fs.readFileSync(__dirname + '/Public/index.html');
The following might also work, though i need to test it more:
var html = fs.readFileSync('./Public/index.html');
For now, I recommend the first option. This is necessary because your program is no longer being launched from the directory in which you created it, but instead, is start from the /etc/init directory. There fore you need to use __dirname, which resolves to the complete path to your file. For instance:
/home/charlie/git/MyProgram/Public/index.html
The __dirname variable, which is built into Node, gives you the /home/charlie/git/MyProgram part of the path. Of course, on your system that bit of the path will probably be different. Here is more information on dirname:
<http://nodejs.org/docs/latest/api/globals.html#globals_dirname>
We specify where the log file will be written in this part of our upstart scripts:
exec /usr/bin/nodejs /home/ubuntu/ExpressSend/server.js >> /var/log/node.log 2>&1
This command has three parts that we need to get write:
- exec - This command executes a process or program.
- /usr/bin/nodejs - This parameter points at our nodejs program. This is the program to be executed
- /home/ubuntu/ExpressSend/server.js - This is the path to the script that nodejs will run.
Then we redirect the output from the program to a text file called node.log that is located in the /var/log directory:
>> /var/log/node.log 2>&1
To see the content of that file, run this command:
cat /var/log/node.log
That is the most important command when it comes to debugging our UpStart scripts.
Let's talk for a minute more about this strange command:
>> /var/log/node.log 2>&1
The > character redirects the output from one command to some other place, usually a file. So this command sends the output of the echo command to a file called foo.txt:
echo foo > foo.txt
After the command is run, foo.txt contains the string foo.
This command appends the output of the echo command to foo.txt:
echo bar >> foo.txt
Now foo.txt contains both foo and bar. The > operator will overwrite foo.txt, and the >> operator will append data to it.
All this is called redirection, which is different from piping, which is done with the | symbol.
This part of the command is more complicated:
2>&1
There are actually two streams of output that can occur when we launch a program. One is the standard output stream, and that is what we are redirecting above. The other is stderr, which is an error stream. By error stream, I mean that it is a stream that contains the output produced by errors in our program.
The bizarre looking 2>&1 command redirects stderr to the same place as stdout. This means that both the normal text, and the error text, is being redirected to the same place. In our case, they are both being redirected to node.log. When we read (cat) /var/log/node.log, we are therefore seeing all the standard output, and all the error output, from our program.
The EADDRINUSE error is introduced above. Attemps to fix the error might be complicated if you are on a Linux box and using Upstart. UpStart keeps your program running even after you close the command prompt. This means you can't stop the program by just typing Ctrl-C.
When using UpStart, remember to stop any running programs, such as our ExpressSend sample, like this:
sudo stop ExpressSend
You might think that you can tell if a program is running on a port by going to browser and seeing if anything comes up when you type in the address and port of your server:
That should help you tell if something is running on that port, but it might not if you tried to launch something on that port, but it failed during the launch. In particular, sometimes an attempt to start a node program with UpStart will fail:
sudo start ExpressSend
You have to check /var/log/node.log to see if there are errors. But the port can be munged up even if the program did not start correctly. To fix the problem, just tell the program to stop running. If necessary, remove the script from /etc/init. This can be important because Linux will try to rerun the script when your server restarts:
sudo rm /etc/init/ExpressSend.config
Like all powerful tools, UpStart can be a double edged sword. It gives you control over your system, but the power it grants you can also be source of trouble.
See the Library in the following project for an example of how to copy files and make directories:
JsObjects/JavaScript/Syntax/MakeDirectory.
To create a directory:
var mkdirp = require('mkdirp');
var createDirectory = function(directory) {
mkdirp(directory, function(err) {
if (err) {
console.log(err);
} else {
console.log("Created directory");
}
});
};
For mkdirp: npm install mkdirp
And to copy a file:
var copyFile = function(source, target) {
var rd = fs.createReadStream(source);
rd.on("error", function(err) {
done(err);
});
var wr = fs.createWriteStream(target);
wr.on("error", function(err) {
done(err);
});
wr.on("close", function(ex) {
done('Success: ' + ex);
});
rd.pipe(wr);
function done(msg) {
console.log(msg);
}
};
A library with a routine for ensuring a directory exists and for recursively removing directories.
var mkdirp = require('mkdirp');
var fs = require('fs');
var path = require("path");
var SimpleDir = (function() {
function SimpleDir() {
}
var makeDir = function(folder) {
mkdirp(folder);
}
// Test if a directory exists, if it does not exist create it
SimpleDir.prototype.ensureDir = function(folder) {
fs.exists(folder, existsFunc);
}
// Synchronous version of directory exists
SimpleDir.prototype.ensureDirSync = function(folder) {
currentFolder = folder;
if (fs.existsSync(folder)) {
return fs.statSync(folder);
} else {
makeDir(folder);
return 'successfully created directory';
}
};
// Remove directories recursively
// Credit to tkihira: https://gist.github.com/tkihira/2367067
SimpleDir.prototype.rmdirSync = function(dir) {
var list = fs.readdirSync(dir);
for(var i = 0; i < list.length; i++) {
var filename = path.join(dir, list[i]);
var stat = fs.statSync(filename);
if(filename == "." || filename == "..") {
// pass these files
} else if(stat.isDirectory()) {
// rmdir recursively
this.rmdirSync(filename);
} else {
// rm filename
fs.unlinkSync(filename);
}
}
fs.rmdirSync(dir);
};
return SimpleDir;
})();
exports.dirs = new SimpleDir();
You might use it in node like this:
var dirLib = require('./Library/SimpleDir');
var folder = 'foo/bar/bam';
dirLib.dirs.ensureDirSync(folder);
dirLib.dirs.rmdirSync('foo');
If you have set a global environment variable called JSOBJECTS, you can access it like this:
process.env.JSOBJECTS
Suppose you set JSOBJECTS to C:\Temp\JsObjects:
set JSOBJECTS=C:\Temp\JsObjects
Now you can access this variable inside your node code:
var jsObjects = process.env.JSOBJECTS;
You can run JSHint from node. First install JSHint:
npm install -g jshint
Now try running JSHint by typing the command jshint at the command line. If you see an error about the path, then set the following environment variable:
set HOME=%HOMEPATH%
It is a bug in JsHint that makes us do this. On Linux and the Mac you probably won't need to set the environment variable.
And finally try running jshint against one of your files:
jshint index.js
Every little bit, run:
git gc
Verify it:
C:\Git\repo>git verify-pack -verbose .git\objects\pack\pack-4beeb...idx
Run git gc per above.
Now find any huge files:
git rev-list --objects --all > bar.txt
Look for entries about your big file:
git log --pretty=oneline -- /Tech/Monkey.png
Like this:
C:\Git\repo>git log --pretty=oneline -- Tech/Graphics/HtmlSwitch/Monkey.JPG
3c6a55fa8d507e31864e5651ca1fec3a9eb2b5d1 delete big files
69d6f1ed3de5198b9595d2edae818bb00ef4444d Adding switch examples
git filter-branch --index-filter "git rm --cached --ignore-unmatch Tech/Graphics/HtmlSwitch/Monkey.JPG" -- 69d6f1^
Or:
git filter-branch --index-filter "git rm --cached --ignore-unmatch Tech/Graphics/HtmlSwitch/Monkey.JPG" -- 69d6f1^
Or:
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch Tech/Graphics/HtmlSwitch/Monkey.JPG" HEAD
At this point you ought to be able to push your changes.
Linux or Mac users, See this GIST:
##Karma and CHROME_BIN {#karmaChrome}
Here's a tip:
echo 'export CHROME_BIN="/usr/bin/chromium-browser"' >> ~/.bashrc && source ~/.bashrc
Just remember that you put the call in .bashrc in case there is some reason why you don't want that behavior later on. In other words, you have now set CHROME_BIN for all bash sessions you create until you remove that line. Frankly, that seems like a totally reasonable thing to do, but just remember that you did it, in case there is some reason you want different behavior later on. Also, we don't want to put too much in our .bashrc file or they will become too complex, and take too long to execute. This one line alone won't cause problems, of course.
I believe I had referenced this bash file:
https://github.com/charliecalvert/JsObjects/blob/master/JavaScript/Design/BridgeSailor/RunKarma.sh
It is a script, and needs to be run as such:
sh RunKarma.sh
or
chmod +x RunKarma.sh // Done once
./RunKarma.sh // Any time you want to run the script once it has the executable flag set by the chmod call.
Then when it runs, it starts a new shell, then sets the environment variable $CHROME_BIN in the new shell to /usr/bin/chromium-browser, and then executes the line karma start. The point, I assume, is that Karma needs to know where chromium is located, and it checks the $CHROME_BIN environment variable as at least one way of finding it.
If you put the line: export CHROME_BIN=/usr/bin/chromium-browser at the end of your .bashrc file, then each time you start a new bash shell, that environment variable will be set.
The line source ~/.bashrc is a way to have the .bashrc file executed without having to start a new shell. It executes the line inside the present shell, and it can change the current shell, and particularly the environment variables for the current shell.
http://superuser.com/questions/46139/what-does-source-do
The point here is this. If you run source .bashrc, or if you start a new shell the normal way, then the current shell, the one you are in, is affected. It is a way of making sure that your current shell, the one at whose command line you are currently working, has executed all the commands in .bashrc. But if you run a script with the dot (.) command, then a new shell is launched, the script is run, and when it is finished you are returned to the original shell and changes the script made to the environment are forgotten. Consider running our command:
./RunKarma.sh
It creates a new shell, sets the environment variable CHROME_BIN for that shell to /usr/bin/chromium-browser. The script then starts Karma. When you hit Control-C to end the run, then you are returned to original shell, and the CHROME_BIN environment variable is returned to the state it was in before you ran the command. Since it is unlikely that anything else but Karma cares about that environment variable, then that is a reasonable solution. You could probably put ./RunKarma in your bin directory, so that you did not have to put it inside of each project.... (Yes, I tried that, and it seems to work).
Remember that you can check the current value of CHROME_BIN by typing:
echo \$CHROME_BIN
On Windows it would be:
echo %CHROME_BIN%
Cloud 9 is an online IDE. You can find it here:
On your account page, you can link to your GitHub account.
Installing NPM modules: