Updating NPM Packages: Tools and Strategies

Keeping our frontend dependency for a big front-end project can be a daunting task. It can get challenging and when this happen we better have strategy in place to ease the process. This article intends to describe some strategies and tools that we can use to help us ease the process of keeping our NPM packages and other front-end dependencies up to date.

Why is it important to ask questions first before trying to update our npm packages?

Updating npm dependencies is a significant task that can potentially impact many parts of your application. In this situation it’s better to stop and analyze and ask questions before actually starting the upgrade. Below, I’ll describe some more reasons why it’s a better idea to ask questions and analyze before starting the upgrade.

  1. Impact Analysis: Updating a dependency may impact multiple parts of your application. Asking questions about the use and impact of a dependency throughout your codebase can help prevent unexpected side-effects.
  2. Breaking Changes: If the new version of the dependency includes breaking changes, your code may no longer work as expected. Asking questions about the nature of the update (is it a major, minor, or patch update?) can help you anticipate potential problems.
  3. Dependency Chains: Some of your dependencies might rely on other dependencies. Updating one could potentially break another if they are not compatible. You need to understand these relationships before updating.
  4. Benefit Analysis: What benefits will the update bring? Will it fix a bug you’re experiencing? Will it add new features that your application needs? You want to be sure the benefits outweigh the potential risks.
  5. Test Coverage: Do you have good test coverage for the parts of your code that use this dependency? This will determine how confident you can be that your updates haven’t broken anything.
  6. Rollback Plan: If things go wrong, how easy is it to roll back the update? Are there automated systems in place, or would it require manual intervention?
  7. Documentation & Community Support: Is the documentation for the new version sufficient? Is there community support available if you encounter issues?
  8. Development & Production Environment: Will the update have any effect on your development, testing, staging, or production environments? Does the update need specific infrastructure requirements?

What questions we should ask before trying to update our npm packages?

When planning to update the npm packages for a front-end project, there are many good questions to ask and answer to ensure the update process goes smoothly and does not introduce bugs or unexpected behavior. Here are a few examples:

What versions of the packages are we currently using?

Understanding the current versions helps to identify which packages are outdated and need updates.

What are the latest versions of the packages, and what changes do they bring?

Knowing the latest versions and the changes they introduce is essential. You can usually find this information in the package’s changelog or release notes.

What new features, fixes, or improvements do these updates bring?

Sometimes, updates come with new features or improvements that might be beneficial for your project. Understanding these changes can help you leverage them for your project.

Are there any breaking changes in the updates?

If the update introduces breaking changes, you’ll need to adjust your code to accommodate these changes, or consider holding off on the update if the changes are too disruptive.

Will the update maintain compatibility with our project’s existing code?

It’s crucial to ensure that the updated packages will remain compatible with your existing codebase, or to identify necessary changes to maintain compatibility.

What are the dependencies and peer dependencies of the updated packages?

Some packages may have dependencies on other packages, and those dependencies also might need to be updated.

How well are the packages maintained?

If a package is poorly maintained, updating it might introduce more issues than it resolves, particularly if there are known bugs in the update.

Do we have a solid test suite to catch potential bugs after the update?

Having a solid set of tests is crucial when updating dependencies. You can run these tests after the update to verify that everything still works as expected.

What is the rollback plan if the update causes issues?

It’s essential to have a plan for quickly reverting the updates if they cause unforeseen issues.

Is there a need for this update?

It’s worth asking whether the update is necessary. Sometimes, updating just for the sake of having the latest version might not be worth the potential risks, particularly if the current version is working well.

Tools available to help us with the npm packages updating process

Now that we’ve asked some important questions, let’s see what tools or options we have to help us answer those questions. There are a variety of tools available to help manage and upgrade npm packages. These tools can help automate the process of updating npm packages, make it easier to spot outdated dependencies, and also help identify potential security vulnerabilities in your dependencies.

