I write node scripts that run from package.json and/or interface with utilities/binaries from npm packages mostly. Even for projects that aren't node, as it's installed everywhere.
Here's an example from an active mono-repo.
"husky": {
"hooks": {
"pre-commit": "node -r esm !main/scripts/run-child-npm-task precommit"
}
},
"scripts": {
"reset:db": "node -r esm !main/scripts/reset-db",
"build": "node -r esm !main/scripts/run-child-npm-task build",
"test": "node -r esm !main/scripts/run-child-npm-task test",
"first-init": "node -r esm !main/scripts/first-init"
}
A typical script for me has the following shell…
import path from "path";
import shell from "shelljs";
export async function main(skip) {
if (skip) return;
... work goes here ...
}
main(!!module.parent).catch(err => {
console.error(err);
process.exit((err && err.code) || 666);
});
Generally, path and shelljs are nearly always used, so I start with the above and add more as needed. the mz package has also been useful, but mostly replaced with internal options.