Cover image by Tima Miroshnichenko
Introduction
This is a course to introduce a developer to Node.js, as it's used in the world of front-end development. It's split into chapters and will take you through the process of building a static HTML site in a modern way using the latest tools (at least at the time of writing). There'll be jokes. There'll be quizzes. There'll be a lot of code. But we're going to take it slow, OK? OK.
This is the course I wish I could have taken as a younger developer. Hopefully it's useful to someone else.
Ground rules
I think there's two kinds of developers:
- Developers who are in love with technology
- Developers who want to build things
We need both! The first kind go on to become principle developers or work in DevOps. I'm the second kind.
This means when I encounter a new technology, I'm not automatically excited by it because it means I need to take days out of my life to learn it, when I could be building stuff instead.
So my first question when someone tells me about some new tech is "yeah, but why?"
I'm going to take this approach in this guide. Because we're going to encounter a lot of technology in this guide, all stacked on top of each other like the level in Getting Over it With Bennett Foddy. And at certain points, you're probably going to feel frustrated and think that web development requires an insane footprint just to render Hello world
to a web page (this is a normal reaction).
Here's the thing: this guide assumes you already know how to do a bit of programming in JavaScript. But this guide isn't about programming, it's about engineering. We're going to be wearing hard-hats, hi-vis vests and boots with regulation toe-caps. We'll be building an application which others can contribute to easily and safely. This, for better or worse, is more or less what web development looks like in the real world.
Assumptions
You, the reader has:
- learned a bit of CSS, HTML and JavaScript
- done some tutorials and have got the hang of things
- want to build something a little more complicated (perhaps you've already given it a go, and it got unwieldy really fast)
- keep encountering code which doesn't make any sense and references to technology which you haven't learned about yet
Version control
This guide expects you to have an account with GitHub and to have the vague idea that version control is like saving stuff "with knobs on". Please go set one up! It's free and you'll likely use it professionally, so don't choose a silly username.
I also make use of GitHub Desktop right at the start. It's true that you can do everything in GitHub Desktop using the command line, but give me a break. I want to build user interfaces. Don't judge me for wanting to use them too.
IDE (Integrated Development Environment)
Developers these days generally edit their code using an IDE. This does nice stuff like syntactic highlighting and shows all your other files on the left. I use Visual Studio Code (it's friends call it "VS Code", but I'm more of a work colleague). It's fine!
VS Code lets you open a terminal (Windows sometimes calls this a "command line") and type commands right next to your code. This means your IDE mostly consists of three parts:
- Your code
- The other files and folders which make up your application
- The terminal
You can open the terminal in VS Code by going to the View
menu and selecting Terminal
.
OS
This guide is written from the assumption that you're using a fairly recent version of Microsoft™ Windows™. Sorry. It'll mostly work in other operating systems but I've not tested it. Windows™ can sometimes be the most difficult to get this tech stack working1.
I'm going to call "folders" "directories" in this guide because that's what the other operating systems call them. If you get into this habit, other developers will think you are 10% more cool.
Let's get started with Node.js!
Hold up - what even is Node?
Like me, I'm sure you've looked at something in the real world and thought "hmmm. It sure would be useful to manipulate that object's methods, properties or events using JavaScript". Objects such as your pet or spouse, for example.
A similar thought occurred to Ryan "Not Roald" Dahl in 2009. He wanted to expand what JavaScript could do.
JavaScript is what's called "sandboxed". Because JavaScript was originally designed to be downloaded from a distant website and executed in the browser, there wasn't any way to ensure if code was safe or not. So browsers ran the code inside sandboxed environments, where it was restricted from browsing your hard drive and looking for passwords. It was a bit like putting it in jail.
Ryan wanted a version of JavaScript which ran on the server and did have access to the hard drive. This means it could do useful stuff like squashing together a bunch of different CSS files into one big CSS file which is completely unreadable becausemostofthewhitespacehasbeenremoved or taking your boring old JPEG images and converting them into the new image formats such as (in ascending order of coolness) JPEG 2000, WebP or AVIF.
But Ryan was also wise enough to know what Node shouldn't do. He knew that as long as he focused on the core of the technology, all the other stuff would be written by other people and they could be equally focused in making their stuff do one thing really well.
Is Node installed?
All of the following technology is reliant on Node, so first, let's check if that's installed or not.
From the terminal in your IDE (probably VS Code), type:
node --version
or if you're short of time, type:
node -v
Press enter, obvs.
What we're doing here is checking if Node exists within your development environment or not. Right from the off, I want you to feel comfortable with the terminal throwing up weird messages at you. It's likely that some angry, red, bold text is shouting at you right now, claiming that Node isn't recognised or that you are bad at spelling. Try not to let the error messages upset you. Think of them as being shouted by a toddler who is cross because they need something to eat.
The two commands above mean the same thing, but the second one is the sort of street-slang version. We'll see this sort of thing a lot in the following lessons.
If Node is installed, then the second part of the command (--version
or -v
) will be parsed. This part is called a "flag" and works a little like an argument being passed to a function. Yes, we've called on Node, but what do we want it to do? (we want it to tell us what version it is)
Why are there two ways of saying the same thing? I guess sometimes you're in a hurry and value expediency over readability.
No Node? What now?
You can download Node as a normal installer, but where's the fun in that? Real developers use Package Managers instead.
Wait, package managers? Like the post office?
Package managers are a type of service (usually driven through the terminal) which allow you to add or remove packages to your application. They work a bit like plugins in your web browser. We'll need to install a lot of them as we go through this course.
We're going to use one package manager (winget) to install a second package manager (Node Package Manager or npm). If this seems daft to you, strap in, because there's a lot more where that came from.
winget comes built-in to Windows. Node does not. winget is only available on Windows so won't work for other operating systems. This means we need a second package manager because people who somehow manage to exist without Windows don't use winget.
So think of using winget to download npm as opening up Microsoft Edge in order to download the superior Firefox. 2
The instructions on the Node site at the time of writing look like this:
# Download and install fnm:
winget install Schniz.fnm
# Download and install Node.js:
fnm install 22
# Verify the Node.js version:
node -v # Should print "v23.7.0".
# Verify npm version:
npm -v # Should print "10.9.2".
We need to work through this one line at a time. First, type (or copy-and-paste) this into your terminal:
winget install Schniz.fnm
Next (and this doesn't seem to be covered in the instructions) you need to shut down VS Code and restart it. Not sure why this is required. Perhaps VS Code needs to sleep on it?
Let's go through this command item by item:
-
winget
- this invokes the winget software, which is built-in to Windows. Think of this as switching the terminal to winget mode, for the duration of the command. -
install
- this is like a function call to the install part of winget -
Schniz.fnm
- this requests that we install the Fast Node Manager package from the winget package library.Schniz
is the name of the user who wrote this package.fnm
is the name of the package. Once we get to Node Package Manager, it works in a slightly simpler way.
Fast Node Manager (fnm)
The first thing we did - before installing Node itself even - was install something called fnm or Fast Node Manager. This is a much bigger deal that you might think.
Fast Node Manager lets us do a whole different bunch of things:
- Download old versions of Node
- Download a newer version of Node which has just come out
- Switch between different versions of Node
- Automatically use a particular version of Node for one particular project
- Give these different versions of Node nicknames which only we understand (just go with it, OK?)
Why is this necessary?
Node is under active development. It's moved up three versions since I started writing this course and I expect it to release a new version by the time you've finished reading this sentence. Sometimes, these new versions break something in the older versions. Or we might use a package which relies on a technique which has changed in later versions of Node. This means we might need to run different versions of Node for different projects.
Fast Node Manager lets us switch between them quickly. It's written in Rust which is a very cool language I know nothing about other than it runs really fast and is used for mission-critical systems.
Let's continue installing Node!
We can use Fast Node Manager to install the current version of Node. But the "current version" comes in two flavours:
- LTS ("Long Term Support" - not short for "latest", as I originally thought)
- Current (under active development)
The Long Term Support edition (which is one version number behind current) is the "stable" release. It's been heavily tested and is only changed in order to address security holes or bugs. This is the version Node suggests you use on production environments (that's what web developers call the live web server).
The current edition has all the new features and is a little more experimental. It's useful for authors of packages (which we'll come to eventually) to check if they still work when the new version comes out.
Let's be conservative and install the LTS version of Node, which, at the time of writing, is 22. But just in case I forget to update this every six months for the rest of my life, have a quick check on the Node download page. In the terminal, type (or paste):
fnm use --install-if-missing 22
Let's break down this line:
-
fnm
- calls Fast Node Manager -
use
- invokes theuse
function, which is part offnm
. This tellsfnm
that we want to change the current version of Node to a different one. -
--install-if-missing
- this tells fnm that if it doesn't find version 22 already installed, it should download and install it -
22
- specifies that version 22 of Node should be installed. fnm won't install the version number 22.0.0. Instead, it will look for the very latest version of release 22 which has come out. Reminder: if you're reading this in the future (the only possible outcome, due to the linear nature of time), the number on the Node site might be bigger now. I think this is due to inflation.
Finally, we get to check which version of Node we have installed, which is where we got into this whole sorry mess in the first place. We do this with the commands:
node -v
... for Node and:
npm -v
... for Node Package Manager.
Great work, team!
Configuring the environmental variables
For reasons the authors of Fast Node Manager are keeping a closely guarded secret, we now need to configure some environmental variables. This used to be part of the install process of Node but with the latest versions, they've removed it. Perhaps someone decided the learning curve was looking a little shallow.
You'll encounter environmental variables during your career but in this context, they're basically the settings for Node. But before I get into how to change them, I'll need to introduce you to PowerShell. We've talked about the terminal and how that's what the cool people call the command prompt. But Windows these days comes with a sexed-up version of the command prompt called PowerShell. It's what's running inside VS Code when you open the terminal.
We can create a profile for PowerShell by typing this into the terminal:
if (-not (Test-Path $profile)) { New-Item $profile -Force }
This is an if
statement which tests if PowerShell has a profile or not, and creates one if it doesn't. Whichever version of reality you live in, after you've run this, a profile will exist for PowerShell. You can open this profile by typing this into the terminal:
Invoke-Item $profile
I like the idea of Invoke-Item
. Makes me feel like a wizard. An empty file will probably appear. Not in VS Code, but in something horrible like Nodepad. Add the following line to it:
fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression
Save the file and close it. Close, then re-open VS Code for good measure. I'm not 100% sure this is required, but we need PowerShell to load its environmental variables from scratch and it seems sensible. Sometimes, web development is indistinguishable from superstition.
Here's what I think is going on with the line we added to the PowerShell profile:
-
fnm
- now we've installed Fast Node Manager, we're calling it for the first time, which is a little like switching the terminal to fnm mode. -
env
- this sets a new environmental variable -
--use-on-cd
- hey, I remember this! This is a flag! This particular flag allows fnm to switch Node versions on the fly. For example, let's say you need to edit a Node project which requires an antique version of Node. fnm will find a configuration file in the root of the project and then use an older matching version of Node. -
--shell
- a "shell" is another word for "terminal". Or command prompt. This flag allows us to choose a shell to assign this environmental variable to, even though it appears inside the profile file for PowerShell. -
poweshell
- this confirms that the shell we want to assign this environmental variable to is PowerShell. -
| Out-String | Invoke-Expression
- Full disclosure: I can't find either of these commands in the documentation. Let's spin this as a learning experience. Sometimes, we have to use commands we don't fully understand and just have faith in how they work. (Did that sound convincing?)
Updating Node
Wait, we've just installed Node and we already need to know how to update it? Yup. The world of Node moves very quickly but by default, Node (or more accurately, fnm) keeps us locked into the version we first installed. This is to ensure that any breaking changes introduced with future versions won't break old code.
fnm lets us juggle multiple version of Node which we can swap between on a whim. Just for fun (YMMV), let's get fnm to list all the versions of Node it knows about. In the terminal, type:
fnm ls-remote
ls
is short for list
. So this asks fnm for a list of all the different Node versions it's possible to use. Let's install whatever the stable version is this week. In the terminal, type:
fnm install -lts
You might recognise the -lts
flag from earlier - it stands for "long term support". If Node has moved up a level or two since you last installed it, this will automatically pull down the new version. However, we won't automatically use it. Let's see what versions we have locally installed. In a terminal, type:
fnm ls
My console shows this:
* v22.13.1 lts-latest
* v23.7.0 default
* system
The line highlighted in blue in your terminal will represent the version of Node which is currently in use. In order to switch to a different one, you can either use the version number like this:
fnm use 22.13.1
... or the alias (I called it a "nickname" earlier), like this:
fnm use lts-latest
List off your Node versions again and the blue highlight should have moved to lts-latest
. You can double-check this by typing:
node -v
Uninstalling old versions of Node
If you have a version of Node you're no longer using and which is just cluttering up your hard drive, you can remove it using the uninstall
command. It works like this:
fnm uninstall 20
Updating Fast Node Manager itself
According to the GitHub page, updating fnm should be as easy as typing this into the terminal:
curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell
I couldn't get that to work but there's an easier way: you can download the code directly from the releases page and install it like a normal Windows application (the one you want is probably fnm-windows.zip).
Summary
That was quite a lot to take in, but we're still laying the (metaphorical) foundations for the beautiful website we're going to build. Where this metaphor breaks down is that we tend to think of foundations as being stable. And Node is under active development which means things change all the time.
Most of the time, this won't impact us. We can update to the latest version of Node and our code will sit on top quite happily.
Why do things change so much?
New exploits and vulnerabilities are constantly being found in web servers and Windows itself. It's why your computer keeps nagging you to restart every so often. But the good news is this: nothing we write in Node will end up on a web server. All of this code is in service of generating nice, comfortable, flat HTML pages (at least on this course). So even if we do encounter terrible security holes (and we will), it won't harm the site you build. But we'll cover that as we go.
Quiz
-
Where as in other operating systems, you can nest quotation marks like this: "Here is the outer quote 'here is the inner quote' and we are back outside again", in Windows we can't use single quotes and we need to "escape" the inner quotes. We'll be covering this in more detail later. ↩
-
It hurts to make this joke because I prefer Edge to Chrome. ↩