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.
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.