helpful libraries for *building* CLIs. Not a list of CLIs.
See the codethis list is now archived - look inside https://github.com/sw-yx/brain if you would like an updated list! thank you.
helpful libraries and resources for building Node.js CLIs. Not a list of CLIs.
I put together a 90 minute Egghead.io Course and Workshop on how to put these tools together, if you like video learning. I also make some money if you watch those videos if you want to help :)
12 Factor CLI Apps (Blogpost, Talk): Jeff Dickey's list of requirements for UX.
Heroku CLI Style Guide (Guide, Talk, Talk): Heroku's CLI Style Guide.
CLI Guidelines (Guide, Source): An open-source guide to help you write better command-line programs, taking traditional UNIX principles and updating them for the modern day.
The Poetics of CLI Command Names: Command naming anti-patterns and excellent names
CLI State Machines (Gist): My little thoughts on state management
Add a dry run mode for expensive commands like gatsby dry-run
create-react-app, vue-cli, and many others. Key feature: pluggability. Vorpal is another framework inspired by Commander and is seeking maintainerswebpack-cli, mocha, react-native, nyc, and 14,343 other modules.vercel, ncc, micro, serve, and many others. Key Feature: tinycreate-nuxt-app and many others.New: see CLUI https://blog.repl.it/clui
Inspiration from other languages - the http://charm.sh/ universe.
For performance logging, you can try process.htime() instead of console.time() (altho the latter uses the former under the hood)
Context from Git/CI
Context from filesystem/PATH
which: Find the first instance of an executable in the PATH.require.resolve
relative('a/b/c', 'a/d') // ../../dConfig validation
Loading config from json, rc file, etc*
searchPaths to implement XDG spec compliance.
don't need but nice to know: https://www.npmjs.com/package/read-package-json
Beware the race condition when you check if file exists and then open it. the file could be deleted in betwee. instead, just open the file and handle the error if it doesnt exist.
Loading/Storing config from a persistent store
⚠️ Be aware of the XDG spec. Sindre's libraries use
env-pathsto get paths compliant with this.
Stdin Parsing
cat mydata.json | mycli)Argument Parsing
⚠️ Your framework may come with parsing built in
Input/Stdin/Argument Processing
make sure to also normalize inputted stuff before you compare
path.resolve(str1) === path.resolve(str2)Command execution
preferLocal: truestdio: 'inherit' to pipe stdout/stderr upshell: true unless absolutely necessaryRemember Windows users for cross-platform nodejs (Guide). e.g. dont execute pkg.json or shell commands with single quotes instead of escaped double quotes
Sometimes processes can spawn processes. This is troublesome for watch/reload features. Kill them all with tree-kill.
You'll probably also use these in conjunction with port monitors (e.g. the process you're working with opens a port, like CRA for Netlify Dev):
If child_processes are going to be a key part of your CLI, be sure to read the docs and this guide to be aware of the API.
You may also want to poll for conditions to be true to execute async processes:
Spinners/Loaders
Templating
Temp folders
Files
fs.existsSync(path.resolve/path.join) http://npm.im/path-existsIcons & Coloring
Note that you may want to offer the option to FORCE_COLOR in CI logging.
PrettyPrinting
there are also react based renderers
Boxing
Tables
Banners
Debug Logging
util.debuglog does a lot of the same h/t @stefanjudis)You often also find specialized logger tools for each domain, like @dazn/lambda-powertools-logger for AWS Lambda, but at their core they all support the core pattern of Log Levels DEBUG, INFO, WARN and ERROR.
⚠️ None of these are offline-first. Keen on finding one that respects offline first.
upgrade command based on git diffsimport { spawn, hasYarn } from 'yarn-or-npm'
// optionalDir for installing?
const prefixFlag = hasYarn() ? '--cwd' : '--prefix'
spawn.sync(['install', prefixFlag, optionalDir], { stdio: 'inherit' })
servetmux like UIgray-matterremarkNew: see CLUI https://blog.repl.it/clui
4,974 followers · starred May 2019
3,286 followers · starred Nov 2019
949 followers · starred Jun 2019
3,920 followers · starred May 2019
helpful libraries for *building* CLIs. Not a list of CLIs.
See the codethis list is now archived - look inside https://github.com/sw-yx/brain if you would like an updated list! thank you.
helpful libraries and resources for building Node.js CLIs. Not a list of CLIs.
I put together a 90 minute Egghead.io Course and Workshop on how to put these tools together, if you like video learning. I also make some money if you watch those videos if you want to help :)
12 Factor CLI Apps (Blogpost, Talk): Jeff Dickey's list of requirements for UX.
Heroku CLI Style Guide (Guide, Talk, Talk): Heroku's CLI Style Guide.
CLI Guidelines (Guide, Source): An open-source guide to help you write better command-line programs, taking traditional UNIX principles and updating them for the modern day.
The Poetics of CLI Command Names: Command naming anti-patterns and excellent names
CLI State Machines (Gist): My little thoughts on state management
Add a dry run mode for expensive commands like gatsby dry-run
create-react-app, vue-cli, and many others. Key feature: pluggability. Vorpal is another framework inspired by Commander and is seeking maintainerswebpack-cli, mocha, react-native, nyc, and 14,343 other modules.vercel, ncc, micro, serve, and many others. Key Feature: tinycreate-nuxt-app and many others.New: see CLUI https://blog.repl.it/clui
Inspiration from other languages - the http://charm.sh/ universe.
For performance logging, you can try process.htime() instead of console.time() (altho the latter uses the former under the hood)
Context from Git/CI
Context from filesystem/PATH
which: Find the first instance of an executable in the PATH.require.resolve
relative('a/b/c', 'a/d') // ../../dConfig validation
Loading config from json, rc file, etc*
searchPaths to implement XDG spec compliance.
don't need but nice to know: https://www.npmjs.com/package/read-package-json
Beware the race condition when you check if file exists and then open it. the file could be deleted in betwee. instead, just open the file and handle the error if it doesnt exist.
Loading/Storing config from a persistent store
⚠️ Be aware of the XDG spec. Sindre's libraries use
env-pathsto get paths compliant with this.
Stdin Parsing
cat mydata.json | mycli)Argument Parsing
⚠️ Your framework may come with parsing built in
Input/Stdin/Argument Processing
make sure to also normalize inputted stuff before you compare
path.resolve(str1) === path.resolve(str2)Command execution
preferLocal: truestdio: 'inherit' to pipe stdout/stderr upshell: true unless absolutely necessaryRemember Windows users for cross-platform nodejs (Guide). e.g. dont execute pkg.json or shell commands with single quotes instead of escaped double quotes
Sometimes processes can spawn processes. This is troublesome for watch/reload features. Kill them all with tree-kill.
You'll probably also use these in conjunction with port monitors (e.g. the process you're working with opens a port, like CRA for Netlify Dev):
If child_processes are going to be a key part of your CLI, be sure to read the docs and this guide to be aware of the API.
You may also want to poll for conditions to be true to execute async processes:
Spinners/Loaders
Templating
Temp folders
Files
fs.existsSync(path.resolve/path.join) http://npm.im/path-existsIcons & Coloring
Note that you may want to offer the option to FORCE_COLOR in CI logging.
PrettyPrinting
there are also react based renderers
Boxing
Tables
Banners
Debug Logging
util.debuglog does a lot of the same h/t @stefanjudis)You often also find specialized logger tools for each domain, like @dazn/lambda-powertools-logger for AWS Lambda, but at their core they all support the core pattern of Log Levels DEBUG, INFO, WARN and ERROR.
⚠️ None of these are offline-first. Keen on finding one that respects offline first.
upgrade command based on git diffsimport { spawn, hasYarn } from 'yarn-or-npm'
// optionalDir for installing?
const prefixFlag = hasYarn() ? '--cwd' : '--prefix'
spawn.sync(['install', prefixFlag, optionalDir], { stdio: 'inherit' })
servetmux like UIgray-matterremarkNew: see CLUI https://blog.repl.it/clui
4,974 followers · starred May 2019
3,286 followers · starred Nov 2019
949 followers · starred Jun 2019
3,920 followers · starred May 2019