Node.js: The commonly used NPM packages — Part 2

Mayank Choubey
Tech Tonic
9 min readJan 19, 2024

--

There is no denying that Node.js’s power comes from the 1.5M NPM packages. Without NPM, Node.js is still usable, but not much. In this article series, we will explore the commonly used NPM packages that every developer should be aware of. In this part, we’ll cover packages 11 to 20.

The other parts in this series are:

11. axios

Axios established itself as a promise-based HTTP client built for the modern web. It provides a simple and elegant API for making HTTP requests, offering developers a clear and concise way to fetch data, send requests, and interact with remote servers. Axios was and still the most popular HTTP client for Node.js. With built-in stable fetch, the popularity of axios might reduce over time.

Statistics

  • Version: 5.2.0 (as of January 18, 2024)
  • Weekly Downloads: 47M
  • Repository Size: 1.8M
  • Total Files: 81
  • License: MIT

Code Samples

Simple GET Request

axios.get('https://api.example.com/users')
.then(response => {
console.log(response.data); // Array of user objects
})
.catch(error => {
console.error(error);
});

POST Request with JSON Data

axios.post('https://api.example.com/posts', {
title: 'My new post',
content: 'This is the post content',
})
.then(response => {
console.log(response.data); // Newly created post object
})
.catch(error => {
console.error(error);
});

Automatic JSON Serialization

axios.get('https://api.example.com/products')
.then(response => {
console.log(response.data); // Array of product objects automatically parsed from JSON
})
.catch(error => {
console.error(error);
});

Pros and Cons

Pros

  • Promise-based API: Offers a clean and asynchronous approach to handling HTTP requests and responses.
  • Concise and Readable Syntax: Code is clear and easy to understand, minimizing boilerplate and complexity.
  • Automatic JSON Serialization and Deserialization: Simplifies working with JSON data without manual parsing.
  • Interceptors: Provides powerful hooks for modifying requests and responses, customizing behavior, and error handling.
  • Cancellation Support: Allows for aborting pending requests based on certain conditions.

Cons

  • Learning Curve for Advanced Features: Mastering interceptors and customization options might require additional investment.
  • Alternatives in Native APIs: Fetch API in modern Node.js offers similar functionality, though lacking some of axios’s features.

12. tslib

tslib establishes itself as the heart of runtime support for TypeScript. It provides the necessary functionality for using helper functions and decorators within compiled JavaScript code, enabling essential features like class inheritance, decorators, and mixins to function seamlessly even when targeting older JavaScript environments.

Statistics

  • Version: 2.5.1 (as of January 18, 2024)
  • Weekly Downloads: 232M
  • Repository Size: 84KB
  • Total Files: 14
  • License: MIT

Code Samples

Using Decorators with tslib

@deprecated('Use the new `replaceWith` function instead.')
class MyClass {
// ... class implementation
}

// Compile using the `--importHelpers` flag to include tslib's runtime helpers

Extending Classes with Mixins and tslib

class Logger {
log(message: string) {
console.log(message);
}
}

class MyExtendedClass extends MyClass {
@mixin(Logger)
// ... class implementation with access to `log` method
}

// Compile using the `--importHelpers` flag to include tslib's mixin helper

Pros and Cons

Pros

  • Essential for Helper Functions and Decorators: Enables key TypeScript features to work in compiled JavaScript.
  • Compatibility across Environments: Supports various JavaScript versions and build tools.
  • Automatic Inclusion with TypeScript Flag: Requires minimal manual configuration thanks to the --importHelpers flag.

Cons

  • Indirect Dependency: Not always explicitly listed as a project dependency due to its role as runtime support.
  • Potentially Overlooked: Developers might not fully grasp its importance for some TypeScript features.

13. mkdirp

mkdirp can create directories with ultimate ease. It handles the complexities of nested directory structures, ensuring that every path is established properly.

Statistics

  • Version: 1.0.4 (as of January 18, 2024)
  • Weekly Downloads: 70M
  • Repository Size: 107 KB
  • Total Files: 65
  • License: MIT

Code Samples

Constructing a Nested Directory Structure

const mkdirp = require('mkdirp');

mkdirp('./src/components/user-profile', (err) => {
if (err) {
console.error(err); // Handle errors gracefully
} else {
console.log('Directory structure created successfully!');
}
});

Handling Asynchronous Operations with Promises

mkdirp('./data/logs')
.then(() => {
console.log('Directory created asynchronously!');
})
.catch((err) => {
console.error(err); // Handle errors appropriately
});

Customizing Options for Enhanced Control

mkdirp('./tmp/cache', { mode: 0o755 }, (err) => {
// Directory created with specific permissions
});

Pros and Cons

Pros

  • Recursive Creation: Seamlessly constructs entire directory hierarchies in a single function call.
  • Error Handling: Provides robust mechanisms for managing potential errors during directory creation.
  • Asynchronous Support: Works harmoniously with promises for efficient integration into non-blocking workflows.
  • Customization Options: Grants developers control over directory permissions and other attributes.

Cons

  • Potential for Race Conditions: Asynchronous usage might necessitate careful handling of concurrent operations.

14. glob

