A Modern Way To Build a CLI with oclif in Node

Alex Korzhikov
codeburst
Published in
5 min readJun 4, 2019

--

In the previous articles, we explored different ways of creating a CLI program with JavaScript. We overviewed basics and some libraries helping to build a command line application. The given examples were aiming to show how powerful Node environment is in terms of its infrastructure and flexibility. The topic for this article is to understand the oclif library and its satellites — a modern way of constructing a pluggable CLI.

We start to build a program to manipulate pieces of Markdown. The CLI will save notes in the file system. In the future, we plan to create a very fruitful tool for managing user’s notes and saving them in Git repository. And the first steps would be:

  • Understand oclif concepts,
  • Generate projects structure,
  • Implement the add note command.
https://oclif.io/

First of all, oclif is not a library — it’s a framework instead.

And for those who doubt what’s the difference, we recommend reading the great article Inversion of Control by Martin Fowler.

Made by Heroku to design CLI applications in Node. The article Evolution of the Heroku CLI: 2008–2017 provides a very deep perspective of designing, implementing, and maintaining a rich and popular command line program. The main benefits of using Node underlined by oclif creators are:

  • stable and performant core,
  • enormous JavaScript community, with all existing npm packages,
  • dynamic plugins with user-defined dependencies.

However, oclif appeared only in 2018, other big products, like GraphQL Apollo development and production tooling are already using it.

A second big difference comparing to our previous attempts of building the CLI application is that oclif strongly encourages a developer to use the TypeScript language. The framework’s core itself is written in TypeScript and it uses the TypeScript Node (ts-node) — the on-the-fly module extension and REPL for Node.

It is designed to be easily extendable with plugins and hooks. Any plugin can be developed and maintained separately. Similarly to Commander.js and Vorpal, it supports different command types, which can meet most developer’s demands.

Many tools around oclif infrastructure allow the developer to generate, develop, test, and publish a fine extendable CLI. So, shall we start? 😀

Generate New CLI

Oclif proposes to run the CLI for creating a new CLI.

It allows to generate a single command CLI, like simple Linux commands ls, curl, or a multi-command CLI, like Git. We’ve started the CLI series with a little description of both approaches. The official documentation explains quite well how to generate a new package, either single or multi-command.

Before we start doing a CLI on oclif, we would recommend reading also another famous article — 12 Factor CLI Apps — Heroku, which is a sequel to their legendary The Twelve-Factor App.

We start with generating a new npm package as usual

And the output can be something like

As you might see, the oclif generator uses yeoman internally. Now, the project’s structure is ready

It contains a README.md with main information, TypeScript configuration, and tests, helping to construct a stable CLI. We still need to install our package globally in order to try it, let’s do it with npm link command

The oclif has generated an example command. Now, when we have a working hello world example, we are ready to implement some features for our application.

A first command we are going to implement is add, and we want it to create a Markdown file.

Flags & Arguments

Not a single CLI program can go without parsing user arguments. Libraries like yargs, nops, or minimist help with it. More powerful packages commander and vorpal, intended for constructing the command line application has this functionality embedded. oclif like others fully supports arguments definition as well as its automated documentation and parsing.

Its official blog post about arguments definition provides clear examples and terminology for this topic. A user can provide arguments to the CLI in many different ways, and all of them are supported by oclif:

  • Flags change a format of an executed command. Like adding verbosity in the npm i — verbose.
  • Options are an addition to flags, adding customization. git log — abbrev-commit — pretty=oneline -n 50 command shows commit logs, and the pretty option can have oneline value to make it compact.
  • Arguments are normally targets on which command is operating, e.g. npm install yargs, where yargs is an argument.
  • Standard input, when the user interacts to the program while entering a text or typing values in the terminal.
  • Environment variables are passed implicitly, but the program can check if needed parameters exist.

For the add command, we will specify a note argument. Static args property is responsible for arguments declaration. Logically, the file’s name should be required, and oclif will perform the check.

We added a check to not override the existing file, and we use Node’s built-in fs module to create new notes. The -h flag prints declared arguments and parameters, so the user is not blindly stuck with the tool.

Features

The oclif framework supports many CLI required features, some of them we’ve already used:

  • arguments parsing,
  • auto-documentation,
  • code generation,
  • plugins.

It has many other built-in abilities, such as hooks, testing, and releasing. For tests, the @oclif/test library can be used, and oclif-dev pack command can help to release a CLI as a binary package.

Some Doubts

Like any other framework, oclif has quite an opinionated set of principles to follow:

  • The unobvious convention in colon-separated command names.
  • It encourages to use TypeScript instead of JavaScript, so the development process can be more complex in transpiling and debugging sense.
  • The test library is non-standard, which makes writing tests experience harder.

Summary

Oclif is a great tool for developing a CLI application. It supports many features to make your application stable, and lots of helpers to achieve good quality with less effort. However, it has some particular circumstances, it’s a very mature instrument for implementing the CLI in Node.

In the next articles, we are going to continue working on the “Notes CLI” and explore further specialties of constructing the CLI application in JavaScript.

This is a part of “Crafting Notes CLI in TypeScript” workshop and tutorials performed by JavaScript Planet — a group of software engineers, instructors, and Web enthusiasts. Our goal is to help developers to extend their knowledge and improve software programming skills.

--

--

Software engineer, instructor, mentor, and author of technical materials #JavaScript