Data report"State of code review 2024" is now liveRead the full report

npm continuous integration

Kenny DuMez
Kenny DuMez
Graphite software engineer

Continuous integration (CI) is an important part of modern software development, especially for projects using npm (Node Package Manager) to manage JavaScript dependencies. Implementing CI in npm projects can help automate testing, improve code quality, and streamline the deployment process. This guide will explore setting up a robust CI pipeline for an npm-based project, from basic setup to optimization techniques.

Start by selecting a CI service that integrates well with your version control system (e.g., GitHub, GitLab, Bitbucket). Popular options for CI services include:

Create a configuration file in your repository (e.g., .github/workflows/node.js.yml for GitHub Actions) that defines the pipeline’s steps. Here's a basic example for a GitHub Actions workflow:

Terminal
name: Node.js CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test

This script sets up a job that triggers on pushes and pull requests to the main branch, checks out the code, sets up Node.js, and runs the npm ci, npm run build, and npm test commands.

Use npm ci instead of npm install in your CI pipelines. npm ci installs dependencies directly from the package-lock.json file, ensuring consistency across installations and speeding up the setup process.

  • Understanding package-lock.json:

    • The package-lock.json file is an automatic record generated by npm (Node Package Manager) whenever a node project is initialized or whenever dependencies are modified (added, updated, or removed). This file locks down the exact versions of each installed package and its dependencies, which npm resolved at the time of generation.
    • By doing so, package-lock.json ensures that the same versions of the packages are used every time the project is installed, regardless of when and where it is installed. This eliminates discrepancies in package versions that might occur due to version updates or dependencies' version ranges specified in package.json.
  • Advantages of npm ci:

    • Consistency: npm ci will reference the package-lock.json to install exactly the same dependencies that were installed initially, ensuring that every install results in the same file structure in node_modules across all your environments—from development to production. This avoids issues where an update to a package could potentially introduce bugs that were not present at the time of initial development.
    • Speed: Since npm ci bypasses the dependency resolution step and copies or downloads fixed versions, it is generally faster than running npm install. This is particularly beneficial in CI pipelines, where reducing the build time can significantly impact overall workflow efficiency.
    • Clean state: npm ci starts by removing the existing node_modules directory, if present, ensuring a clean slate before installing the specified versions of dependencies. This prevents any residual or corrupted packages from affecting the new installation.
  • Using npm ci in CI pipelines:

    • To implement npm ci in your CI pipeline, replace any npm install commands with npm ci. Ensure that your package-lock.json file is included in your version control system (such as Git) to maintain consistency across all clones of the repository.
    • When your CI pipeline runs, it will execute npm ci, which utilizes the package-lock.json to install dependencies. This ensures that every build in your CI process uses the exact same set of dependencies, mirroring your development environment and reducing the likelihood of "it works on my machine" issues.

Integrating npm ci into your CI pipelines leverages the deterministic nature of package-lock.json to enhance the reliability and performance of your development and deployment processes.

Most CI services allow you to cache files or directories between runs. For npm, you can cache the node_modules directory to speed up installation steps. Here’s how you can add caching to the GitHub Actions workflow:

Terminal
steps:
- uses: actions/checkout@v2
- name: Cache node modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test

Caching in CI/CD pipelines stores frequently accessed data such as dependencies in a cache layer to reduce retrieval times in subsequent runs. In this workflow, caching is implemented by storing the ~/.npm directory based on a key derived from the package-lock.json file, allowing subsequent workflow runs to quickly restore and reuse the previously downloaded npm packages without re-downloading them, thus speeding up the build process.

Expand your CI pipeline by integrating other types of tests like linting, security scans, and performance tests. Tools like ESLint for linting, npm audit for security checks, and Lighthouse for performance testing can be added to your workflows as additional steps.

Setting up continuous integration for your npm project can significantly enhance the quality and reliability of your software. By automating tests and deployments, you can ensure that each change made to your codebase is validated before deployment, leading to more stable and reliable applications. Regularly revising and updating your CI pipeline configurations to adapt to new npm features and best practices helps make sure your codebase stays up to date and secure.

Git gud
"It's the first Git workflow I've used that actually feels good."
–@robboclancy
Learn more

Graphite
Git stacked on GitHub

Stacked pull requests are easier to read, easier to write, and easier to manage.
Teams that stack ship better software, faster.

Or install our CLI.
Product Screenshot 1
Product Screenshot 2