Chapter 2. Getting Started with Node
If you donât have any experience with Node, this chapter is for you. Understanding Express and its usefulness requires a basic understanding of Node. If you already have experience building web apps with Node, feel free to skip this chapter. In this chapter, we will be building a very minimal web server with Node; in the next chapter, we will see how to do the same thing with Express.
Getting Node
Getting Node installed on your system couldnât be easier. The Node team has gone to great lengths to make sure the installation process is simple and straightforward on all major platforms.
The installation is so simple, as a matter of fact, that it can be summed up in three simple steps:
-
Go to the Node home page.
-
Click the big green button that says INSTALL.
-
Follow instructions.
For Windows and OS X, an installer will be downloaded that walks you through the process. For Linux, you will probably be up and running more quickly if you use a package manager.
Caution
If youâre a Linux user and you do want to use a package manager, make sure you follow the instructions in the aforementioned web page. Many Linux distributions will install an extremely old version of Node if you donât add the appropriate package repository.
You can also download a standalone installer, which can be helpful if you are distributing Node to your organization.
If you have trouble building Node, or for some reason you would like to build Node from scratch, please refer to the official installation instructions.
Using the Terminal
Iâm an unrepentant fan of the power and productivity of using a terminal (also called a âconsoleâ or âcommand promptâ). Throughout this book, all examples will assume youâre using a terminal. If youâre not friends with your terminal, I highly recommend you spend some time familiarizing yourself with your terminal of choice. Many of the utilities in this book have corresponding GUI interfaces, so if youâre dead set against using a terminal, you have options, but you will have to find your own way.
If youâre on OS X or Linux, you have a wealth of venerable shells (the terminal command interpreter) to choose from. The most popular by far is bash, though zsh has its adherents. The main reason I gravitate toward bash (other than long familiarity) is ubiquity. Sit down in front of any Unix-based computer, and 99% of the time, the default shell will be bash.
If youâre a Windows user, things arenât quite so rosy. Microsoft has never been particularly interested in providing a pleasant terminal experience, so youâll have to do a little more work. Git helpfully includes a âGit bashâ shell, which provides a Unix-like terminal experience (it only has a small subset of the normally available Unix command-line utilities, but itâs a useful subset). While Git bash provides you with a minimal bash shell, itâs still using the built-in Windows console application, which leads to an exercise in frustration (even simple functionality like resizing a console window, selecting text, cutting, and pasting is unintuitive and awkward). For this reason, I recommend installing a more sophisticated terminal such as Console2 or ConEmu. For Windows power usersâespecially for .NET developers or for hardcore Windows systems or network administratorsâthere is another option: Microsoftâs own PowerShell. PowerShell lives up to its name: people do remarkable things with it, and a skilled PowerShell user could give a Unix command-line guru a run for their money. However, if you move between OS X/Linux and Windows, I still recommend sticking with Git bash for the consistency it provides.
Another option, if youâre a Windows user, is virtualization. With the power and architecture of modern computers, the performance of virtual machines (VMs) is practically indistinguishable from actual machines. Iâve had great luck with Oracleâs free VirtualBox, and Windows 8 offers VM support built in. With cloud-based file storage, such as Dropbox, and the easy bridging of VM storage to host storage, virtualizing is looking more attractive all the time. Instead of using Git bash as a bandage on Windowsâs lackluster console support, consider using a Linux VM for development. If you find the UI isnât as smooth as you would like, you could use a terminal application, such as PuTTY, which is what I often do.
Finally, no matter what sytem youâre on, thereâs the excellent Codio. Codio is a website that will spin up a new Linux instance for every project you have and provide an IDE and command line, with Node already installed. Itâs extremely easy to use and is a great way to get started very quickly with Node.
Tip
When you specify the -g
(global) option when installing npm packages, they are installed in a subdirectory of your Windows home directory. Iâve found that a lot of these packages donât perform well if there are spaces in your username (my username used to be âEthan Brown,â and now itâs âethan.brownâ). For your sanity, I recommend choosing a Windows username without a space in it. If you already have such a username, itâs advisable to create a new user, and then transfer your files over to the new account: trying to rename your Windows home directory is possible but fraught with danger.
Once youâve settled on a shell that makes you happy, I recommend you spend some time getting to know the basics. There are many wonderful tutorials on the Internet, and youâll save yourself a lot of headaches later on by learning a little now. At minimum, you should know how to navigate directories; copy, move, and delete files; and break out of a command-line program (usually Ctrl-C). If you want to become a terminal ninja, I encourage you to learn how to search for text in files, search for files and directories, chain commands together (the old âUnix philosophyâ), and redirect output.
Caution
On many Unix-like systems, Ctrl-S has a special meaning: it will âfreezeâ the terminal (this was once used to pause output quickly scrolling past). Since this is such a common shortcut for Save, itâs very easy to unthinkingly press, which leads to a very confusing situation for most people (this happens to me more often than I care to admit). To unfreeze the terminal, simply hit Ctrl-Q. So if youâre ever confounded by a terminal that seems to have suddenly frozen, try pressing Ctrl-Q and see if it releases it.
Editors
Few topics inspire such heated debate among programmers as the choice of editors, and for good reason: the editor is your primary tool. My editor of choice is vi1 (or an editor that has a vi mode). vi isnât for everyone (my coworkers constantly roll their eyes at me when I tell them how easy it would be to do what theyâre doing in vi), but finding a powerful editor and learning to use it will significantly increase your productivity and, dare I say it, enjoyment. One of the reasons I particularly like vi (though hardly the most important reason) is that like bash, it is ubiquitous. If you have access to a Unix system (Cygwin included), vi is there for you. Many popular editors (even Microsoft Visual Studio!) have a vi mode. Once you get used to it, itâs hard to imagine using anything else. vi is a hard road at first, but the payoff is worth it.
If, like me, you see the value in being familiar with an editor thatâs available anywhere, your other option is Emacs. Emacs and I have never quite gotten on (and usually youâre either an Emacs person or a vi person), but I absolutely respect the power and flexibility that Emacs provides. If viâs modal editing approach isnât for you, I would encourage you to look into Emacs.
While knowing a console editor (like vi or Emacs) can come in incredibly handy, you may still want a more modern editor. Some of my frontend colleagues swear by Coda, and I trust their opinion. Unfortunately, Coda is available only on OS X. Sublime Text is a modern and powerful editor that also has an excellent vi mode, and itâs available on Windows, Linux, and OS X.
On Windows, there are some fine free options out there. TextPad and Notepad++ both have their supporters. Theyâre both capable editors, and you canât beat the price. If youâre a Windows user, donât overlook Visual Studio as a JavaScript editor: itâs remarkably capable, and has one of the best JavaScript autocomplete engines of any editor. You can download Visual Studio Express from Microsoft for free.
npm
npm is the ubiquitous package manager for Node packages (and is how weâll get and install Express). In the wry tradition of PHP, GNU, WINE, and others, ânpmâ is not an acronym (which is why it isnât capitalized); rather, it is a recursive abbreviation for ânpm is not an acronym.â
Broadly speaking, a package managerâs two primary responsibilities are installing packages and managing dependencies. npm is a fast, capable, and painless package manager, which I feel is in large part responsible for the rapid growth and diversity of the Node ecosystem.
npm is installed when you install Node, so if you followed the steps listed earlier, youâve already got it. So letâs get to work!
The primary command youâll be using with npm (unsurprisingly), is install
. For example, to install Grunt (a popular JavaScript task runner), you would issue the following command (on the console):
npm install -g grunt-cli
The -g
flag tells npm to install the package globally, meaning itâs available globally on the system. This distinction will become clearer when we cover the package.json files. For now, the rule of thumb is that JavaScript utilities (like Grunt) will generally be installed globally, whereas packages that are specific to your web app or project will not.
Note
Unlike languages like Pythonâwhich underwent a major language change from 2.0 to 3.0, necessitating a way to easily switch between different environmentsâthe Node platform is new enough that it is likely that you should always be running the latest version of Node. However, if you do find yourself needing to support multiple version of Node, there is a project, nvm, that allows you to switch environments.
A Simple Web Server with Node
If youâve ever built a static HTML website before, or are coming from a PHP or ASP background, youâre probably used to the idea of the web server (Apache or IIS, for example) serving your static files so that a browser can view them over the network. For example, if you create the file about.html, and put it in the proper directory, you can then navigate to http://localhost/about.html. Depending on your web server configuration, you might even be able to omit the .html, but the relationship between URL and filename is clear: the web server simply knows where the file is on the computer, and serves it to the browser.
Note
localhost, as the name implies, refers to the computer youâre on. This is a common alias for the IPv4 loopback address 127.0.0.1, or the IPv6 loopback address ::1. You will often see 127.0.0.1 used instead, but I will be using localhost in this book. If youâre using a remote computer (using SSH, for example), keep in mind that browsing to localhost will not connect to that computer.
Node offers a different paradigm than that of a traditional web server: the app that you write is the web server. Node simply provides the framework for you to build a web server.
âBut I donât want to write a web server,â you might be saying! Itâs a natural response: you want to be writing an app, not a web server. However, Node makes the business of writing this web server a simple affair (just a few lines, even) and the control you gain over your application in return is more than worth it.
So letâs get to it. Youâve installed Node, youâve made friends with the terminal, and now youâre ready to go.
Hello World
Iâve always found it unfortunate that the canonical introductory programming example is the uninspired message âHello World.â However, it seems almost sacrilegious at this point to fly in the face of such ponderous tradition, so weâll start there, and then move on to something more interesting.
In your favorite editor, create a file called helloWorld.js:
var
http
=
require
(
'http'
);
http
.
createServer
(
function
(
req
,
res
){
res
.
writeHead
(
200
,
{
'Content-Type'
:
'text/plain'
});
res
.
end
(
'Hello world!'
);
}).
listen
(
3000
);
console
.
log
(
'Server started on localhost:3000; press Ctrl-C to terminate....'
);
Make sure you are in the same directory as helloWorld.js, and type node helloWorld.js
. Then open up a browser and navigate to http://localhost:3000, and voilà ! Your first web server. This particular one doesnât serve HTML; rather, it just transmits the message âHello world!â in plaintext to your browser. If you want, you can experiment with sending HTML instead: just change text/plain
to text/html
and change 'Hello world!'
to a string containing valid HTML. I didnât demonstrate that, because I try to avoid writing HTML inside JavaScript for reasons that will be discussed in more detail in [link unavailable].
Event-Driven Programming
The core philosophy behind Node is that of event-driven programming. What that means for you, the programmer, is that you have to understand what events are available to you and how to respond to them. Many people are introduced to event-driven programming by implementing a user interface: the user clicks on something, and you handle the âclick event.â Itâs a good metaphor, because itâs understood that the programmer has no control over when, or if, the user is going to click something, so event-driven programming is really quite intuitive. It can be a little harder to make the conceptual leap to responding to events on the server, but the principle is the same.
In the previous code example, the event is implicit: the event thatâs being handled is an HTTP request. The http.createServer
method takes a function as an argument; that function will be invoked every time an HTTP request is made. Our simple program just sets the content type to plaintext and sends the string âHello world!â
Routing
Routing refers to the mechanism for serving the client the content it has asked for. For web-based client/server applications, the client specifies the desired content in the URL; specifically, the path and querystring (the parts of a URL will be discussed in more detail in [link unavailable]).
Letâs expand our âHello world!â example to do something more interesting. Letâs serve a really minimal website consisting of a home page, an About page, and a Not Found page. For now, weâll stick with our previous example and just serve plaintext instead of HTML:
var
http
=
require
(
'http'
);
http
.
createServer
(
function
(
req
,
res
){
// normalize url by removing querystring, optional
// trailing slash, and making it lowercase
var
path
=
req
.
url
.
replace
(
/\/?(?:\?.*)?$/
,
''
).
toLowerCase
();
switch
(
path
)
{
case
''
:
res
.
writeHead
(
200
,
{
'Content-Type'
:
'text/plain'
});
res
.
end
(
'Homepage'
);
break
;
case
'/about'
:
res
.
writeHead
(
200
,
{
'Content-Type'
:
'text/plain'
});
res
.
end
(
'About'
);
break
;
default
:
res
.
writeHead
(
404
,
{
'Content-Type'
:
'text/plain'
});
res
.
end
(
'Not Found'
);
break
;
}
}).
listen
(
3000
);
console
.
log
(
'Server started on localhost:3000; press Ctrl-C to terminate....'
);
If you run this, youâll find you can now browse to the home page (http://localhost:3000) and the About page (http://localhost:3000/about). Any querystrings will be ignored (so http://localhost:3000/?foo=bar will serve the home page), and any other URL (http://localhost:3000/foo) will serve the Not Found page.
Serving Static Resources
Now that weâve got some simple routing working, letâs serve some real HTML and a logo image. These are called âstatic resourcesâ because they donât change (as opposed to, for example, a stock ticker: every time you reload the page, the stock prices change).
Tip
Serving static resources with Node is suitable for development and small projects, but for larger projects, you will probably want to use a proxy server such as Nginx or a CDN to serve static resources. See [link unavailable] for more information.
If youâve worked with Apache or IIS, youâre probably used to just creating an HTML file, navigating to it, and having it delivered to the browser automatically. Node doesnât work like that: weâre going to have to do the work of opening the file, reading it, and then sending its contents along to the browser. So letâs create a directory in our project called public (why we donât call it static will become evident in the next chapter). In that directory, weâll create home.html, about.html, 404.html, a subdirectory called img, and an image called img/logo.jpg. Iâll leave that up to you: if youâre reading this book, you probably know how to write an HTML file and find an image. In your HTML files, reference the logo thusly: <img src="/img/logo.jpg" alt="logo">
.
Now modify helloWorld.js:
var
http
=
require
(
'http'
),
fs
=
require
(
'fs'
);
function
serveStaticFile
(
res
,
path
,
contentType
,
responseCode
)
{
if
(
!
responseCode
)
responseCode
=
200
;
fs
.
readFile
(
__dirname
+
path
,
function
(
err
,
data
)
{
if
(
err
)
{
res
.
writeHead
(
500
,
{
'Content-Type'
:
'text/plain'
});
res
.
end
(
'500 - Internal Error'
);
}
else
{
res
.
writeHead
(
responseCode
,
{
'Content-Type'
:
contentType
});
res
.
end
(
data
);
}
});
}
http
.
createServer
(
function
(
req
,
res
){
// normalize url by removing querystring, optional
// trailing slash, and making lowercase
var
path
=
req
.
url
.
replace
(
/\/?(?:\?.*)?$/
,
''
)
.
toLowerCase
();
switch
(
path
)
{
case
''
:
serveStaticFile
(
res
,
'/public/home.html'
,
'text/html'
);
break
;
case
'/about'
:
serveStaticFile
(
res
,
'/public/about.html'
,
'text/html'
);
break
;
case
'/img/logo.jpg'
:
serveStaticFile
(
res
,
'/public/img/logo.jpg'
,
'image/jpeg'
);
break
;
default
:
serveStaticFile
(
res
,
'/public/404.html'
,
'text/html'
,
404
);
break
;
}
}).
listen
(
3000
);
console
.
log
(
'Server started on localhost:3000; press Ctrl-C to terminate....'
);
Note
In this example, weâre being pretty unimaginative with our routing. If you navigate to http://localhost:3000/about, the public/about.html file is served. You could change the route to be anything you want, and change the file to be anything you want. For example, if you had a different About page for each day of the week, you could have files public/about_mon.html, public/about_tue.html, and so on, and provide logic in your routing to serve the appropriate page when the user navigates to http://localhost:3000/about.
Note weâve created a helper function, serveStaticFile
, thatâs doing the bulk of the work. fs.readFile
is an asynchronous method for reading files. There is a synchronous version of that function, fs.readFileSync
, but the sooner you start thinking asynchronously, the better. The function is simple: it calls fs.readFile
to read the contents of the specified file. fs.readFile
executes the callback function when the file has been read; if the file didnât exist or there were permissions issues reading the file, the err
variable is set, and the function returns an HTTP status code of 500 indicating a server error. If the file is read successfully, the file is sent to the client with the specified response code and content type. Response codes will be discussed in more detail in [link unavailable].
Tip
__dirname
will resolve to the directory the executing script resides in. So if your script resides in /home/sites/app.js, __dirname
will resolve to /home/sites. Itâs a good idea to use this handy global whenever possible. Failing to do so can cause hard-to-diagnose errors if you run your app from a different directory.
Onward to Express
So far, Node probably doesnât seem that impressive to you. Weâve basically replicated what Apache or IIS do for you automatically, but now you have some insight into how Node does things and how much control you have. We havenât done anything particularly impressive, but you can see how we could use this as a jumping-off point to do more sophisticated things. If we continued down this road, writing more and more sophisticated Node applications, you might very well end up with something that resembles Expressâ¦.
Fortunately, we donât have to: Express already exists, and it saves you from implementing a lot of time-consuming infrastructure. So now that weâve gotten a little Node experience under our belt, weâre ready to jump into learning Express.
1 These days, vi is essentially synonymous with vim (vi improved). On most systems, vi is aliased to vim, but I usually type vim to make sure Iâm using vim.
Get Modern JavaScript now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.