Command Line Tools

  1. npm: npm itself provides commands to update packages. You can use npm outdated to see which packages have updates available, and then npm update to update them.
  2. yarn: Similar to npm, yarn provides commands to upgrade packages. The yarn upgrade command updates packages to their latest version based on the version range specified in the package.json file. And yarn upgrade-interactive command allows you to choose which packages to upgrade. Both npm and yarn are package managers for the Node.js runtime environment and provide almost the same features. However, they have slight differences in terms of performance and how they handle dependencies.
  3. npm-check-updates (ncu): This is a command-line utility that will update your package.json dependencies to the latest versions, respecting the existing version constraints. You can install it globally with npm install -g npm-check-updates.
  4. npm-check: This tool allows you to check for outdated, incorrect, and unused dependencies. It can be installed globally with npm install -g npm-check.

Bots

  1. Dependabot: This is a bot provided by GitHub that automatically opens pull requests on your repository when it detects outdated dependencies. It supports private repositories and can be configured via a config file in your repository.
  2. Renovate: Renovate is another bot similar to Dependabot that can automatically update dependencies in your project. It also supports a wide range of languages and package managers, including npm.
  3. Greenkeeper: This is another bot that helps keep your dependencies up to date. It works by monitoring your package.json file and opening pull requests whenever dependencies need to be updated.

Web Tools

  1. Snyk: Snyk is a web tool that not only helps keep your dependencies up to date, but also checks them for security vulnerabilities. It can be integrated with your GitHub repository and can open pull requests with updates.
  2. David: David is a web tool that shows you the outdated dependencies in your project. You can use it by visiting https://david-dm.org/<your GitHub username>/<your repository name>.

How to use Semantic versioning, or SemVer in our npm package update process

Semantic versioning, or SemVer, is a system for versioning software that aims to convey meaning about the underlying changes in a release. It uses a three-part versioning scheme in the format X.Y.Z, where X represents the major version, Y the minor version, and Z represents the patch version. Here’s what each part signifies:

  1. Major (X): Breaking changes are made; the API changes in a way that is not backward-compatible.
  2. Minor (Y): New features are added in a backward-compatible manner.
  3. Patch (Z): Backward-compatible bug fixes are introduced.

This information can be incredibly helpful when trying to manage and update your npm packages. Here’s a strategy you could use to decide what to update:

  1. Patch updates (Z): Generally, it’s safe to update packages that only have patch version updates. These are supposed to be only bug fixes and shouldn’t introduce any new functionality or breaking changes. Therefore, they should be safe to update at any time.
  2. Minor updates (Y): Minor updates add new functionality but should do so in a backwards-compatible way. You can usually safely update packages with minor version updates, but it’s a good idea to check the release notes first to see what has changed.
  3. Major updates (X): Major version updates can introduce breaking changes, so these should be approached with caution. Before updating a package with a major version change, you should thoroughly read the release notes and potentially even test the update in a separate branch or environment. Depending on the complexity of the package and how heavily your project relies on it, you may even want to allocate time for potential necessary code changes.

By following these guidelines, you can use SemVer to keep your npm packages updated while minimizing the risk of introducing breaking changes into your project. npm also uses a special symbol called the caret (^) in its package.json file to automatically update minor and patch versions of packages.

Furthermore, using the npm outdated command or ncu from npm-check-updates package can give you an overview of which packages are outdated in your project. It’ll show the current version your project uses, the highest version available that’s covered by your SemVer rule in the package.json, and the latest version available on npm.

Always remember, no matter the version update, proper testing should be carried out to ensure everything works as expected before deploying to production. It’s also a good practice to use continuous integration (CI) systems to run your test suite whenever your dependencies are updated.

Handle Major Version Updates Carefully

Be cautious when updating dependencies to a new major version as they often contain breaking changes. Always read the changelog for the dependency before updating and ensure you have a good set of tests to catch any issues.

Updating NPM packages

Now that we ask some questions and have some tools to help us, let’s dev into the technical detail of actually updating our packages. Updating NPM packages efficiently can be quite a challenge, especially when working with a large codebase with multiple dependencies. Here are the steps you can take to efficiently update your npm packages using yarn, npm-check-updates (ncu), npm-check, and Dependabot.

1 – Identify outdated packages:

You can use either npm-check or npm-check-updates (ncu) to identify outdated packages. You can also use yarn outdated if you prefer yarn.

  • npm-check:
command to run
npm install -g npm-check
npm-check -u

The -u option will run the update interactive UI.

  • npm-check-updates:
command to run
npm install -g npm-check-updates
ncu

This will show you a list of dependencies with newer versions.

  • yarn:
command to run
yarn outdated

This will display a table in the terminal, showing the current version you’re on, the latest version and the package type.

2 – Update packages:

  • You can update your packages with npm-check by selecting the ones you want in the interactive UI.
  • With npm-check-updates, you can upgrade your package.json file to use the latest versions by running:
command to run
ncu -u

Then run npm install or yarn install to update your node_modules folder. Sometimes it’s necessary to run these command with arguments -force or –legacy-peer-deps in order to ignore the errors or force the installation related to incompatible peer dependencies. In case you encounter conflicts between package versions, you can use the npm ls or yarn list command to see a tree view of your package dependencies. This command will help you identify which packages depend on which versions of other packages, making it easier to identify the root of the conflict.

  • With yarn, you can update to the latest major version with:
command to run
yarn upgrade <package-name>

Or a specific version with:

command to run
yarn upgrade <package-name>@<version>

3 – Automate package updates with Dependabot:

Once we moved our repos to git, we can start using Dependabot to automate some of the package update effforts. Dependabot is a tool provided by GitHub which checks for updates on your dependencies and opens a pull request if it finds one. You can configure Dependabot by adding a configuration file .github/dependabot.yml to your repository. Here is an example of how you can configure it:

dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "daily"
    open-pull-requests-limit: 10

This configuration checks daily for npm updates at the root of the repository and limits the number of open pull requests to 10.

4 – Use npm audit for security:

npm audit is a built-in command since npm v6. It analyzes your dependency tree and helps you identify and fix known vulnerabilities in the packages you are using.

5 – Use tools for handling updates in monorepos:

If you’re working with a monorepo (multiple packages in the same repository), tools like Lerna or Yarn Workspaces can be very useful for managing package updates.

6 – Test thoroughly:

After every update, make sure to test your application thoroughly. Automated tests, if available, can be a great help. Be aware of major updates (as indicated by semantic versioning) as they may contain breaking changes.

7 – Regularly repeat the process:

Keeping your packages up-to-date is an ongoing process that should be repeated regularly. Using automation tools like Dependabot can help with this, but you should still manually check for updates regularly.

Importance of having a .npmrc file in our project

The .npmrc file is a configuration file for NPM (Node Package Manager), which is used extensively in Node.js development. This file can be located in several places depending on the scope of the configuration. Having a .npmrc file is important for several reasons:

  1. Custom Configuration: It allows you to customize how NPM behaves. You can use it to define the default registry, set a different directory for package installations, configure proxy settings, and so on. You can use different .npmrc files for different projects, enabling project-specific configurations.
  2. Authentication: It allows you to authenticate with private registries or scoped packages. If you’re using private modules or scoped packages, you’ll need to authenticate with the registry to install them. An auth token will be added to your .npmrc file when you log in.
  3. Environment Variables: It can reference environment variables for sensitive data, which can be essential for continuous integration/continuous deployment (CI/CD) pipelines. This helps maintain security by preventing the inclusion of sensitive information, like access tokens, in the codebase.
  4. Improved Performance: You can also set cache parameters to improve performance. You can specify the location of your cache, the maximum cache size, and the minimum time-to-live of cache data before it’s considered stale.
  5. Dependency Resolution: Helps with the resolution of dependencies. For instance, you can ensure that everyone on your team is pulling packages from the same source, which can be helpful to avoid potential inconsistencies.

It is also important in term of security, here’s some of the things it can help with:

  • Private Modules / Scoped Packages: If you’re using private modules or scoped packages in your project, you’ll need to authenticate with the registry to install them. In this case, an auth token will be added to your .npmrc file when you log in via npm login. This token should be treated like a password, and not committed to your version control system. Instead, use environment variables to provide the token where necessary, for example in a CI/CD pipeline.
  • Registry Configuration: For security reasons, it’s recommended to use a secure registry (https://) in your .npmrc file. This helps ensure that your packages are downloaded securely.
  • Sensitive Data: No sensitive data should be stored in the .npmrc file. If there is a need for sensitive data, it should be stored in environment variables and not in the file itself.

Now that we know what .npmrc file can do, let’s see a basic example of the things contained in this file:

.npmrc file
# registry to download packages from
registry=https://registry.npmjs.org/


# scope for the packages
scope=your-company-name


# auth token
//registry.npmjs.org/:_authToken=${NPM_TOKEN}


# strict-ssl
strict-ssl=true


# cache settings
cache=/home/user/.npm
cache-min=10
cache-max=Infinity


# log level
loglevel=warn

In this file:

  • ${NPM_TOKEN} is an environment variable that contains your auth token. You would typically set this in your shell profile file or in the environment variables section of your CI/CD settings.
  • strict-ssl=true ensures that an SSL certificate is always required to make a network connection.
  • The loglevel option sets the level of logging NPM will produce. Possible values are “silent”, “error”, “warn”, “notice”, “http”, “timing”, “info”, “verbose”, “silly”.
  • The cache options are setting where npm will store packages and how long before npm considers a cached package outdated.

Checking for Security vulnerabilities when updating npm packages

I think it’s beneficial to also be mindful of any security vulnerabilities that already exist in package in our project. Also updating a package might bring with itself a security vulnerability, so it’s better to be mindful of that before attempting an upgrade. Below I’ll list some suggestions and ways we can increase the security of our npm packages.

  1. Using yarn audit Commandyarn audit is a built-in command in Yarn which checks for vulnerabilities in your project dependencies. This command will give you a report of known vulnerabilities, their severity, and some tips on how to resolve them. It is a good practice to run yarn audit regularly to keep track of the state of your dependencies.
  2. Check the Dependencies Before Adding Them: Before adding a new package to your project, check its details on the yarnpkg.com website or npmjs.com. Look at the package’s maintenance frequency, popularity, and open issues. Packages with recent updates and large numbers of weekly downloads are usually safer.
  3. Keeping Dependencies Up-To-Date: Many security vulnerabilities are fixed in newer versions of packages. It’s essential to regularly update your dependencies using commands like yarn upgrade.
  4. Automatically Fix Vulnerabilities: After running yarn audit, you can upgrade packages to automatically install compatible updates to vulnerable dependencies. If a fix isn’t available, yarn audit will give instructions on what to do next.
  5. Using a Dedicated Security Tool: There are several tools and services that can help automate the process of checking for security vulnerabilities. These include SnykDependabot, and Whitesource Bolt. These tools integrate with your development workflow and provide real-time alerts about vulnerabilities, along with solutions to fix them.
  6. Locking Down Versions with yarn.lock: This file locks the versions of your project’s dependencies, which helps to avoid unexpected updates that could introduce vulnerabilities.
  7. Using Private Yarn Registries: If your organization has sensitive code or can’t risk using public packages, you might want to consider using a private Yarn registry.
  8. Running Static Code Analysis: Tools such as ESLint, SonarQube, and others can help you identify code patterns that could lead to vulnerabilities.
  9. Avoiding Execution of Untrusted Code: Try to avoid using Yarn packages that require preinstall or postinstall scripts, which execute when the package is installed. These scripts can be a source of vulnerabilities if the package is compromised.
  10. Setting up Automated CI/CD Pipeline Scans: As part of your continuous integration/continuous deployment (CI/CD) pipeline, include stages that run yarn audit and other security checks to catch vulnerabilities before they make it to production.

Other general advice that might be useful when updating npm packages

Lock Files: Ensure you’re using a lockfile, like package-lock.json or yarn.lock. This file is automatically generated and should be committed to your version control system. It describes the exact tree that was generated when you last ran npm install or yarn install respectively. This ensures that everyone working on the project is using the same versions of dependencies.

Resolve Conflicts: If two packages depend on different versions of the same package (known as a diamond dependency problem), npm v7+ automatically attempts to resolve the conflict. If it’s unable to find a version that satisfies both, it will install multiple versions. Try to resolve these conflicts where possible by updating the package that has the lower version dependency.

Understanding Your Dependency Tree: Before you begin updating, it’s crucial to understand your dependency tree. You can use npm ls or yarn list to see a tree of your dependencies and their respective versions.

Keep Your yarn.lock File: This file is automatically generated by Yarn, and ensures that the exact same versions of packages are installed every time yarn install is run. This helps keep your environments consistent and your builds reliable.

Regularly Check for Vulnerabilities: Regularly run yarn audit to check for new known vulnerabilities in your packages.

Regularly Update Packages: Keeping your packages updated can help ensure you have the latest features and security patches.

Use Scoped Packages for Private Code: If you’re developing code that shouldn’t be publicly available, consider using scoped packages. These allow you to specify a namespace for your packages, and can be published to a private registry

Update only one package at a time: Updating multiple packages at once can be risky because it can cause conflicts between different versions of dependencies.

Keep track of changelogs: Changelogs are documents that describe what has changed between different versions of software. Keeping track of changelogs can help you understand what has changed between different versions of your dependencies.

Only update packages that you know are safe to update: Before updating a package, always read the release notes to make sure that there are no known issues. You can also check the package’s issue tracker to see if there have been any reports of problems.

Use a version control system like Git to track your changes: This will make it easy to revert to a previous version if something goes wrong with an update.

Document your changes: Keep a record of which packages you updated and the versions that you used. This will make it easier to track down problems in the future.

Set up a continuous integration (CI) pipeline: This will automatically build and test your project after each update. This will help you to catch any problems early on.

Separate branch for package update: Package updates should ideally be done in a separate branch rather than directly in the main or master branch. This ensures the main codebase isn’t immediately affected by potential breaking changes.

Importance of review: Before pushing changes to the production environment, a thorough review of the code should be done to make sure there are no issues.

Summary

Managing frontend dependencies for a big project is a challenging task. In this article, we’ve explored strategies and tools to simplify this process and maintain our NPM packages and other frontend dependencies.

Before diving into an update, it’s essential to ask the right questions. This can help us assess potential impacts, anticipate problems related to breaking changes, understand dependency chains, analyze benefits, ensure adequate test coverage, plan rollbacks, and examine documentation & community support. Also, it’s important to review the effects on our development, testing, staging, or production environments.

Here are some key questions to consider:

  1. What versions of the packages are we currently using?
  2. What are the latest versions, and what changes do they bring?
  3. Are there any breaking changes in the updates?
  4. Will the update maintain compatibility with our existing code?
  5. What are the dependencies of the updated packages?
  6. How well are the packages maintained?
  7. Do we have a robust test suite?
  8. What’s the rollback plan if issues arise?
  9. Is the update necessary?

There are several tools available to assist in the updating process, including command line tools (npm, yarn, npm-check-updates, npm-check), bots (Dependabot, Renovate, Greenkeeper), and web tools (Snyk, David).

We also need to understand Semantic Versioning, or SemVer. It’s a versioning system that conveys meaning about the changes in a release (major, minor, and patch). The use of SemVer helps us decide what to update based on the type of changes made.

Finally, it’s essential to have a plan when updating NPM packages. This can involve identifying outdated packages, examining changelogs, updating packages, running tests, and checking your application in a real environment.

Remember, testing should be carried out to ensure everything works as expected before deploying to production. Also, a good practice is to use continuous integration systems whenever dependencies are updated. Be careful with major version updates as they often contain breaking changes. Always read the changelog before updating and make sure you have a good set of tests to catch any issues.

We also delved into the significance of the .npmrc file, a configuration file for Node Package Manager (NPM) that plays a crucial role in Node.js development. The .npmrc file enables customization of NPM behavior, helps in authentication with private registries, aids in referencing environment variables for sensitive data, and optimizes performance. It’s also key in dependency resolution and security.

I also touch upon the importance of being proactive with security vulnerabilities in our projects, especially when updating NPM packages. I share several strategies for enhancing the security of NPM packages, including frequent audits, thorough vetting of new packages, keeping dependencies up-to-date, using dedicated security tools, and employing private yarn registries.

Further, I provide some general advice on how to manage the upgrade of NPM packages. Emphasizing the importance of using a lockfile, understanding your dependency tree, and regularly checking for vulnerabilities. I also stress the significance of careful package updating, tracking changes, and setting up a CI pipeline to catch issues early on. Hopefully by the end of this post, you’ll have a arsenal of tools and strategies to ease the process NPM packages update.

Share...
 

Hamid Mosalla

Hi, I'm Hamid ("Arman"). I'm a software developer with 8+ years of experience in C#, .NET Core, Software Architecture and Web Development. I enjoy creating dev tools, contributing to open-source projects, and sharing insights on my blog. Outside of tech, I’m into indie cinema, classical music and abstract art.

 

Leave a Reply

Your email address will not be published. Required fields are marked *