Mastering npm Query Command (with examples)
The npm query command is a powerful tool integrated within Node Package Manager (npm) that allows developers to query and analyze the package dependencies of a Node.js project using selectors similar to CSS. This command helps manage project dependencies by listing them in various customized ways. Here’s a closer look at how this command can be creatively used in different scenarios.
Use Case 1: Print Direct Dependencies
Code:
npm query ':root > *'
Motivation:
In large projects with numerous packages, identifying direct dependencies—i.e., those dependencies listed directly in package.json
—is a common requirement. This keeps developers informed of the immediate packages their application relies on, especially during audits or when planning updates.
Explanation:
:root
indicates the root of the package tree, which corresponds to the project itself.>
is a direct child selector indicating that only the direct children of the root should be considered.*
selects all elements, in this case, all direct dependencies of the project.
Example Output:
[
{
"name": "express",
"version": "4.17.1"
},
{
"name": "lodash",
"version": "4.17.21"
}
]
Use Case 2: Print All Direct Production/Development Dependencies
Code:
npm query ':root > .prod|dev'
Motivation:
Differentiating between production and development dependencies is crucial for deployment and environment setup. By listing these dependencies separately, developers can streamline their operations for building and deploying applications efficiently.
Explanation:
:root >
operates just like the previous example, targeting direct dependencies..prod|dev
filters the selection to include only production (.prod
) and development (.dev
) dependencies.
Example Output:
[
{
"name": "express",
"version": "4.17.1"
},
{
"name": "chai",
"version": "4.2.0"
}
]
Use Case 3: Print Dependencies with a Specific Name
Code:
npm query '#package'
Motivation:
This command is useful when you need detailed information about a specific package within your dependency tree. This can help in troubleshooting or understanding the particulars of why a package is included.
Explanation:
#package
selects a dependency by its name. Replacepackage
with the desired package name you want to query.
Example Output:
[
{
"name": "express",
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz"
}
]
Use Case 4: Print Dependencies with a Specific Name and Version Range
Code:
npm query '#package@semantic_version'
Motivation:
This query is valuable when you want to ensure compatibility by checking if a specific version or version range of a package is being used in your project or if there are potential mismatches that could cause issues during runtime.
Explanation:
#package@semantic_version
specifies the package name and the version or version range (e.g.,express@^4.16.0
), allowing you to query packages according to version constraints.
Example Output:
[
{
"name": "express",
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz"
}
]
Use Case 5: Print Dependencies Which Have No Dependencies
Code:
npm query ':empty'
Motivation:
Dependencies without further dependencies (leaf nodes) can be audited for updates or removals, minimizing bloat or simplifying the dependency tree. These packages often stand as singular elements in a setup and could be evaluated for updates or alternatives.
Explanation:
:empty
selects dependencies that have no child dependencies. This is equivalent to identifying packages that exist at the leaves of the dependency graph.
Example Output:
[
{
"name": "uuid",
"version": "8.3.2"
}
]
Use Case 6: Find and Uninstall All Dependencies with Postinstall Scripts
Code:
npm query ":attr(scripts, [postinstall])" | jq 'map(.name) | join("\n")' -r | xargs -I {} npm uninstall {}
Motivation:
Packages with postinstall scripts can introduce unwanted side effects when a project is installed or deployed. Identifying and potentially replacing or uninstalling them increases the predictability and security of your setup.
Explanation:
:attr(scripts, [postinstall])
filters packages to those that have postinstall scripts defined.- The command is piped (
|
) tojq
, which transforms the data into a list of package names. - This list is passed to
xargs
which feeds these names tonpm uninstall
to remove each package found.
Example Output:
removed 2 packages in 0.489s
Use Case 7: Find All Git Dependencies and Determine Which Application Requires Them
Code:
npm query ":type(git)" | jq 'map(.name)' | xargs -I {} npm why {}
Motivation:
Dependencies pulled directly from Git repositories might indicate development dependencies, forks, or unvetted packages. Knowing which part of the application requires them is beneficial for assessing the need for these dependencies and ensuring stability.
Explanation:
:type(git)
queries all dependencies that are Git-based rather than from a registry.- The result is processed with
jq
to extract the package names. npm why
checks and explains why each of these dependencies is included in your project.
Example Output:
eslint:
git+https://github.com/eslint/eslint.git
is a devDependency of this package
Conclusion:
The npm query command alongside powerful chaining through other tools like jq and xargs provides deep insights and control over package dependencies in a Node.js project. By leveraging these use cases, developers can efficiently manage, audit, and optimize their project’s dependency landscape.