hello-ts-cli tutorial
This github repository explains how to create a node cli tool with typescript and publish it as a npm (yarn) package.
📌Create yarn package
mkdir hello-ts-cli
cd hello-ts-cli
yarn init -y
📌Install Typescript in your project
To use typescript, let's install typescript
.
yarn add typescript --dev
https://www.typescriptlang.org/download
📌Make first ts file
Make src
folder and cli.ts
inside it.
src/cli.ts
#!/usr/bin/env node
console.log("Hello World");
📌Typescript compile command
Let's check basic typescript command.
https://www.typescriptlang.org/docs/handbook/compiler-options.html
tsc
✅tsc
is the command to compile the Typescript code.
yarn tsc src/cli.ts
This command creates src/cli.js
.
tsc --watch
✅Automatically compile ts
files when you make a change.
tsc src/index.ts --watch
tsconfig.json
📌https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
tsconfig.json
?
✅What is - Specify compile options
- Indicates that the directory is the root of a TypeScript project
- You can specify which files to compile and which files to exclude (you don't need to specify each files to compile).
tsconfig.json
✅Make yarn tsc --init
to create the tsconfig.json
file.
tsconfig.json
settings
✅Use Recommended 📝In the beginning, you may not know what settings to use, so let's extend the recommended settings.
This time, we will use the recommended settings for node14
.
https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#tsconfig-bases
terminal
yarn add -D @tsconfig/node14
Then,
tsconfig.json
{
"extends": "@tsconfig/node14/tsconfig.json",
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
rootDir
✅ Add Set the rootDir
to src
since ts
files are only stored under the src
directory.
tsconfig.json
{
"extends": "@tsconfig/node14/tsconfig.json",
"compilerOptions": {
"rootDir": "src",
},
"include": ["src/**/*"],
"exclude": ["node_modules"],
}
Ref: https://www.typescriptlang.org/tsconfig#rootDir
✅ Change output dir
- Change the output destination of the compiled
.ts
file tolib
. - Also, add exclude
lib
intsconfig.json
.
{
"extends": "@tsconfig/node14/tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
},
"include": ["src/**/*"],
"exclude": ["node_modules", "lib"],
}
Ref: Naming Conventions of lib
@types/node
📌Add If you compile the file in this state, you will get the following error.
terminal
$ yarn tsc # thanks to `tsconfig.json`, you don't need to specify target ts files now.
Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
1 console.log("Hello World");
~~~~~~~
This is caused by the lack of node
types. So, you can add
yarn add -D @types/node
Ref: microsoft/TypeScript#9545
main
and bin
to package.json
📌Add package.json
{
"name": "hello-ts-cli",
"version": "1.0.0",
"main": "lib/cli.js",
"bin": {
"hello-ts-cli": "lib/cli.js"
},
"license": "MIT",
"devDependencies": {
"@tsconfig/node14": "^1.0.0",
"@types/node": "^15.6.1",
"typescript": "^4.3.2"
},
"dependencies": {
"chalk": "^4.1.1",
"commander": "^7.2.0"
}
}
main
: https://docs.npmjs.com/cli/v7/configuring-npm/package-json#main
bin
: https://docs.npmjs.com/cli/v7/configuring-npm/package-json#bin
📌Run cli scripts
Now we are ready to run the cli command. Let's install the current folder into npm
global.
terminal
npm i -g .
Now you can use the hello-ts-cli
command specified in package.json
.
terminal
$ hello-ts-cli
Hello World
❗Don't forget to uninstall after finishing this tutorial.
npm uninstall -g .
📌Terminal Text Coloring
https://github.com/chalk/chalk
yarn add chalk
src/cli.ts
#!/usr/bin/env node
import chalk from "chalk";
console.log(chalk.blue("Hello World"));
yarn tsc
hello-ts-cli
📌Accept Args
https://github.com/tj/commander.js/
yarn add commander
I will use this example
https://github.com/tj/commander.js/#action-handler
#!/usr/bin/env node
import { Command } from "commander";
import chalk from "chalk";
const program = new Command();
program
.arguments("<name>")
.option("-t, --title <honorific>", "title to use before name")
.option("-d, --debug", "display some debugging")
.action((name, options, command) => {
if (options.debug) {
console.error("Called %s with options %o", command.name(), options);
}
const title = options.title ? `${options.title} ` : "";
console.log(chalk.blue(`Hello ${title}${name}`));
});
program.parse();
Then compile and run command with options
$ yarn tsc
$ hello-ts-cli World --title="Super"
Hello Super World
📌Publish Yarn Package
Then,
# git tagging before publish
$ git tag v1.0.0
$ git tag -l
v1.0.0
$ git push origin v1.0.0
# publish package
$ yarn publish
✅If package name is already taken
Change name in package.json
{
"name": "@username/hello-ts-cli",
...
}
Then
yarn publish --access public
Ref: https://docs.npmjs.com/creating-and-publishing-scoped-public-packages
yarn publish
✅Files included in package by You can check what files will be included in your package, by running npx npm-packlist
.
$npx npm-packlist
lib/cli.js
package.json
tsconfig.json
README.md
src/cli.ts
Ref: https://docs.npmjs.com/cli/v7/commands/npm-publish#files-included-in-package
✅Prevent the possibility of forgetting to build before publish.
If you put the following in package.json
, it will automatically build the typescript file when you type yarn publish
.
In package.json
...
"scripts": {
"prepare": "tsc"
},
...
Ref: https://docs.npmjs.com/cli/v7/using-npm/scripts#life-cycle-scripts
📌Update and publish yarn package
$ yarn version
...
# Type new version here
question New version: 1.0.1
yarn version
automatically creates new git tag.
$ git tag -l
v1.0.0
v1.0.1
# So, just push new version to remote
git push origin v1.0.1
# publish updated version
yarn publish
Refs
- https://developer.okta.com/blog/2019/06/18/command-line-app-with-nodejs
- https://medium.com/netscape/a-guide-to-create-a-nodejs-command-line-package-c2166ad0452e
- https://www.digitalocean.com/community/tutorials/typescript-new-project
- https://itnext.io/how-to-create-your-own-typescript-cli-with-node-js-1faf7095ef89