TypeScript CLI project template.
- Create an empty project
- Add itself to
PATH
- Configure TypeScript in tsconfig.json
- .editorconfig
- ESLint
- Prettier
- Jest
- Must-have libraries
Create an empty npm project,
npm init
Fill in some information then we get a package.json
file:
{
"name": "ts-cli-starter",
"version": "1.0.0",
"description": "TypeScript CLI project template.",
"main": "dist/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/soulmachine/ts-cli-starter.git"
},
"keywords": ["typescript", "CLI"],
"author": "soulmachine",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/soulmachine/ts-cli-starter/issues"
},
"homepage": "https://github.com/soulmachine/ts-cli-starter"
}
Install TypeScript compiler:
npm install typescript --save-dev
Make TypeScript outputs compiled JS files to the directory dist/
:
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
}
}
Add a build
and start
command in package.json
:
{
"scripts": {
"build": "tsc -p tsconfig.json",
"start": "node ./dist/index.js"
}
}
Create a typescript file ./src/index.ts
:
console.log('Hello World');
Now compile this project with npm run build
and run it with npm start
, you'll see Hello World
printed out!
We can install this CLI project as a command to PATH
so that it can be used directly in terminal.
First add the following line at the beginning of index.ts
:
#!/usr/bin/env node
Then add 2 properties in package.json
:
"bin": "dist/index.js",
"preferGlobal": "true",
bin
tells npm where your executable file is so that it can install it into the PATH
. And preferGlobal
, if set to true
, will warn users if they try to install the package locally. preferGlobal
is not necessary, but it can be nice to let users know that the package is a CLI tool and meant to be installed globally.
Run npm link
and type the command ts-cli-starter
in terminal, you'll also see Hello World
printed out!
All compiler options are configured in tsconfig.json
.
Note:
- Make sure set "module" to "commonjs". Because Node.js runtime only recognizes CommonJS format, and it doesn't support
import
.
Install node types which is needed by all Node.js projects:
npm install @types/node --save-dev
EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.
Add a new file .editoconfig
at the root directory of this project:
# https://EditorConfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
# Markdown Files
[*.md]
trim_trailing_whitespace = false
# Batch Files
[*.{cmd,bat}]
end_of_line = crlf
There are two special rules:
- Do NOT trim trailing whtespaces for Markdown files.
- Windows batch files(
.cmd
and.bat
) requireCRLF
line endings.
Add a .gitattributes
file to the root of your repository to force everything to be LF
, except for Windows batch files that require CRLF
:
* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf
Install eslint
and typescript-eslint
packages:
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-airbnb-base --save-dev
Install plugins:
npm install eslint-plugin-import eslint-plugin-jest eslint-plugin-markdown --save-dev
Configure ESLint in file.eslintrc.js
.
Note:
- Set
parser
to@typescript-eslint/parser
- Add
@typescript-eslint
toplugins
Add a command inside scripts
field:
"scripts" {
"lint": "eslint . --ext '.js,.jsx,.ts,.tsx,.md'",
}
Add a file .eslintignore
to ignore several files and directories.
Install:
npm install prettier eslint-config-prettier eslint-plugin-prettier --save-dev
Add the following config to .eslintrc.js
to intergrate with ESLint:
{
"extends": ["plugin:prettier/recommended"]
}
Then set Prettier's own options inside a .prettierrc
file.
Add a command in scripts
:
"prettier": "prettier -c --write '**/*'",
Make VS Code formats code automatically on save:
"files.autoSave": "onFocusChange",
"eslint.autoFixOnSave": true,
"editor.formatOnSave": true,
Add a file .prettierignore
to ignore several file types.
For more details see https://prettier.io/docs/en/integrating-with-linters.html.
Install:
npm install jest eslint-plugin-jest ts-jest @types/jest --save-dev
Add a test
command in pacage.json
:
"test": "jest --config jest.config.json --no-cache",
Also add a prepare
command in package.json
:
"prepare": "npm run build && npm run lint && npm run prettier && npm run test"
jest.config.json
:
{
"preset": "ts-jest",
"testEnvironment": "node",
"roots": ["<rootDir>/tests"],
"testPathIgnorePatterns": ["<rootDir>/node_modules/"]
}
Create a new file tests/hello.spec.ts
and put a dummy unit test in it:
test('A dummy unit test', (): void => {
const n = 2;
expect(n).toBe(2);
});
Now run npm run test
and you'll see Jest is doing its job!
Add a Git hook. Install husky
using npm install husky --save-dev
and add the following config to package.json
:
{
"husky": {
"hooks": {
"pre-commit": "npm run prepare"
}
}
}
Install yargs
:
npm install yargs --save
npm install @types/yargs --save-dev
Added the following code to ./src/index.ts
:
import yargs from 'yargs';
const argv = yargs.options({
a: { type: 'boolean', default: false },
b: { type: 'string', demandOption: true },
c: { type: 'number', alias: 'chill' },
d: { type: 'array' },
e: { type: 'count' },
f: { choices: ['1', '2', '3'] },
}).argv;
console.info(argv);
Installchalk
:
npm install chalk --save
Add the following code to ./src/index.ts
:
import chalk from 'chalk';
console.info(chalk.green('Green text'));
Install figlet
:
npm install figlet --save
npm install @types/figlet --save-dev
Add the following code to ./src/index.ts
:
import figlet from 'figlet';
console.log(chalk.green(figlet.textSync('ts-cli-starter')));
First, use a .npmignore
file to keep stuff out of your package. See Keeping files out of your package to learn more about .npmignore
.
Second, run npm login
to login.
Last, run npm publish
to publish your package to npm.