No installation or deps: if you use node, it's built-in!
Aware of context: your package.json and system
Shell, unlike BEST-NEXT-THING-SINCE-SLICED-BREAD.js, is a long term investment and will remain relevant in years to come
Simple for simple tasks
Powerful for complex tasks: running and composing commands is actually what shell is made for
Uses shell scripts and environment variables: mechanisms which are battle tested for decades now
Integrate seamlessly with CI and CLI apps
Neither is perfect, both beat JS at OS operations: files, streams, error handling, etc
Write business logic in general purpose programming languages, do systems stuff in shell
➜ mkdir fatigue-js; cd fatigue-js; npm init -y
Wrote to package.json:
{
"name": "fatigue-js",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test":
"echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
{
// ...
"scripts": {
"test":
"echo \"Error: no test specified\" && exit 1"
},
// ...
}
➜ npm run test
> echo "Error: no test specified" && exit 1
Error: no test specified
➜ npm run hello
> fatigue-js@1.0.0 prehello
> echo creating world...
creating world...
> fatigue-js@1.0.0 hello
> echo Hello, World!
Hello, World!
> fatigue-js@1.0.0 posthello
> echo destroying world...
destroying world...
"scripts": {
"prehello": "echo creating world...",
"hello": "echo Hello, World!",
"posthello": "echo destroying world..."
}
{
"name": "fatigue-js",
"version": "1.0.0",
// ...
"scripts": {
"prehello":
"echo preparing $npm_package_name@$npm_package_version...",
"hello":
"node -e 'console.log(`hello ${ process.env.npm_package_name }@${ process.env.npm_package_version }!`)'"
},
// ...
}
➜ npm run hello
> fatigue-js@1.0.0 prehello
> echo preparing $npm_package_name@$npm_package_version...
preparing fatigue-js@1.0.0...
> fatigue-js@1.0.0 hello
> node -e 'console.log(`hello ${ process.env.npm_package_name }@${ process.env.npm_package_version }!`)'
hello fatigue-js@1.0.0!
{
// ...
"config": {
"port": 3000
},
"scripts": {
"prestart":
"echo Checking port $npm_package_config_port availability...",
"start":
"node -e 'console.log(`Running on port`, process.env.npm_package_config_port)'",
"dev":
"npm --$npm_package_name:port=8080 run start"
},
// ...
}
➜ npm run start
> fatigue-js@1.0.0 prestart
> echo Checking port $npm_package_config_port availability...
Checking port 3000 availability...
> fatigue-js@1.0.0 start
> node -e "console.log('Running on port', process.env.npm_package_config_port)"
Running on port 3000
➜ npm run dev
> fatigue-js@1.0.0 dev
> npm --$npm_package_name:port=8080 run start
> fatigue-js@1.0.0 prestart
> echo Checking port $npm_package_config_port availability...
Checking port 8080 availability...
> fatigue-js@1.0.0 start
> node -e 'console.log(`Running on port`, process.env.npm_package_config_port)'
Running on port 8080
"config": {
"port": 3000
}
➜ eslint --version
zsh: eslint: command not found...
➜ npm install --save-dev eslint
fatigue-js@1.0.0 /home/code/fatigue-js
└── eslint@3.10.2
OK, let's see it... awkwardly?
➜ ./node_modules/eslint/bin/eslint.js --version
v3.10.2
➜ npm run lint -- --version
> fatigue-js@1.0.0 lint
> eslint "--version"
v3.10.2
{
// ...
"scripts": {
"lint": "eslint"
},
"devDependencies": {
"eslint": "3.10.2"
}
}
install
start
restart
stop
version
{
// ...
"scripts": {
"lint": "eslint",
"test": "jest",
"build": "webpack -p",
"prepublish":
"npm run lint && npm run test && npm run build"
},
"devDependencies": {
"eslint": "3.10.2",
"jest": "17.0.3",
"webpack": "2.1.0-beta.27"
}
}
➜ npm publish
> fatigue-js@1.0.0 prepublish
> npm run lint && npm run test && npm run build
> fatigue-js@1.0.0 lint
> eslint
eslint [options] file.js [file.js] [dir]
# [full eslint output was here]
> fatigue-js@1.0.0 test
> jest
No tests found
# [full jest output was here]
> fatigue-js@1.0.0 build
> webpack -p
No configuration file found and no output filename configured via CLI option.
A configuration file could be named 'webpack.config.js' in the current directory.
Use --help to display the CLI options.
npm ERR! code ELIFECYCLE
npm ERR! fatigue-js@1.0.0 build: `webpack -p`
npm ERR! Exit status 255
{
// ...
"scripts": {
"lint": "time sleep 2s; echo lint took 2s!",
"test": "time sleep 1s; echo test took 1s!",
"watch":
"time (npm run lint & npm run test & wait) && echo done!"
},
// ...
}
➜ npm run watch
> fatigue-js@1.0.0 watch
> time (npm run lint & npm run test & wait) && echo done!
> fatigue-js@1.0.0 test
> time sleep 1s; echo test took 1s!
> fatigue-js@1.0.0 lint
> time sleep 2s; echo lint took 2s!
real 0m1.003s
user 0m0.000s
sys 0m0.001s
test took 1s!
real 0m2.001s
user 0m0.001s
sys 0m0.000s
lint took 2s!
real 0m2.579s
user 0m1.036s
sys 0m0.107s
done!
✗ Bash/cmd.exe interop is nearly impossible
✗ Very verbose output, especially for errors :(
✗ package.json is strict JSON:
npm-scripts documentation
npm-config documentation
npm's package.json documentation
npm scripting: configs and arguments... and some more tricks by Marcus Hammarberg