Start an Express Server

In the last article, we installed Express and configured a gitignore file. This time around, let's write the boilerplate server code and start the server. I've posted some additional resources in the "Going further" section if you'd like to go into more depth.

Create server

Open VS Code and the integrated Terminal

View > Terminal

Next, enter the following to create a server JavaScript file.

touch server.js

Let's start building our server based on the Express documentation.

https://expressjs.com/en/starter/hello-world.html

Add the following code to server.js.

const express = require('express');
 
const app = express();
const port = 3000;

app.get('/', (req, res) => res.send('Express server running'));

app.listen(port, () => console.log(`Listening on port ${port}`));

The app responds with "Express server running" for requests to the root URL (/) or route. For every other path, it will respond with a 404 Not Found.

Start the server

The usual way to run a Node.js program is to run the node command and pass the file's name you want to execute.

https://nodejs.dev/learn/run-nodejs-scripts-from-the-command-line

To run the server type node server.js.

You can visit http://localhost:3000 in a web browser to see the message, "Express server running."

"Listening on port 3000" appears in the Terminal.

To exit use: Control ⌃C (control + c)

Of course, starting and stopping the server every time you make a change is tedious. So it would be nice to automate the restart, and that's what nodemon does.

https://nodemon.io

Nodemon

In the previous article, we installed nodemon as a developer dependency. Unless you install nodemon globally, the following command results in an error.

nodemon server.js

Result:

zsh: command not found: nodemon

So, we can either install nodemon globally or use the NPX command instead.

https://github.com/remy/nodemon#nodemon

NPX

"For the past couple of years, the npm ecosystem has been moving more and more towards installing tools as project-local devDependencies, instead of requiring users to install them globally."

https://blog.npmjs.org/post/162869356040/introducing-npx-an-npm-package-runner

"npx lets you run code built with Node.js and published through the npm registry."

"Node.js developers used to publish most of the executable commands as global packages, in order for them to be in the path and executable immediately."

"This was a pain because you could not really install different versions of the same command."

"Running npx commandname automatically finds the correct reference of the command inside the node_modules folder of a project, without needing to know the exact path, and without requiring the package to be installed globally and in the user's path."

https://nodejs.dev/learn/the-npx-nodejs-package-runner

In the Terminal, try the following.

npx nodemon server.js

Result:

[nodemon] 2.0.12
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node server.js`
Listening on port 3000

To exit use: Control ⌃C (control + c)

NPM scripts

We can define a shortcut command for starting the server using NPM scripts.

What happens if you run the command npm start or npm run start?

Result:

> backend@1.0.0 start
> node server.js

Listening on port 3000

To exit use: Control ⌃C (control + c)

"If there is a server.js file in the root of your package, then npm will default the start command to node server.js."

https://docs.npmjs.com/cli/v7/using-npm/scripts#npm-start

"In your package.json file, you can specify a scripts property that essentially creates aliases for your commands that npm can run."

https://www.smashingmagazine.com/2016/01/issue-with-global-node-npm-packages/

Take a note of the following code in package.json.

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }

Modify the scripts section of package.json.

  "scripts": {
    "start": "npx nodemon server.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  }

Now we have a shortcut command to run nodemon.

Try npm start or npm run start again. Here's the result.

> backend@1.0.0 start
> npx nodemon server.js

[nodemon] 2.0.12
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node server.js`
Listening on port 3000

To exit use: Control ⌃C (control + c)

Going further

These sections go into detail about what's happening in the server.js code.

Modules

"When Node.js was invented, modules and code encapsulation were high on the priority list. The creators of Node.js were keen for it to not suffer the same fate as the browser by having a big, dangerous global scope. So they implemented Node.js with a module specification called CommonJS (which is where you get the module exports and require syntax from)."

https://stackify.com/node-js-module-exports/

Why your ES6+ syntax doesn't work in Node.js and how to fix it

"As our application grows bigger, we want to split it into multiple files, so called "modules". A module may contain a class or a library of functions for a specific purpose."

"The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js."

https://javascript.info/modules-intro

"CommonJS defines a module format. Unfortunately, it was defined without giving browsers equal footing to other JavaScript environments. Because of that, there are CommonJS spec proposals for Transport formats and an asynchronous require."

https://requirejs.org/docs/commonjs.html

Require

"In the Node.js module system, each file is treated as a separate module."

https://nodejs.org/dist/latest-v16.x/docs/api/module.html

"Require is an import of certain files or packages used with NodeJS's modules. It is used to improve code structure and uses."

https://devtut.github.io/nodejs/require.html#beginning-require-use-with-a-function-and-file

Use strict

"Modern JavaScript supports "classes" and "modules" – advanced language structures (we'll surely get to them), that enable use strict automatically. So we don't need to add the "use strict" directive, if we use them."

"So, for now "use strict"; is a welcome guest at the top of your scripts. Later, when your code is all in classes and modules, you may omit it."

https://javascript.info/strict-mode

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

Export

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

Import

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

// const express = require('express');
import express from 'express';

In server.js, if you change the require statement to an import statement, you should see the following error.

(node:5578) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
Desktop/backend/server.js:2
import express from 'express';
^^^^^^

SyntaxError: Cannot use import statement outside a module
[nodemon] app crashed - waiting for file changes before starting...

When you add the following line to package.json, it works!

"type": "module",

However, require statements won't work any longer.

const express = require('express');
^

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and 'Desktop/backend/package.json' contains "type": "module".
To treat it as a CommonJS script, rename it to use the '.cjs' file extension.

Variables

https://javascript.info/variables

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables

Functions

https://javascript.info/function-basics

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions

https://javascript.info/arrow-functions-basics

Template literals

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

Console

https://developer.mozilla.org/en-US/docs/Web/API/console/log

Application

https://expressjs.com/en/4x/api.html#app

Get

https://expressjs.com/en/4x/api.html#app.get

Request

"The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on."

https://expressjs.com/en/4x/api.html#req

Response

"The res object represents the HTTP response that an Express app sends when it gets an HTTP request."

https://expressjs.com/en/4x/api.html#res

Listen

http://expressjs.com/en/5x/api.html#app.listen

Client-server

https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps

https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview

Express

"The Express philosophy is to provide small, robust tooling for HTTP servers, making it a great solution for single page applications, websites, hybrids, or public HTTP APIs."

https://github.com/expressjs/express

https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs

Summary

In this article, we created a server file and added Express boilerplate code. Then, we started the server in a few different ways and resolved the nodemon local install issue. Next, hopefully, you dove into the complex history of modules in Javascript and the additional resources that add insight to the Express server code.