I present to your attention a selection of ten popular npm packages with examples of their use and alternative solutions.
It assumes that you are very familiar with JavaScript and in particular Node.js.
This part presents the following packages:
chalk
Weekly downloads: 58 million.
Purpose: formatting messages displayed in the terminal.
Usage example.
Install the package: yarn add chalk or npm i chalk.
Create chalk.js file:
const chalk = require("chalk");
const log = console.log;
log(
chalk.red(" \n") +
chalk.green(" \n") +
chalk.blue(" ")
);
//
const os = require("os");
log(`
Total memory: ${chalk.blue(os.totalmem())} bytes
Free memory: ${chalk.green(os.freemem())} bytes
Memory used: ${chalk.red(os.totalmem() - os.freemem())} bytes
`);
//
const v8 = require("v8");
const {
total_heap_size: total,
used_heap_size: used,
heap_size_limit: limit,
} = v8.getHeapStatistics();
log(chalk`
Heap Size Limit: {rgb(0, 0, 255) ${limit}}
Total Heap Size: {hex('#008000') ${total}}
Used Heap Size: {red ${used}}
`);
Run the script: node chalk.js.
Alternative: escape sequences:
console.log(
"[31m%s[0m[32m%s[0m[34m%s[0m",
" \n",
" \n",
" "
);
progress
Weekly downloads: 13 million.
Purpose: "terminal" progress indicator (ASCII characters).
Usage example.
Install the package: yarn add progress.
Create progress.js file:
const ProgressBar = require("progress");
const bar = new ProgressBar(":bar", { total: 10 });
const timer = setInterval(() => {
bar.tick();
if (bar.complete) {
console.log("\n");
clearInterval(timer);
}
}, 200);
Run the script: node progress.js
One more example:
const ProgressBar = require("progress");
const https = require("https");
const req = https.request({
host: "example.com",
port: 443,
path: "/filename.ext",
});
req.on("response", (res) => {
const len = parseInt(res.headers["content-length"], 10);
console.log();
const bar = new ProgressBar(
" [:bar] :rate/bps :percent :etas",
{
complete: "=",
incomplete: " ",
width: 20,
total: len,
}
);
res.on("data", (chunk) => {
bar.tick(chunk.length);
});
res.on("end", () => {
console.log("\n");
});
});
req.end();
minimist
Weekly downloads: 35 million.
Purpose: parsing the arguments passed through the terminal.
Usage example.
Install the package: yarn add minimist.
Create minimist.js file:
const args = require("minimist")(process.argv.slice(2));
console.log(args);
console.log(args._);
console.log(args.a);
Run the script: node script.js foo bar baz -x 1 -y2 --z = 3 -a
fs-extra
Weekly downloads: 32 million.
Purpose: additional methods for working with the file system (extension fs).
Basic methods:
- copy - copy files
- emptyDir - empty directory. If the directory does not exist, it is created
- ensureFile - Determining if a file exists. If a request is made to create a file in directories that do not exist, they are created
- ensureDir is the same for a directory. Aliases - mkdirs, mkdirp
- move - move a file or directory
- outputFile - similar to fs.writeFile, except that if missing, a parent directory is created
- outputJson - similar to fs.writeJson, except that if missing, a parent directory is created
- readJson - read a JSON file and convert it to an object
- remove - remove a file or directory
- writeJson - writing an object to a JSON file
The given methods are asynchronous, there are their synchronous counterparts (with the "Sync" prefix).
Methods can be used with callbacks, promises, and async / await. I will use promises.
const fs = require("fs-extra");
// copy
fs.copy("/old-file", "/dir/new-file")
.then(() => {
console.log("!");
})
.catch((err) => {
console.error(err);
});
// emptyDir
fs.emptyDir("/some/empty/dir")
.then(() => {
console.log("!");
})
.catch((err) => {
console.error(err);
});
// ensureFile
const file = "/this/path/does/not/exist/file.txt";
fs.ensureFile(file)
.then(() => {
console.log("!");
})
.catch((err) => {
console.error(err);
});
// move
const src = "/dir/file.txt";
const dest = "/dir/this/path/does/not/exist/file.txt";
fs.move(src, dest)
.then(() => {
console.log("!");
})
.catch((err) => {
console.error(err);
});
// outputFile
const file = "/this/path/does/not/exist/file.txt";
fs.outputFile(file, "!")
.then(() => fs.readFile(file, "utf8"))
.then((data) => {
console.log(data); // => !
})
.catch((err) => {
console.error(err);
});
// readJson
fs.readJson("/data.json")
.then((obj) => {
console.log(obj.someKey); // => some value
})
.catch((err) => {
console.error(err);
});
// remove
fs.remove("/dir/file")
.then(() => {
console.log("!");
})
.catch((err) => {
console.error(err);
});
// writeJson
fs.writeJson("/data.json", { someKey: "some value" })
.then(() => {
console.log("!");
})
.catch((err) => {
console.error(err);
});
uuid
Weekly downloads: 36 million.
Purpose: Generate a unique identifier.
Usage example.
Let's create a server using express that returns an ID when requested by the client.
Install uuid, express and cors: yarn add uuid express cors.
Create a uuid.js file:
const express = require("express");
const cors = require("cors");
const { v4: uuidv4 } = require("uuid");
const app = express();
app.use(cors());
app.use("/getId", (_, res) => {
//
const id = uuidv4();
//
res.json(id);
});
app.listen(process.env.PORT || 3000, () => console.log("server ready"));
We start the server: node uuid.js.
Create index.html file:
<body>
<input type="text" />
<button>add</button>
<ul></ul>
<script>
const button = document.querySelector("button");
const input = document.querySelector("input");
const list = document.querySelector("ul");
button.addEventListener("click", async () => {
//
const res = await fetch("http://localhost:3000/getId");
const id = await res.json();
const value = input.value;
if (value.trim() !== "") {
list.insertAdjacentHTML(
"beforeend",
//
`<li data-id=${id}>${value}</li>`
);
}
});
input.value = ", , ...";
button.click();
</script>
</body>
Open index.html in a browser.
Alternatively, in simple applications, you can use the Date.now () method, which returns the number of milliseconds since January 1, 1970:
const id1 = Date.now();
console.log(id1); // 1601905165758
console.log(typeof id1); // number
const id2 = Date.now().toString().slice(-4);
console.log(id2); // 5758
moment
Weekly Downloads: 14 million.
Purpose: Date and time formatting.
Usage example.
const moment = require("moment");
console.log(
`
${moment().format()}
${moment().format("DD.MM.YYYY H:m")}
`
);
/*
2020-10-05T19:16:38+05:00
05.10.2020 19:16
*/
moment.locale("ru");
console.log(moment().format("dddd, Do MMMM Y"));
// , 5- 2020
Alternative: Date and Intl.DateTimeFormat constructors.
const date = new Date();
const options = {
day: "numeric",
month: "long",
year: "numeric",
};
console.log(date.toLocaleString("ru", options));
// 5 2020 .
options.weekday = "long";
options.hour = "numeric";
options.minute = "numeric";
console.log(
new Intl.DateTimeFormat("ru", options).format(date)
); // , 5 2020 ., 19:42
Moment is currently discontinued.
axios
Weekly downloads: 12 million.
Purpose: Sending HTTP requests. Works in both Node.js and browser.
Usage example.
Install the package: yarn add axios.
Create axios.js file:
// GET
const axios = require("axios");
(async () => {
try {
const res = await axios.get(
"https://jsonplaceholder.typicode.com/users"
);
console.table(res.data);
} catch (er) {
console.error(er);
}
})();
Run the file: node axios.js.
// POST
axios
.post("/user", {
firstName: "Harry",
lastName: "Heman",
})
.then((res) => {
console.log(res);
})
.catch((er) => {
console.error(er);
});
Implementation of a GET request in "pure" Node.js:
const https = require("https");
https
.get("https://jsonplaceholder.typicode.com/users", (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
console.table(JSON.parse(data));
});
})
.on("error", (er) => {
console.error(er.message);
});
In the browser, you can use the Fetch API:
;(async () => {
await fetch("http://example.com/user", {
method: "POST",
mode: "no-cors",
body: JSON.stringify({
firstName: "Harry",
lastName: "Heman",
}),
});
})();
On the web, you can find a mention of another package for sending HTTP requests - request, however, it is currently deprecated.
async
Weekly downloads: 31 million.
Purpose: utility for working with asynchronous code. Works in both Node.js and browser.
Usage example.
Install the package: yarn add async.
Create 3 files (name -> content): file1.txt -> foo, file2.txt -> bar, file3.txt -> baz qux.
Create the async.js file:
const async = require("async");
const fs = require("fs");
const ext = "txt";
const file = (name) => `${__dirname}/${name}.${ext}`;
//
async.map(
[file("file1"), file("file2"), file("file3")],
fs.stat,
(er, results) => {
if (er) console.error(er);
console.log(results.map((item) => item.size));
}
); // [ 3, 3, 7 ]
//
async.map(
[file("file1"), file("file2"), file("file3")],
fs.readFile,
(er, results) => {
if (er) console.error(er);
console.log(results.map((item) => item.toString()));
}
); // [ 'foo', 'bar', 'baz qux' ]
//
const timer1 = () => setTimeout(() => console.log("foo"), 300);
const timer2 = () => setTimeout(() => console.log("bar"), 100);
const timer3 = () => setTimeout(() => console.log("baz"), 200);
const asyncFuntions = [timer1, timer2, timer3];
async.parallel(asyncFuntions, (er, res) => {
console.log(res);
}); // bar baz foo
//
async.series(asyncFuntions, (_, res) => console.log(res));
// foo
//
const add1 = (n, cb) => setTimeout(() => cb(null, n + 1), 100);
const sub2 = (n, cb) => setTimeout(() => cb(null, n - 2), 200);
const mult3 = (n, cb) => setTimeout(() => cb(null, n * 3), 300);
const composed = async.compose(add1, sub2, mult3);
// mult3 -> sub2 -> add1
composed(4, (_, res) => console.log(res)); // 11
dotenv
Weekly Downloads:
12M Purpose: Load environment variables from the ".env" file into process.env.
Usage example.
Let's simulate a connection to MongoDB Cloud.
Install the package: yarn add dotenv.
Create a ".env" file:
// <usename>, <password> <dbname>
MONGODB=mongodb+srv://<username>:<password>@cluster0.p7jbn.mongodb.net/<dbname>?retryWrites=true&w=majority
Create a file "dotenv.js":
// dotenv
require("dotenv/config");
// mongoose
const mongoose = require("mongoose");
// process.env.MONGODB - "MONGODB" ".env"
mongoose.connect(process.env.MONGODB, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
Alternatively, you can use config .
Install the package: yarn add config.
Create config.json file:
{
"mongoDB": "mongodb+srv://<username>:<password>@cluster0.p7jbn.mongodb.net/<dbname>?retryWrites=true&w=majority"
}
Create config.js file:
// config
const config = require("config");
// mongoose
const mongoose = require("mongoose");
// config.get("mongoDB") - "mongoDB" "config" "config.json"
mongoose.connect(config.get("mongoDB"), {
useNewUrlParser: true,
useUnifiedTopology: true,
}, () => console.log("Connected to database"));
validator
Weekly downloads: 4 million.
Purpose: a library for validation and neutralization of data transmitted as strings.
Usage example.
Let's implement form submission and data validation on the server.
Install the package: yarn add validator.
Create the index.html file:
<head>
<title>Form Validation</title>
<style>
label,
span {
display: block;
margin: .5rem;
}
</style>
</head>
<body>
<form>
<label>Name: <input type="text" value="Igor" data-name="name" /></label>
<label>Age: <input type="number" value="30" data-name="age" /></label>
<label
>Email:
<input type="email" value="myemail.example.com" data-name="email"
/></label>
<label
>Site: <input type="url" value="myblog.org" data-name="url"
/></label>
<label
>Card: <input type="text" value="1111222233334444" data-name="card"
/></label>
<button>Send</button>
<p></p>
</form>
<script>
const form = document.querySelector("form");
//
const btn = form.querySelector("button");
//
const log = form.querySelector("p");
//
const getValue = (name) =>
form.querySelector(`[data-name=${name}]`).value;
btn.addEventListener("click", (e) => {
e.preventDefault();
//
const data = {
name: getValue("name"),
age: getValue("age"),
email: getValue("email"),
url: getValue("url"),
card: getValue("card"),
};
//
const sendData = async (url) => {
const req = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
//
const res = await req.json();
console.log(res);
//
if (res.length !== 0) {
let html = "";
for (const msg of res) {
html += `<span>${msg}</span>`;
log.innerHTML = html;
}
} else {
log.textContent = 'Success'
}
};
sendData("http://localhost:3000/users");
});
</script>
Create validator.js file:
const express = require("express");
const cors = require("cors");
// ,
// escape -
const {
isAlpha,
isNumeric,
isEmail,
isURL,
isCreditCard,
escape,
} = require("validator");
//
const validators = [isAlpha, isNumeric, isEmail, isURL, isCreditCard];
const app = express();
app.use(cors());
app.use(express.json());
//
app.use("/users", (req, res) => {
//
const data = ({ name, age, email, url, card } = req.body);
console.log(data);
//
const errors = [];
//
for (let i = 0; i < validators.length; i++) {
//
escape(Object.values(data)[i]);
//
//
if (!validators[i](Object.values(data)[i])) {
errors.push(`Wrong ${Object.keys(data)[i]}`);
}
}
console.log(errors);
//
res.json(errors);
});
app.listen(process.env.PORT || 3000, () => console.log("Server ready"));
We start the server: node validator.js.
Open index.html and send data.
We receive a message that the email address and credit card number are invalid.
Let's change the email and card values ββto myemail@example.com and 2222111111111111, respectively.
Click "Send".
We receive a message about successful data validation.
That's all for today. Hope you found something helpful. Thank you for attention.