Published
- 3 min read
Writing Shell Scripts in JavaScript with ZX
Photo by JÉSHOOTS from Pexels
I was working in the past on a project, that was still requiring us to do manual releases. We followed a short guide consisting of Terminal commands. Only a minor adjustment was needed for each new release. We could have greatly benefited from writing a simple bash script. However I am not a sysadmin and tend to rarely write shell scripts. It would take way too much time to debug and create a working bash script. We decided copy and pasting code is just more efficient.
Luckily the developers at Google also did not want to write bash scripts. However apparently they got the resources to create something even better:
zx - A tool for writing better scripts
It allows you to combine JavaScript with the Bash commands to create complex scripts. At its core its just a simpler wrapper syntax for working with NodeJS child_process
.
The Release Script
Our build steps are basically:
- Bump the version in package.json with the command
npm version patch
- Pass the new version number to the releaseCMD
The reason to do this manually was that there is no easy way to read the new version number from the package.json
to store it in a variable to pass it into the releaseCMD
The ZX Script
Output Text to the console
Its always useful to output stuff to the console. You can simply use console.log("Hello")
to output text on the console.
Execute Commands
As alternative if you want to execute any terminal command like echo
to output text. You write it as
$\``echo Hello
Read JSON
The Github Page of ZX has a list of typical commands and examples what you can do with them. One of them is to read the package version
const { version } = await fs.readJson("./package.json");
Let’s put it all together
I created a directory scripts
that will contain all the future projects scripts and created the file release.mjs
/scripts/release.mjs
console.log('Running Release Script')
await $`npm version patch` // Bumps package version
const { version } = await fs.readJson('./package.json') // Reads new package version
try {
await $`echo releaseCMD -version ${version}` //Replace with actual command
} catch (p) {
console.log(`Error: ${p.stderr} ExitCode ${p.exitCode}`) //Logs Error to the terminal
}
Executing the Script
You either can install zx globally with the command
npm i -g zx
or you can run it with npx zx <scriptname>
.
Personally as soon as I am done with the script I don’t want to deal with this anymore. I want that every team member can use the script without any explanation.
Thus I added it as a script in package.json
/package.json
{
"scripts": {
"release": "npx zx ./scripts/release.tjs"
}
}
Now you can run it like any other script npm run release
Conclusion
Unfortunatly I did not have a lot of time to play around with ZX. I am sure that it is capable of creating very complex scripts.
For my usecase I did not look into executing scripts as an admin, or creating cross platform scripts etc. Again I am not a sysadmin.
In the end, I think ZX is a great way of creating shell scripts without having to deal with BASH. Thus with your TypeScript/JavaScript knowledge you can quickly create scripts to automate the boring stuff.