This short tutorial demonstrates building command-line tools in TypeScript, non-blocking operations with async/await, continuous integration with Mocha automated testing, and Travis – CI.
Intro
Recently TJ released Node-Prune to clean up the redundant files in node_modules, but the project was written in Go, so I ported a JavaScript version. You can continue to read the article with the source code. Projects are built in TypeScript and automatically translated to JavaScript when published by NPM, so feel free to use the latest syntax and type detection such as async/await. It also uses TS-Node to debug directly in TypeScript. Project code is small, suitable as a template for similar gadgets ~
TypeScript Setup
The final structure of the project is as follows. The source code is placed in the SRC/directory, and finally transcoded to lib/ and published to NPM. The test code is in the test/ directory.
.
├ ─ ─ SRC /
├ ─ ─ the test /
├ ─ ─ lib /
├ ─ ─ node_modules /
├ ─ ─ LICENSE
├ ─ ─ the README, md
├ ─ ─ package - lock. Json
├ ─ ─ package. Json
└ ─ ─ tsconfig. JsonCopy the code
First use NPM init to initialize the project and install TypeScript
npm i typescript -DCopy the code
After entering, open package.json and add:
{
"scripts": {
"build": "tsc",
"dev": "tsc -w",
"prepare": "npm run build",
}
},Copy the code
TSC is a TypeScript translation command. The -w parameter is used to monitor source code changes and prepare is executed before NPM install and NPM publish to ensure that the latest translated code is published.
To tell TSC how to translate, you need a configuration file, tsconfig.json, that generates a default template from TSC –init on the command line. To support node6.x, 7.x, change the “target”: “ES2015” for the Node project. Module generation requires “module”: “commonJS” and then specifies the ts files included below.
{
"compilerOptions": {
"target": "ES2015"."module": "commonjs"."outDir": "./lib"."strict": true
},
"exclude": [
"node_modules"."lib"]."include": ["src/**/*.ts"]}Copy the code
Now we can have fun writing TS code. Try writing a function for all files and folders in walk.
import * as fs from 'fs-extra';
import * as path from 'path';
export async function walk(dir: string, prunerF: (p: string, s: fs.Stats) => void): Promise<void> {
let s = await fs.lstat(dir);
if (!s.isDirectory()) return;
const items = await fs.readdir(dir);
for (let item of items) {
const itemPath = path.join(dir, item);
const s = await fs.lstat(itemPath);
const pruned = await prunerF(itemPath, s);
if (!pruned && s.isDirectory()) {
await walk(itemPath, prunerF);
}
}
}Copy the code
Note here that we can use async/await directly and type the incoming parameters, and if you use an editor with plug-in support, you will have a pleasant experience with intelligent completion.
Async is implemented by defining an __awaiter function. If you are interested, you can explore it by yourself.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise(a))function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch(e) { reject(e); }}function rejected(value) { try { step(generator["throw"](value)); } catch(e) { reject(e); }}function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};Copy the code
CLI
You can run a script from Node file.js, but how do you install an NPM executable, as described by npmjs.com, in package.json
{
"bin": {
"prune": "lib/cli.js"}}Copy the code
You can then install a Prune into your system path and add #! To the top of the file you execute. /usr/bin/env node, otherwise it is not recognized as a node script.
To read arguments passed from the command line, you can use args, this code in SRC /cli.ts
const argv = yargs
.usage('Prune node_modules files and dependencies\n\nUsage: node-prune <path>')
.option('config', {
alias: 'c',
description: '<filename> config file name'.default: '.prune.json'.type: 'string'
})
.option('dryrun', {
alias: 'd',
description: 'dry run'.default: 'false'.type: 'boolean'
})
.option('verbose', {
description: 'log pruned file info'.default: 'false'.type: 'boolean'
})
.help('help').alias('help'.'h')
.version('version'.'0.1.0 from').alias('version'.'v')
.argv;
const path = argv._[0] | |'node_modules';
const configs = {
config: argv.config,
dryrun: argv.dryrun,
verbose: argv.verbose
};Copy the code
It can produce something like this:
$ prune -h
Prune node_modules files and dependencies
Usage: node-prune <path>
Options:
--config, -c <filename> config file name [string] [default: ".prune.json"]
--dryrun, -d dry run [boolean] [default: "false"]
--verbose log pruned file info [boolean] [default: "false"]
--help, -h Show help [boolean]
--version, -v Show version number [boolean]Copy the code
You can import the business code you wrote to perform operations after obtaining the parameters, which is omitted here and can be seen on Github for example.
After that, we can use NPM publis after NPM install -g pruner-cli to download the installation tool and execute prune call directly.
Async Test
The test code also needs to use TypeScript and async/await. Mocha was selected to conduct BDD style tests. Chai is a library of assertions that work best when used together.
$ npm install mocha ts-node -g
$ npm install mocha chai ts-node --save-devCopy the code
Mocha normally executes JavaScript in the test/ directory. To test the TS code directly, skip the translation. We can bind ts-Node to execute the test code directly.
{
"scripts": {
"test": "mocha -r ts-node/register test/**/*.spec.ts"}},Copy the code
So all *.spec.ts under test/ will be tested, and you can expect BDD with await async. An example.
Travis
Add the configuration for the project language after adding.travis. Yml under the project
language: node_js
node_js:
- "6"
- "Seven"
- "8"
- "9"Copy the code
Then add your own open source project to travis-ci.org/ to automatically test compilation and test every push.
Click the build | after passing the picture link to project can be displayed on the making of CI in the README state!
The original address