Feb 16, 2025

πŸ“¦ NPM: package manager for JavaScript πŸš€

This structured guide provides a detailed yet easy-to-follow reference for JavaScript package management using npm.


Introduction

A package manager is a tool that automates the process of installing, upgrading, configuring, and managing third-party libraries (dependencies) in a project. πŸ”„βœ¨

❓ Why do we need a Package Manager? πŸ€”

Without a package manager:

  • You need to manually download and manage third-party libraries.
  • Security issues arise (ensuring you're getting the right, safe version).
  • Version control becomes complex (ensuring compatibility between different libraries).

A package manager solves these issues by:

  • Automating dependency management. βš™οΈ
  • Handling versioning and updates. πŸ”„
  • Ensuring security by verifying the source of libraries. πŸ”

πŸ” npm Overview

  • npm (Node Package Manager): Default package manager for Node.js, widely used in JavaScript development. πŸ› οΈ

πŸ—οΈ npm Architecture

  • npm Registry: A cloud-based storage of packages maintained by the npm organization. ☁️
  • npm CLI: Command-line interface to interact with the registry. πŸ–₯️
  • node_modules: The directory where all installed packages and their dependencies are stored locally. πŸ“‚

    • This directory should generally not be modified manually.
    • When troubleshooting, deleting node_modules and package-lock.json followed by npm install often resolves dependency issues.
    • The node_modules directory is typically excluded from version control (.gitignore).

πŸ“‘ Understanding package.json

The package.json file is the central configuration file for a Node.js project. It contains essential metadata about the project and its dependencies. πŸ“

πŸ“‹ Key Fields in package.json

  • name: Name of the package.
  • version: Version number following semantic versioning (major.minor.patch).
  • description: Short description of the package.
  • main: Entry point file (e.g., index.js).
  • scripts: Custom commands that can be executed using npm run.
  • dependencies: List of packages required for production.
  • devDependencies: Packages only needed for development (e.g., testing tools).
  • license: Type of license for the package.
  • repository: Link to the package's GitHub repository.

✨ Creating a package.json File

To create a new package.json file interactively:

npm init

To create it with default values:

npm init -y

πŸš€ Setting Up a JavaScript Project with npm

πŸ“₯ Installing npm and Node.js

Ensure you have Node.js installed, which includes npm:

node -v   # Check Node.js version
npm -v    # Check npm version

πŸ“Œ Installing Packages

πŸ“¦ Installing a Dependency

npm install express

πŸ›  Installing a Development Dependency

npm install jest --save-dev

#### 🎯 Installing a Specific Version

npm install lodash@4.17.21

πŸ”„ Installing the Latest Compatible Version

npm install lodash@^4.17.0  # Any minor update within 4.x
npm install lodash@~4.17.21  # Only patch updates within 4.17.x

πŸ“Œ Understanding Versioning (Semantic Versioning)

Version numbers in npm follow the Semantic Versioning (semver) format:

MAJOR.MINOR.PATCH
  • MAJOR: Increases when there are breaking changes.
  • MINOR: Increases when new features are added in a backward-compatible manner.
  • PATCH: Increases when bug fixes and minor improvements are made.

Example:

1.2.3  # 1 (Major), 2 (Minor), 3 (Patch)
  • ^1.2.3: Allows updates to 1.x.x but not 2.0.0.
  • ~1.2.3: Allows updates to 1.2.x but not 1.3.0.
  • 1.2.3: Strictly installs this exact version.

    🏷️ Understanding Peer Dependencies

Peer dependencies define package compatibility without automatically installing them.

  • Common in libraries that extend a framework (e.g., Angular lib).
  • Developers must manually install them to match project requirements.

Example:

{
  "peerDependencies": {
    "angular": "^19.0.0"
  }
}

This means the package expects angular to be installed in the project but won't install it automatically.

🧹 Pruning Unused Packages

Sometimes, dependencies remain installed even after being removed from package.json. To clean up these unused dependencies, use:

npm prune

This ensures that only necessary packages remain in node_modules, helping reduce project size and potential security risks.

πŸ“‹ Listing Installed Packages

npm list
npm list --depth=0  # Show only top-level dependencies

πŸ—‘οΈ Removing Packages

npm uninstall jest

πŸ”„ Updating Packages

npm update lodash

πŸ”’ Locking Dependencies

  • package-lock.json ensures that all team members install the same versions.
  • Always commit this file to version control.

🌍 Working with Global Packages

Global packages are installed system-wide rather than per-project. 🌐

npm install -g http-server
npm list -g  # List globally installed packages
npm uninstall -g http-server  # Remove a global package

πŸ—οΈ Using your own packages in project

πŸš€ Using npx

npx allows running Node.js packages without globally installing them. Useful for:

  • Running CLI tools like Angular CLI without global installation.
  • Quickly testing packages.
  • Ensuring the latest version of a tool is used.

πŸ“Œ Example Usage

npx ng new my-angular-app

πŸ” How npx Works

  • It checks if the package exists locally in node_modules.
  • If not found, it temporarily downloads and caches the package.
  • Once the command execution completes, the temporary files are cleaned up automatically.

🌐 Installing from Different Sources

πŸ–₯️ Installing from a GitHub Repository
npm install https://github.com/expressjs/express.git
πŸ“‚ Installing from a Local Folder
npm install ../my-local-package
πŸ”— Linking Local Packages (for development)
cd my-local-package
npm link
cd ../my-main-project
npm link my-local-package
πŸ“‹ Verifying Linked or Installed Packages

To check if a package has been linked or installed correctly, use:

npm list --depth=0

This will display linked dependencies and installed packages at the top level.


🏠 Using Workspaces (for Monorepos)

Workspaces help manage multiple related packages in a monorepo setup.

  • Easier dependency sharing across projects.
  • Simplified development of interdependent libraries.
  • A single node_modules for efficiency.

πŸ“Œ When to Use Workspaces

  • When managing multiple packages that need to interact frequently.
  • When developing a plugin-based architecture.
  • When optimizing package management for better performance.

βš™οΈ Setting Up a Workspace

npm init -w packages/my-package
npm install lodash -w my-package

πŸ”„ Reflecting Changes in the Main Project

If you modify a package within a workspace, ensure the main project reflects those changes by running:

npm update -w my-package
npm init -w packages/my-package
npm install lodash -w my-package

πŸ“ Using npm Scripts

Scripts allow you to define command-line tasks in package.json. βš™οΈ

πŸ“Œ Standard vs Non-Standard Scripts

  • Standard scripts like start and test can be run without run:

    npm start
    npm test
    
  • Non-standard scripts require run:

    npm run lint
    npm run build
    

Scripts allow you to define command-line tasks in package.json. βš™οΈ

{
  "scripts": {
    "start": "node server.js",
    "test": "jest",
    "lint": "eslint ."
  }
}

πŸ“€ Publishing Your Own Package


πŸ”‘ Setting Up npm User

npm login

πŸ“¦ Preparing a Package

Ensure package.json contains:

  • name (unique package name)
  • version (semantic versioning: major.minor.patch)
  • main (entry file, e.g., index.js)

πŸ“’ Publishing a Package

🏷️ Releasing Beta Versions

If you need to publish a pre-release or beta version before a stable release, you can do so by tagging it as a beta:

npm version prerelease --preid=beta  # Creates a version like 1.0.1-beta.0
npm publish --tag beta

This allows users to install the beta version specifically:

npm install my-package@beta

When the beta is stable, you can publish the final version by running:

npm version patch  # Move to the next stable version
npm publish
npm publish

πŸ”„ Updating a Published Package

πŸ”– Managing Versions with npm version and Git Tags

Before publishing a new version, it's essential to update the version number. The npm version command automates this:

npm version patch  # Increment patch version (e.g., 1.0.0 β†’ 1.0.1)
npm version minor  # Increment minor version (e.g., 1.0.0 β†’ 1.1.0)
npm version major  # Increment major version (e.g., 1.0.0 β†’ 2.0.0)

This command:

  • Updates the version in package.json.
  • Creates a Git tag with the new version.
  • Commits the changes automatically.

πŸ“Œ Pushing the Git Tag to Remote Repository

To share the version update with others, push the tag to the remote repository:

git push origin --tags

This ensures that your Git history reflects the published package versions.

πŸ“’ Publishing a Package

Once the version is updated, publish the package to npm:

npm publish

πŸš€ Steps for a Smooth Publish

  1. Ensure your package follows npm guidelines.
  2. Run npm test to verify functionality.
  3. Update the version using npm version.
  4. Push the changes and Git tags to remote.
  5. Publish using npm publish.

πŸ“’ Unpublishing a Package

If you need to remove a package version, use:

npm unpublish --force

Note: npm has strict rules about unpublishing to prevent breaking dependencies.

npm version patch  # Increment patch version
npm publish

πŸ” Security and Best Practices


⚠️ Beware of Typosquatting and Malicious Packages

One common security risk when using npm is typosquattingβ€”attackers create malicious packages with names similar to popular ones. If you accidentally mistype a package name, you could install a harmful package instead of the intended one. πŸ›‘

Example of a risky situation:

npm install reacte # Incorrect (could be a malicious package)
npm install react  # Correct βœ…

To prevent this:

  • Double-check package names before installing.
  • Verify package authors and download counts on npmjs.com. πŸ”
  • Use **npm audit** regularly to detect potential security vulnerabilities.
  • Lock dependencies with package-lock.json to prevent unintended upgrades to malicious versions.

πŸ›‘οΈ Checking for Security Vulnerabilities

npm audit

πŸ› οΈ Automatically Fixing Security Issues

npm audit fix

🏁 Conclusion

  • npm is an essential for managing JavaScript dependencies efficiently. πŸ“Œ
  • Understanding package.json, dependencies, versioning, and scripts is crucial. πŸ“œ
  • Keeping dependencies updated and using security tools like npm audit ensures project safety. πŸ”
  • Publishing your own packages enables code reuse and sharing within the JavaScript community. πŸš€

This structured guide provides a detailed yet easy-to-follow reference for JavaScript package management using npm. 🌟✨