Congratulations on open sourcing this. It looks great. Is there a reason you went with Node.js instead of something like Go? As a sysadmin, I personally hate having to deal with dependencies from tools built in non-compiled languages like Python, Node and Ruby.
We did try to partially write it in Go. Writing it fully in Go would not have be possible because of the plugin system we have. However we struggled with Go quite a bit and ultimately dropped it from the codebase. This article gets more into detail as to why: https://blog.heroku.com/evolution-of-heroku-cli-2008-2017
We also have some tools we use with the Heroku CLI we will be backporting into oclif very soon that directly addresses this problem node has with distribution. Essentially it's some scripts that let you export an oclif CLI as a standalone tarball (node binary into it), optionally being able to autoupdate with github or s3.
oclif is also compatible with pkg (https://github.com/zeit/pkg) which will turn the CLI into a dependency-less single binary just like it would be with Go. I don't like it personally as I find it useful for debugging to actually edit the files. With Go we would have to cut a release just to add extra debugging information.
As part of dropping Heroku for our own platform we ended up writing something equivalent in python, then Go initially to deal with packaging/distribution. Its been pretty great, but damn I would have loved this to have been in Go. Then I wouldn't even tell the developers we moved off Heroku :P
I'm interested in the reasons this annoys you, as I find nearly all the installation problems we see in node is when somebody has included some C code that needs to be built.
What makes this better for building CLIs than using something like Thor with Ruby or Click with Python?
I mean, from the 1 minute video that's posted on the page, it just looks like it's a basic Node library to help tackle some common CLI requirements and it happens to have generators.
It's fairly pointless to compare the library to CLI libraries for other languages.
It's much more meaningful to pick a language that fits the main purpose of the program, and not depending on what CLI libraries are available.
Generally, the CLI interface will be a fraction of the code in an application. When deciding on a CLI library, it's usually the case of "I'm writing this application that does X, and now it requires a CLI interface - which one do I pick?".
Of course it can still be useful to review how libraries for different languages work, in order to get ideas for making a better one (or improving existing ones).
So, what makes this better than e.g. Thor or Click is that if you're in the target group, you're already using node, making the other mentioned libraries irrelevant.
> t's much more meaningful to pick a language that fits the main purpose of the program, and not depending on what CLI libraries are available.
It's possible for providing a CLI to be a significant part of the main purpose of the program; e.g., if the program is largely a client CLI for a web service, other than having a language with a reasonably usable web requests library, there's not a lot beside the CLI-building tools guiding the choice.
The major advantage oclif has is plugins. Plugins are a way to share code between CLIs or organize within a CLI. At Heroku, different teams manage their own CLI plugin and each of those plugins have their own set of dependencies. These dependencies will not conflict with each other. It's a great way to share code and modularize a large CLI's codebase.
This kind of setup isn't possible with Ruby (to have multiple dependencies of different versions). I'm not sure if it's possible with Python, but I don't think so. Node's dependency model naturally supports this behavior though.
I haven't used thor in years and only looked at the docs for click. For a large CLI built in a scripting language, lazy loading of commands is crucial. It appears that click supports this, but my cursory reading of the thor docs looks like that one does not have lazy loading.
I have a lot of experience trying to deliver the Heroku CLI as a ruby CLI and I can tell you first hand that dealing with ruby as a runtime dependency vs node is a world of difference. Node is simply far easier. Also, we will be coming out with a plugin for oclif within the next few months that will help you build dependency-less tarballs so the end-user doesn't need to even have node installed. (You can also do this today with oclif just by using pkg) This is also going to come with a couple options for adding autoupdates that won't depend on the local npm. The goal is to make distributing CLIs as easy as possible and have it not conflict with anything that may or may not be on the end-user's machine.
If you're just building a small CLI, I don't think between these tools you'll notice much of a difference. Just use the one in the language you feel more comfortable in. oclif is really meant to solve a lot of the problems we've had with large CLIs (sharing code, distribution, dependency management, versioning, namespacing) and abstract away common issues end-users have with setting up.
The choice of node is also helpful for large codebases like what we have at Salesforce and Heroku. This is an area where people's main job is writing in many different languages but everyone knows at least some javascript. This means that even if javascript isn't their favorite language, they're still able to jump in and write code. Often CLI code just isn't that complicated either (usually doesn't involve any memory management as the application is only running for less than a second, for example), so the language choice I feel doesn't matter as much as it would compared to back-end development.
16 comments
[ 3.1 ms ] story [ 48.3 ms ] threadoclif is also compatible with pkg (https://github.com/zeit/pkg) which will turn the CLI into a dependency-less single binary just like it would be with Go. I don't like it personally as I find it useful for debugging to actually edit the files. With Go we would have to cut a release just to add extra debugging information.
https://github.com/drew-y/cliffy
I mean, from the 1 minute video that's posted on the page, it just looks like it's a basic Node library to help tackle some common CLI requirements and it happens to have generators.
It's much more meaningful to pick a language that fits the main purpose of the program, and not depending on what CLI libraries are available.
Generally, the CLI interface will be a fraction of the code in an application. When deciding on a CLI library, it's usually the case of "I'm writing this application that does X, and now it requires a CLI interface - which one do I pick?".
Of course it can still be useful to review how libraries for different languages work, in order to get ideas for making a better one (or improving existing ones).
So, what makes this better than e.g. Thor or Click is that if you're in the target group, you're already using node, making the other mentioned libraries irrelevant.
It's possible for providing a CLI to be a significant part of the main purpose of the program; e.g., if the program is largely a client CLI for a web service, other than having a language with a reasonably usable web requests library, there's not a lot beside the CLI-building tools guiding the choice.
This kind of setup isn't possible with Ruby (to have multiple dependencies of different versions). I'm not sure if it's possible with Python, but I don't think so. Node's dependency model naturally supports this behavior though.
I haven't used thor in years and only looked at the docs for click. For a large CLI built in a scripting language, lazy loading of commands is crucial. It appears that click supports this, but my cursory reading of the thor docs looks like that one does not have lazy loading.
I have a lot of experience trying to deliver the Heroku CLI as a ruby CLI and I can tell you first hand that dealing with ruby as a runtime dependency vs node is a world of difference. Node is simply far easier. Also, we will be coming out with a plugin for oclif within the next few months that will help you build dependency-less tarballs so the end-user doesn't need to even have node installed. (You can also do this today with oclif just by using pkg) This is also going to come with a couple options for adding autoupdates that won't depend on the local npm. The goal is to make distributing CLIs as easy as possible and have it not conflict with anything that may or may not be on the end-user's machine.
If you're just building a small CLI, I don't think between these tools you'll notice much of a difference. Just use the one in the language you feel more comfortable in. oclif is really meant to solve a lot of the problems we've had with large CLIs (sharing code, distribution, dependency management, versioning, namespacing) and abstract away common issues end-users have with setting up.
The choice of node is also helpful for large codebases like what we have at Salesforce and Heroku. This is an area where people's main job is writing in many different languages but everyone knows at least some javascript. This means that even if javascript isn't their favorite language, they're still able to jump in and write code. Often CLI code just isn't that complicated either (usually doesn't involve any memory management as the application is only running for less than a second, for example), so the language choice I feel doesn't matter as much as it would compared to back-end development.