yargs v16 released
Tags: npm, javascript, node, yargs
Published: 2020-09-09 16:21:14

About 5 months ago, [Mael Le Guen](https://github.com/mleguen) proposed converting the yargs codebase to TypeScript. I was a bit skeptical at first...

I saw benefits TypeScript could offer the project:

* yargs has a large API surface with many implicit contracts, e.g., how calling a method like `.option()` eventually feeds into [yargs-parser](https://github.com/yargs/yargs-parser).
* some parts of the codebase are quite messy, and type safety would give additional confidence to future refactors.

A few concerns were motivating my skepticism:

* I knew this would be a large project, and was worried we'd deliver something that was only _halfway there._
* The existing [@types/yargs](https://www.npmjs.com/package/@types/yargs) TypeScript definitions have **>12,000,000** downloads/week, I didn't want to disrupt this community.
* I didn't want to significantly bloat the size of yargs.

Thanks to the hard work of Mael, who lead the conversion project (_with help from others like [QmarkC](https://github.com/QmarkC)_), and thanks to a few compromises, I'm happy to say that the TypeScript conversion project was successful.

Beyond the benefits I expected (_ease of refactoring, and explicit interfaces_), TypeScript made two additional improvements to yargs easier, which I'm excited to announce in **v16**:

* yargs now supports both ESM and CommonJS (_you can even use [yargs directly in the browser](https://jsfiddle.net/bencoe/m9fv2oet/), without bundling_).
* yargs now has experimental support for Deno.

## yargs is now written in TypeScript, but...

As the TypeScript project approached completion, it became clear that it would be significant amount of work to match the type definitions exposed in **@types/yargs**...

We've made the decision to not ship yargs with [Type declaration files](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html). As a TypeScript user of yargs, usage [instructions](https://github.com/yargs/yargs/blob/master/docs/typescript.md) shouldn't change, and you will still `npm i @types/yargs --save-dev`.

Developers working on the yargs project now benefit from type safety, and the project benefits from the build steps we've introduced (_more on this in a moment_), but the existing TypeScript community should be able to upgrade with minimal disruption.

## ESM and CJS support

**yargs@v16** is **~26%** larger than past version of yargs. This is because, using Node.js' [conditional exports](https://nodejs.org/api/esm.html#esm_conditional_exports), yargs now provides an interface for both CommonJS and ESM:

**CommonJS example:**

```js
const {argv} = require('yargs')

if (argv.ships > 3 && argv.distance < 53.5) {
  console.log('Plunder more riffiwobbles!')
} else {
  console.log('Retreat from the xupptumblers!')
}
```

**ESM example:**

```js
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'

yargs(hideBin(process.argv))
  .command('curl <url>', 'fetch the contents of the URL', () => {}, (argv) => {
    console.info(argv)
  })
  .demandCommand(1)
  .argv
```

To facilitate this, we target ESM with the TypeScript compilation step, then have an additional compile step with [Rollup](https://github.com/rollup/rollup) which creates a CommonJS bundle of the library.

It's my hope that taking this approach of shipping a dual mode library will help smooth the process for folks experimenting with ESM (_and that the additional bloat in the library will be forgiven 😊_)

## Deno Support

> Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust.

Taking on the work to make yargs and its dependencies fully support ESM, combined with converting the codebase to TypeScript, made it a short addition step towards supporting the Deno runtime.

**Deno example:**

```typescript
import yargs from 'https://deno.land/x/yargs/deno.ts'
import { Arguments, YargsType } from 'https://deno.land/x/yargs/types.ts'

yargs()
  .command('download <files...>', 'download a list of files', (yargs: YargsType) => {
    return yargs.positional('files', {
      describe: 'a list of files to do something with'
    })
  }, (argv: Arguments) => {
    console.info(argv)
  })
  .strictCommands()
  .demandCommand(1)
  .parse(Deno.args)
```

I am a Deno novice, and would characterize yargs' support of the platform as _experimental_. However, I'm excited to see folks adopt the functionality, and will happily fix bugs for the platform as they arise.

## Significant Breaking Changes

* the use of Conditional exports makes yargs' exported files explicit. Folks who were requiring deep files, e.g., `lib/utils/obj-filter.js`, will not be able to do so. The helpers yargs exposes have been [defined explicitly](https://github.com/yargs/yargs/pull/1733).
* the `rebase` helper method has been removed from yargs (this was just wrapping `path.relative`).
* Node 8 support has been dropped.

_Other changes are listed in the [CHANGELOG](https://github.com/yargs/yargs/blob/master/CHANGELOG.md)_.

Related:

* ["Maintainers Should Consider Following Node.js’ Release Schedule"](https://medium.com/the-node-js-collection/maintainers-should-consider-following-node-js-release-schedule-ab08ed4de71a).
* ["How my team releases libraries"](https://dev.to/bcoe/how-my-team-releases-libraries-23el).