In a Node environment or a project with a package.json, it's very common to have a "scripts" field in package.json. It lists the scripts available to build, test, and run the project.
To see which scripts are available without opening package.json in an editor, yarn and npm provide commands that list them: yarn run and npm run.
Depending on whether you use npm or yarn, the command either lists the scripts or opens a prompt where you can enter the command you want to run.
This is the output from a recently created expo app:
yarn run v1.22.4
info Project commands
- android
expo start --android
- eject
expo eject
- ios
expo start --ios
- start
expo start
- web
expo start --web
question Which command would you like to run?:It's very handy. You get a fast lookup instead of spending energy trying to remember the commands. But it's very slow (around 250ms!) because it needs to start a node process, parse the json file, and send output to stdin. The UX could be better, too, because it forces you to type the command again.
I was a little frustrated, so I created a small bash script to solve it. It's aliased to run in my local environment, and it works like this:
yarn-run.gif
It uses fzf to filter the available commands and search them quickly. If you don't know what fzf is, I can't recommend taking a look at it enough. fzf stands for fuzzy finder. With fzf's shell integration enabled, I use CTRL+R to navigate my shell history; fzf is also commonly used to navigate files in an editor.
fzf.gif
What's the script about
if cat package.json > /dev/null 2>&1; then
scripts=$(cat package.json | jq .scripts | sed '1d;$d' | fzf --height 40%)
if [[ -n $scripts ]]; then
script_name=$(echo $scripts | awk -F ': ' '{gsub(/"/, "", $1); print $1}')
print -s "yarn run "$script_name;
yarn run $script_name
else
echo "Exit: You haven't selected any script"
fi
else
echo "Error: There's no package.json"
fiThis can be intimidating at first, so let's break it down and explain what each command does.
The first interesting bit previews the content of package.json in an fzf menu.
cat package.json | jq .scripts | sed '1d;$d'
cat package.json prints the content of package.json.
jq .scripts parses the json and selects only "scripts".
sed '1d;$d' removes the first and last lines.
"predeploy": "yarn build",
"deploy": "gh-pages -d public",
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write src/**/*.{js,jsx}",
"start": "npm run develop",
"serve": "gatsby serve",This output gets passed to fzf, which creates the floating menu. Once you select a row, the $script value is set to "start": "npm run develop". The script then gets the command name "start", saves that command to the history, and finally runs "yarn run start".
I appended
yarn runinstead ofyarn start, which is also valid, to avoid shadowing any binary.
Custom
This script lives in my dotfiles repo, which is an easy way to install and set up your environment each time you change laptops.
Feel free to change this script to use npm or make any other changes. I've found playing with my terminal very rewarding. Learning more about the tools I use every day has let me do things I couldn't do before, and those small performance boosts have made my life a little easier. I'll keep sharing more as they pop into my head.
Resources
- For an introduction to fzf, see this blog post
- My personal setup, davesnx/setup, uses zsh
- If you aren't familiar with dotfiles, this should provide a little clarity
- For Spanish speakers, I found this course amazing