Interacting with JSON data and package.json files

Now that we know how to write and execute our own scripts, it's time to move into building out a little arsenal of tools that we can re-use in different web projects. Most useful are scripts that can be universally applied, regardless of the frameworks we use in our projects or that help us automate tasks that would otherwise be repetitive or time-consuming.

One great tool that doesn't come pre-installed is jq — it allows us to interact with JSON data by parsing it into a bash array which we can then iterate over like we've done before when we looked at basic loops. In order to use jq on the command line or in our scripts, we first need to install it from the official site.

Once you have it installed, we can immediately use it in our scripts. Let's look at a basic example, where we provide the JSON data in form of a simple string. We're piping the JSON string to jq, which filters out and returns the according value to the name property that we are looking for.

command line
echo '{ "name": "Loki" }' | jq '.name'
Loki

Reading dependencies from a package.json file

Now that we have a basic understanding of how jq works, let's combine it with pipes and loops, like previously learned, so we're able to loop over every single dependency in the package.json.

command line
for dep in $(jq -r '.dependencies | keys | .[]' package.json); do
echo $dep
done

The -r flag tells jq to return raw output, which helps us deal with quotes in the JSON data and is especially useful when piping the output to other commands. The built-in keys function returns all dependencies keys as an array, ordered alphabetically.

Now demonstrate how useful this little script can really become, let's try finding all dependencies that are not imported in a modern JavaScript codebase, but installed according to our package.json.

command line
for dep in $(jq -r '.dependencies | keys | .[]' package.json); do
if ! grep "from .*$dep.*" -Rq --exclude-dir="node_modules" ./src; then
echo "Likely unused: $dep"
fi
done

We're using the simple loop we already used above but instead of just listing all dependencies, we're now utilizing grep to search through all files in our ./src directory. The pattern we're searching for in this case is "from '<dependency>'" like it's commonly used to import scripts in JS.

We're replacing <dependency> with the actual values (packages) from our package.json and can use the flags -Rq to make the command recursive and quiet, so it only prints something to the console if the condition is met. the last flag allows us to exclude the node_modules folder from our grep command, so we don't get any false positives by looking in there.

And just like that, we have a re-usable script that can tell us when a package was installed by not used anywhere in our codebase, so we can likely remove it, which might lead to improved build times 🎉