glob tracks down files within your project based on predefined patterns. It helps to identify specific sets of files with concise expressions, simplifying tasks like building applications, running tests, and processing data.

Statistics

  • Version: 8.0.3 (as of January 18, 2024)
  • Weekly Downloads: 130M
  • Repository Size: 454KB
  • Total Files: 65
  • License: MIT

Code Samples

Matching all JavaScript files in a directory

const glob = require('glob');

glob('./src/**/*.js', (err, files) => {
if (err) {
console.error(err);
} else {
console.log('Found', files.length, 'JavaScript files.');
}
});

Matching files with specific extensions

glob(['./data/*.csv', './reports/*.txt'], (err, files) => {
// Process identified CSV and TXT files
});

Filtering files based on names

glob('./images/*.{png,jpg}', (err, files) => {
// Process only PNG and JPG image files
});

Pros and Cons

Pros

  • Concise and Expressive: Patterns provide intuitive ways to specify desired files.
  • Flexible Matching: Supports wildcards, negations, and expansions for granular control.
  • Cross-Platform Compatibility: Works across different operating systems with consistent behavior.
  • Efficient File Finding: Minimizes time spent manually searching for files.

Cons

  • Learning Curve for Advanced Features: Complex patterns may require some initial understanding.
  • Alternatives in Modern Tools: Build systems might offer built-in file finders for basic cases.

15. yargs

yargs transforms complex command line arguments into structured data. It empowers developers to build user-friendly CLI tools and interactive scripts by parsing arguments, generating help messages, and handling errors with ease.

Statistics

  • Version: 17.5.1 (as of January 18, 2024)
  • Weekly Downloads: 85M
  • Repository Size: 292 KB
  • Total Files: 62
  • License: MIT

Code Samples

Simple CLI Tool with Basic Options

const yargs = require('yargs');

yargs
.command('sayHello', 'Says hello to a name', {
name: { type: 'string', alias: 'n', demandOption: true },
})
.option('verbose', { type: 'boolean', alias: 'v' })
.help()
.parse((err, argv) => {
if (err) {
console.error(err);
} else {
console.log(`Hello, ${argv.name}!`);
}
});

Command Groups and Subcommands

yargs
.command('user', 'Manage user accounts', {
create: { command: 'add' },
update: { command: 'modify' },
delete: { command: 'remove' },
})
.parse();

Customizing Help Messages and Output

yargs
.help('usage', '[OPTIONS] <command>')
.epilogue('For more information, visit https://yargs.js.org')
.parse((err, argv) => {
// Access parsed arguments and custom output options
});

Pros and Cons

Pros

  • Comprehensive Argument Parsing: Handles various argument types, flags, and aliases.
  • User-Friendly Interface: Simplifies CLI tool creation with intuitive options and help messages.
  • Customization Options: Provides control over parsing behavior, output format, and error handling.
  • Powerful Extension System: Extensible with plugins for additional features and integrations.

Cons

  • Potential for Verbosity: Overly complex CLI definitions can become difficult to maintain.
  • Alternatives for Simple Cases: Built-in Node.js options might suffice for basic parsing needs.

16. colors

colors enriches the CLI output with colors. It elevates plain text into visually captivating experiences, enhancing readability, highlighting important information, and injecting a touch of personality into your CLI tools and scripts.

Statistics

  • Version: 2.6.0 (as of January 18, 2024)
  • Weekly Downloads: 18M
  • Repository Size: 39 KB
  • Total Files: 21
  • License: MIT

Code Samples

Adding Basic Colors

const colors = require('colors');

console.log(colors.red('Warning! Potential errors ahead.'));
console.log(colors.green('Success! Operation completed successfully.'));

Combining Colors and Styles

console.log(colors.bold.underline.yellow('Important Announcement!'));
console.log(colors.italic.gray('Additional information: https://example.com'));

Using Templates and String Interpolation

const name = 'John';
console.log(colors.magenta(`Welcome back, ${name}!`));

Pros and Cons

Pros

  • Simple and Intuitive API: Easy to learn and use, even for beginners.
  • Wide Range of Colors and Styles: Supports various color models and text formatting options.
  • Cross-Platform Compatibility: Works consistently across different operating systems.

Cons

  • Limited Styling Capabilities: Lacks advanced formatting options like borders and backgrounds.
  • Alternatives for Basic Use Cases: Built-in terminal escape sequences can handle simple coloration.

17. inquirer

inquirer is used to create conversations within the command line interface. It empowers you to design interactive workflows, ask compelling questions, and collect user input with ease. From collecting feedback to configuring settings, inquirer transforms static CLI tools into dynamic dialogues, injecting a human touch into your interactions.

Statistics

  • Version: 8.2.4 (as of January 18, 2024)
  • Weekly Downloads: 27M
  • Repository Size: 89 KB
  • Total Files: 26
  • License: MIT

Code Samples

Basic Prompt for User Name

const inquirer = require('inquirer');

inquirer.prompt([{
type: 'input',
name: 'username',
message: 'What is your username?',
}])
.then(answers => {
console.log(`Welcome back, ${answers.username}!`);
});

List Selection for Configuration

