Node.js: The commonly used NPM packages — Part 2
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:
- Part 1: Packages 1 to 10
- Part 3: Packages 21 to 30
- Part 4: Packages 31 to 40
- Part 5: Packages 41 to 50 (last part)
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.
That’s all for part 2.
The other parts in this series are: