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

Mayank Choubey
Tech Tonic
10 min readJan 18, 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 1 to 10.

The other parts in this series are:

1. lodash

Lodash stands as a comprehensive utility library designed to expedite and simplify common development tasks within the JavaScript ecosystem. It offers a large collection of functions for manipulating arrays, objects, strings, numbers, and other data structures. Lodash adheres to functional programming principles, promoting code conciseness, readability, and maintainability.

Statistics

  • Version: 4.17.21 (as of January 16, 2024)
  • Weekly Downloads: 47M
  • Repository Size: 1.41 MB
  • Total Files: 1054
  • License: MIT

Code Samples

Data Filtering

const users = [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }, { name: "Charlie", age: 20 }];
const youngUsers = _.filter(users, (user) => user.age < 25); // Returns [{ name: "Alice", age: 25 }, { name: "Charlie", age: 20 }]

Array Transformation

const numbers = [1, 2, 3, 4, 5];
const squares = _.map(numbers, (number) => number * number); // Returns [1, 4, 9, 16, 25]

Method Chaining

const data = _.chain(users)
.filter((user) => user.age > 20)
.map((user) => user.name)
.value(); // Returns ["Bob"]

Pros and Cons

Pros

  • Comprehensive Functionality: Offers an extensive array of functions encompassing various data manipulation tasks.
  • Performance Optimization: Meticulous optimization often surpasses native JavaScript in execution speed.
  • Method Chaining: Enables concise and expressive code sequences through function chaining.
  • Functional Programming Principles: Promotes code predictability, testability, and reusability.

Cons

  • Learning Curve: Requires investment in learning its extensive function set.
  • Project Size Considerations: Including the entire library in smaller projects can introduce unnecessary bloat.
  • Potential for Abstraction: Overreliance may hinder a deep understanding of core JavaScript concepts.

2. chalk

Chalk is a popular utility library for adding color and style to your JavaScript output, particularly in the terminal environment. It allows developers to enhance the readability and visual appeal of console logs, errors, and other text-based information. Chalk embraces simplicity and efficiency, offering a concise API for terminal styling without introducing unnecessary complexity.

Statistics

  • Version: 5.3.0 (as of January 16, 2024)
  • Weekly Downloads: 276M
  • Repository Size: 33.6 KB
  • Total Files: 30
  • License: MIT

Code Samples

Basic Colorization

const message = chalk.green('This is a success message!');
console.log(message); // Outputs green text: This is a success message!

Combining Styles

const error = chalk.bold.red.underline('Error: File not found');
console.error(error); // Outputs bold, red, underlined text: Error: File not found

Template Strings

const name = 'Alice';
const greeting = chalk`Hello, {chalk.bold.magenta(name)}!`;
console.log(greeting); // Outputs: Hello, Alice! (with Alice in bold magenta)

Pros and Cons

Pros

  • Enhanced Readability: Colors and styles improve visual differentiation of information, making logs and errors easier to understand and scan.
  • Improved Debugging: Color-coded outputs assist in identifying and isolating issues during debugging processes.
  • User Engagement: Colorful and styled outputs can enhance user experience within terminal-based applications.
  • Concise API: chalk offers a user-friendly and intuitive API with minimal learning curve.
  • Lightweight and Efficient: The library has a small footprint and minimal impact on runtime performance.

Cons

  • Platform Dependence: Functionality primarily benefits terminal environments and may not translate directly to other output formats.
  • Overuse Potential: Excessive use of color and styles can clutter the output and reduce readability.
  • Accessibility Concerns: Colorblind users may require alternative methods for information differentiation.

3. commander

Commander is a toolkit for building powerful and user-friendly command-line interfaces (CLIs). Its intuitive API empowers developers to define commands, flags, and options with remarkable ease, enabling seamless user interaction and intuitive application control. Commander champions minimalism and clarity, allowing developers to focus on core functionality without getting bogged down in complex configuration.

Statistics

  • Version: 5.2.0 (as of January 16, 2024)
  • Weekly Downloads: 129M
  • Repository Size: 34.6 KB
  • Total Files: 25
  • License: MIT

Code Samples

Basic Command Definition

const program = require('commander');

program
.command('hello', 'Greet the user')
.action(() => console.log('Hello world!'));

program.parse(process.argv);

Flags and Options

const program = require('commander');

program
.command('greet', 'Greet a specific user')
.option('-n, --name <name>', 'Specify the user name')
.action((options) => console.log(`Hello, ${options.name}!`));

program.parse(process.argv);

Subcommands and Help

const program = require('commander');

program
.command('users')
.subcommand('list', 'List all users')
.subcommand('add', 'Add a new user')
.option('-h, --help', 'Display help message')
.parse(process.argv);

if (program.args.includes('--help')) {
program.help();
} else {
// Execute relevant subcommand
}

Pros and Cons

Pros

  • Intuitive API: commander boasts a user-friendly and well-documented API, making CLI development accessible even for novice developers.
  • Extensive Functionality: Supports a wide range of features, including subcommands, flags, options, and argument parsing.
  • Clear and Readable Output: Helps build CLIs with consistent and informative output, enhancing user experience.

Cons

  • Steeper Learning Curve for Complex Applications: While basic CLIs are straightforward, intricate interactions and custom validations may require deeper understanding.
  • Potential for Verbosity: Overly-extensive command structures can become cumbersome and challenging to navigate.

4. yarn

Yarn redefines package management with its focus on speed, security, and reliability. Unlike its predecessor npm, yarn boasts a modular architecture, caching mechanisms, and cryptographic verification, elevating the process of installing and managing dependencies to a new level of efficiency and confidence.

Statistics

  • Version: 4.0.2 (as of January 18, 2024)
  • Weekly Downloads: 4M
  • Repository Size: 35.6 MB
  • Total Files: 3,954
  • License: MIT

Usage Samples

Basic Installation

yarn add lodash

Installing Specific Versions

yarn add lodash@4.17.21

Installing Multiple Packages

yarn add lodash react react-dom

Pros and Cons

Pros

  • Unmatched Speed: Caching and parallel installation significantly reduce dependency acquisition times compared to npm.
  • Enhanced Security: Cryptographic verification ensures integrity and authenticity of downloaded packages.
  • Deterministic Builds: Consistent dependency versions across environments enable reliable builds and deployments.

Cons

  • Potentially Steeper Learning Curve: The modular approach and additional features might require more learning compared to basic npm usage.
  • Larger Initial Installation Footprint: The package itself consumes more disk space than npm due to its additional functionalities.
  • Potential Compatibility Issues: Some legacy tools and workflows designed for npm might require adjustments for seamless yarn integration.

5. express

Express establishes itself as the unbeaten champion in the world of Node.js web application frameworks. Many alternate frameworks came, but no one could challenge the dominance of Express. Its minimalist and unopinionated design empowers developers to create robust and scalable servers with remarkable ease. Express prioritizes conciseness and flexibility, providing a foundational framework upon which developers can build their applications without being constrained by rigid conventions.

Statistics

  • Version: 4.18.2 (as of January 18, 2024)
  • Weekly Downloads: 26M
  • Repository Size: 83.7 KB
  • Total Files: 292
  • License: MIT

Code Samples

Hello World Server

const express = require('express');
const app = express();

app.get('/', (req, res) => {
res.send('Hello, World!');
});

app.listen(3000, () => console.log('Server listening on port 3000'));

Routing and Middleware

app.get('/users', (req, res) => {
// Get user data
res.json({ users: [...] });
});

app.use((req, res, next) => {
console.log('Request received for', req.url);
next();
});

Third-Party Integration

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

app.use(bodyParser.json());

app.post('/data', (req, res) => {
console.log('Received data:', req.body);
// Process data
res.send('Data successfully processed!');
});

Pros and Cons

Pros

  • Minimalist and Unopinionated: Developers have complete control over application architecture and design choices.
  • Extensive Middleware Ecosystem: A vast collection of community-built middleware packages expands functionality and simplifies common tasks.
  • Scalability and Performance: express lays the foundation for building robust and high-performance servers.
  • Large and Active Community: Abundant documentation, tutorials, and community support ease learning and troubleshoot challenges.

Cons

  • Security Considerations: Developers are responsible for implementing appropriate security measures within their express applications.
  • Debugging Complex Middleware Chains: Troubleshooting issues within intricate middleware stacks can be challenging.

6. async

Async provides a suite of functions and control flow structures to manage tasks that gets done over time (in other words, promises). It empowers developers to handle delayed computations, network requests, and other non-blocking operations, ensuring a fluid and efficient user experience. Async prioritizes clarity and predictability, striving to solve the complexities of asynchronous programming.

Statistics

  • Version: 3.2.5 (as of January 18, 2024)
  • Weekly Downloads: 50M
  • Repository Size: 45.5 KB
  • Total Files: 55
  • License: MIT

Code Samples

Parallel Execution

async.parallel([
(callback) => {
// Task 1
callback(null, 'Result 1');
},
(callback) => {
// Task 2
callback(null, 'Result 2');
}
], (err, results) => {
// Handle results
});

Sequential Execution

async.series([
(callback) => {
// Task 1
callback(null, 'Result 1');
},
(callback) => {
// Task 2 (depends on Result 1)
callback(null, 'Result 2');
}
], (err, results) => {
// Handle results
});

Handling Timeouts

async.timeout(function(callback) {
// Potentially long-running task
}, 5000, (err) => {
// Handle timeout
});

Pros and Cons

Pros

  • Clear and Concise API: async offers intuitive functions for common asynchronous patterns, simplifying code readability and maintainability.
  • Control Flow Structures: Provides constructs like async.waterfall and async.auto for managing complex asynchronous workflows.
  • Error Handling: Facilitates robust error propagation and handling within asynchronous operations.

Cons

  • Potential for Callback Hell: Overly nested asynchronous operations can lead to code complexity if not carefully structured.
  • Learning Curve: Understanding asynchronous programming concepts and async’s API requires some initial investment.
  • Alternative Solutions: Modern JavaScript offers native promises and async/await syntax, which some developers might prefer.

7. debug

Debug empowers developers to enrich the execution path of their code with precise and informative logging. It offers a lightweight and flexible mechanism for printing custom messages to the console, enabling targeted debugging and troubleshooting without overwhelming the output with unnecessary noise. Debug prioritizes minimalism and context-awareness, ensuring messages are relevant and actionable.

Statistics

  • Version: 4.3.4 (as of January 18, 2024)
  • Weekly Downloads: 232M
  • Repository Size: 15.5 KB
  • Total Files: 15
  • License: MIT

Code Samples

Basic Usage

const debug = require('debug')('my-module');

debug('Starting the module');
// ... perform module logic
debug('Module completed successfully');

Conditional Debugging

const debug = require('debug')('my-module');

if (process.env.DEBUG) {
debug('Detailed information for debugging');
}

Multiple Loggers

const appDebug = require('debug')('app');
const dbDebug = require('debug')('db');

appDebug('Handling request');
// ... application logic
dbDebug('Querying database');

Pros and Cons

Pros

  • Concise and Readable Output: Logs are prefixed with the module name, providing instant context and clarity.
  • Customizable Formatting: Developers can tailor log formatting to their preferences and project needs.
  • Conditional Debugging: Logs can be enabled or disabled dynamically based on environment variables or other conditions.
  • Minimal Performance Impact: The library is optimized for efficiency and has minimal overhead.

Cons

  • Potential for Overuse: Excessive logging can clutter the output and make it difficult to identify key information.
  • Learning Curve: Understanding the syntax and best practices for effective debugging with debug requires some initial investment.
  • Alternative Solutions: Node.js offers built-in console.log and other logging options, which might suffice for basic debugging needs.

8. fs-extra

fs-extra is a comprehensive extension of Node.js’s built-in fs module, providing a wealth of additional functions and utilities to streamline file system operations. It empowers developers to manage files and directories with greater ease and flexibility, saving time and effort while ensuring robust error handling and cross-platform compatibility.

Statistics

  • Version: 10.1.0 (as of January 18, 2024)
  • Weekly Downloads: 86M
  • Repository Size: 223 KB
  • Total Files: 154
  • License: MIT

Code Samples

Copying Directories Recursively

const fs = require('fs-extra');

fs.copy('./src', './dist', (err) => {
if (err) {
console.error(err);
} else {
console.log('Directory copied successfully');
}
});

Removing Directories Recursively, Including Contents

fs.remove('./temp', (err) => {
if (err) {
console.error(err);
} else {
console.log('Directory removed successfully');
}
});

Creating a Symbolic Link

fs.symlink('./src/data.json', './dist/data.json', (err) => {
if (err) {
console.error(err);
} else {
console.log('Symbolic link created successfully');
}
});

Pros and Cons

Pros

  • Extensive Functionality: Offers a wide range of file and directory operations beyond the core fs module's capabilities.
  • Convenience Functions: Simplifies common tasks like copying, moving, deleting, and creating directories.
  • Error Handling: Provides robust error handling mechanisms to ensure graceful error recovery.
  • Cross-Platform Compatibility: Works consistently across different operating systems.
  • Promise-Based API: Supports asynchronous operations using promises for cleaner code structure.

Cons

  • Additional Dependency: Introduces an external dependency for file system operations.
  • Compatibility Considerations: Newer versions of Node.js might introduce built-in features that overlap with fs-extra’s functionality.

9. date-fns

date-fns is an alternative to the aging, but popular, moment library. Date-fns providing a comprehensive collection of functions dedicated to manipulating, formatting, and analyzing dates and times with exceptional flexibility and accuracy. It hides the complexities of the native Date object, offering a streamlined API, immutable data structures, and a focus on functional programming principles for predictable and error-free date-related operations.

Statistics

  • Version: 2.29.4 (as of January 18, 2024)
  • Weekly Downloads: 17M
  • Repository Size: 454 KB
  • Total Files: 654
  • License: MIT

Code Samples

Creating a Date Object

import { parseISO } from 'date-fns';

const date = parseISO('2024-01-18T11:54:00');

Formatting a Date

import { format } from 'date-fns';

const formattedDate = format(date, 'MMMM d, yyyy, h:mm a'); // Output: "January 18, 2024, 11:54 AM"

Comparing Dates

import { isAfter, isBefore } from 'date-fns';

const isFuture = isAfter(date, new Date());
const isPast = isBefore(date, new Date());

Calculating Differences

import { differenceInDays } from 'date-fns';

const daysUntilEvent = differenceInDays(date, new Date());

Pros and Cons

Pros

  • Immutability: Ensures data consistency and prevents unintended side effects.
  • Chainable Methods: Promotes fluent and expressive code style.
  • Extensive Functionality: Offers a wide range of date manipulation and formatting capabilities.
  • I18n Support: Handles internationalization and localization effortlessly.
  • TypeScript Compatibility: Provides robust type definitions for enhanced code safety.

Cons

  • Potential Interoperability Issues: Might require conversions when interacting with code using native Date objects.

10. underscore

Underscore establishes itself as a JavaScript library packed with utility functions designed to simplify common tasks, enhance code readability, and elevate development efficiency. It offers a vast array of tools for manipulating arrays, objects, strings, numbers, and other data structures, empowering developers to focus on core logic rather than reinventing the wheel for repetitive tasks.

Statistics

  • Version: 1.13.7 (as of January 18, 2024)
  • Weekly Downloads: 12M
  • Repository Size: 33.6 KB
  • Total Files: 30
  • License: MIT

Code Samples

Filtering an Array

const fruits = ['apple', 'banana', 'orange', 'kiwi'];
const citrusFruits = _.filter(fruits, fruit => fruit.includes('citrus'));
// citrusFruits now holds ['orange']

Mapping an Object

const users = { John: 30, Jane: 25, Mark: 40 };
const userAges = _.map(users, (age, name) => `${name} is ${age} years old`);
// userAges now holds an array of age strings for each user

Grouping Data

const products = [
{ category: 'Electronics', price: 500 },
{ category: 'Clothing', price: 200 },
{ category: 'Electronics', price: 100 },
];
const groupedProducts = _.groupBy(products, 'category');
// groupedProducts now holds objects with categorized product lists

Pros and Cons

Pros

  • Extensive Functionality: Underscore provides a robust collection of well-tested and reliable functions for diverse tasks.
  • Improved Code Readability: Using concise and familiar functions enhances code clarity and maintainability.
  • Reduced Development Time: Eliminates the need to write repetitive code for common tasks.

Cons

  • Alternatives in Modern JavaScript: Native methods and functionalities in newer JavaScript versions might suffice for simpler tasks.
  • Legacy Considerations: Some underscore functions might not be fully compatible with modern standards and best practices.

That’s all for the part 1. Stay tuned for more.

The other parts in this series are:

--

--