inquirer.prompt([{
type: 'list',
name: 'theme',
message: 'Choose your preferred theme:',
choices: ['light', 'dark', 'custom'],
}])
.then(answers => {
// Apply chosen theme to the application
});

Password Prompt with Masking

inquirer.prompt([{
type: 'password',
name: 'password',
message: 'Enter your password:',
}])
.then(answers => {
// Validate and handle password securely
});

Pros and Cons

Pros

  • Variety of Question Types: Supports text input, lists, choices, passwords, and more.
  • User-Friendly Interface: Ensures smooth and intuitive user interaction.
  • Validation and Error Handling: Provides mechanisms for ensuring accurate and consistent input.
  • Customization Options: Tailors prompts and messages for specific workflows.

Cons

  • Learning Curve for Advanced Features: Mastering custom validation and workflows might require some investment.
  • Alternatives for Simple Cases: Built-in Node.js options can handle basic prompts.

18. minimist

minimist transforms cryptic command-line arguments into well-structured data. It empowers developers to build user-friendly and flexible CLI tools by defining options, handling aliases, and validating input with accuracy.

Statistics

  • Version: 2.5.1 (as of January 18, 2024)
  • Weekly Downloads: 52M
  • Repository Size: 54 KB
  • Total Files: 24
  • License: MIT

Code Samples

Basic Argument Parsing

const args = require('minimist')(process.argv.slice(2));

console.log(`File to copy: ${args.file}`);
console.log(`Force overwrite: ${args.force}`);

Defining Options and Aliases

const options = {
alias: {
f: 'force',
},
};

const args = require('minimist')(process.argv.slice(2), options);

// Access options via their aliases or names

Validation and Error Handling

const args = require('minimist')(process.argv.slice(2), {
string: ['file'],
boolean: ['force'],
});

if (!args.file) {
console.error('Please specify a file to copy.');
process.exit(1);
}

Pros and Cons

Pros

  • Powerful Parsing Capabilities: Handles various argument types, flags, and aliases.
  • Customizable Options: Defines aliases, defaults, and validation rules.
  • Error Handling: Provides mechanisms for graceful error handling and feedback.

Cons

  • Alternatives for Simple Cases: Built-in Node.js options can handle basic argument parsing

19. body-parser

body-parser decodes the bodies of incoming HTTP requests. It acts as a bridge between the raw data transmitted by clients and the structured information your Node.js applications need, ensuring seamless communication and empowering you to construct dynamic web experiences. It is most often used with Express.

Statistics

  • Version: 1.20.2 (as of January 18, 2024)
  • Weekly Downloads: 34M
  • Repository Size: 60 KB
  • Total Files: 11
  • License: MIT

Code Samples

Basic Parsing for JSON Data

const express = require('express');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json()); // Parse JSON data

app.post('/users', (req, res) => {
const user = req.body; // Access parsed user data
// Process user information
});

Parsing URL-Encoded Data

app.use(bodyParser.urlencoded({ extended: true })); // Parse URL-encoded data

app.post('/login', (req, res) => {
const { username, password } = req.body; // Access parsed form data
// Validate credentials
});

Pros and Cons

Pros

  • Simplifies Data Access: Makes request data easily available in req.body.
  • Supports Multiple Formats: Parses JSON, URL-encoded, and text data.
  • Customizable Options: Controls parsing behavior and error handling.

Cons

  • Potential Performance Impact: Parsing can add overhead, especially for large requests.
  • Security Considerations: Improper handling of parsed data can lead to vulnerabilities.

20. rxjs

RxJS orchestrates asynchronous data streams with efficiency. It empowers you to process events, handle errors gracefully, and compose complex flows with clarity, transforming your JavaScript applications into dynamic data processors.

Statistics

  • Version: 7.5.7
  • Weekly Downloads: 54,154,154
  • Repository Size: 4.5 M
  • Total Files: 2277
  • License: MIT

Code Samples

Observables

import { Observable } from 'rxjs';

// Creating an Observable that emits a sequence of numbers
const numbers$ = Observable.create(observer => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
});

Operators

import { map, filter, tap } from 'rxjs/operators';

numbers$
.pipe(
map(x => x * 2), // Multiply each value by 2
filter(x => x % 3 === 0), // Keep only multiples of 3
tap(x => console.log('Transformed value:', x)) // Log each value
)
.subscribe(x => console.log('Final value:', x));

Fetching Data from an API

import { ajax } from 'rxjs/ajax';

const apiUrl = 'https://api.example.com/data';
ajax.get(apiUrl)
.subscribe(response => {
console.log('Fetched data:', response.response);
});

Pros and Cons

Pros

  • Asynchronous Complexity: Streamlines handling of events, timers, promises, and other asynchronous operations.
  • Declarative and Functional Style: Promotes concise, readable, and testable code.
  • Composition and Reusability: Operators enable elegant construction of complex data flows from simpler ones.
  • Error Handling: Provides robust mechanisms for managing errors and avoiding unexpected failures.

Cons

  • Learning Curve: Understanding reactive concepts and mastering operators can require some effort.
  • Potential Overuse: Not always the most suitable solution for simple asynchronous tasks.

--

--