Creating NodeJS project
In this post we are going to cover how to create a proper project with npm init
and how to use npm packages.
Creating a project
Until now we have created some .js
files and our server does work but it is missing some important files and configurations. We are going to fix that now by going into our folder where our files are and just run the command npm init -y
Make sure that NodeJS (and with that, NPM) are installed before running above command. You can check that npm is installed by running npm -v
. You should get version number.
After that, a package.json
file will be created with content similar to this:
{
"name": "myproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Most of it is self explanatory so let’s go through some parts that are not.
main
- this is the main point of entry for the project, you can set it to any file.
scripts
- this allows you to run any defined set of commands as a script. You can have as many as you want( we’ll create our own later).
Why is it important
package.json
holds metadata configuration of your project. But probably the most important thing is that without it you can’t install npm packages
as it is used to store definitions of those packages(dependencies).
Installing our first package
Now we are going to install our first dependency that will allow us to be able to read environment variables
that are basically just values stored in a file .env
(.
is very important as a prefix of the file). This file needs to be in the same folder as other files otherwise it will not work.
So first we want to create that file and inside we want to put:
PORT=3000
Now we can run the command to install our package npm install dotenv
. After this, dependencies
object will be added to our package.json
and it will look similar to this:
{
"name": "myproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^16.3.1"
}
}
dependencies
- this hold all of our installed packages that are used in production and their versions. There is also devDependencies
that we will add later. These are used for installed packages that are used in development and testing and are not installed for production.
You will also see file package-lock.json
that keeps track of dependency trees for all dependencies you installed. You don’t have to worry much about this file. There is also a folder node_modules
which holds all installed packages.
The version installed for me is 16.3.1
and that might not be the case for you because as times goes on developers of these packages release new versions and depending when you install it you will probably get different/newer version.
What does ^16.3.1
mean?
^
- allows the project to automatically update dependency to future minor/patch versions, without incrementing the major version.
Sometimes you’ll see ~
that does the same thing but only updates minor version and not major or patch versions. There are a few more values available.
16
- represents the major
version of the package. New major versions almost always have changes that break backward compatibility. This should only be updated manually.
3
- minor
version. Backward compatible new features. This can be updated automatically.
1
- patch
version. Backward compatible bug fixes. This can be updated automatically.
More about it here.
Changing our code
Now that our package is installed and our .env
file exists and has a variable inside we can change our Ignitor.js
.
Ignitor.js
const http = require("http");
const Route = require("./Route.js");
require("dotenv").config();
class Ignitor {
#instance;
#route;
constructor() {
if (this.#instance) {
throw new Error("New instance cannot be created.");
}
this.#instance = this;
}
setup() {
this.#route = Route;
}
start() {
this.setup();
http
.createServer((req, res) => {
res.setHeader("Content-Type", "application/json");
return this.#route.handle({ req, res });
})
.listen(process.env.PORT);
}
}
module.exports = new Ignitor();
We are first importing our package with require('dotenv').config();
. This loads our key-value pairs from .env
into process.env
.
That allows us to remove PORT
constant from our code and instead use .listen(process.env.PORT);
Now if we run node index.js
everything works as before.
Creating our script
To make things easier for us, we are going to create our own script to run node index.js
and its just updating our package.json
package.json
{
"name": "myproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^16.3.1"
}
}
Now we only need to run npm run start
and it will actually run our node index.js
as defined in the file.
Folder structure
index.js
routes.js
Route.js
Ignitor.js
package.json
package-lock.json
.env
node_modules(folder)