资讯专栏INFORMATION COLUMN

Typescript 构建命令行工具上手指南

TNFE / 2855人阅读

摘要:最近发布了进行对里冗余文件的清理,但项目由写成,于是我移植了一个版本。项目由构建,发布时自动转译成,因此可以随意使用等等最新语法和类型检测。

这篇小教程里演示使用 TypeScript 构建命令行工具,利用 async/await 进行非阻塞操作,利用 mocha 自动化测试以及 travis-ci 进行持续集成。

Intro

最近 TJ 发布了 node-prune 进行对 node_modules 里冗余文件的清理,但项目由 Go 写成,于是我移植了一个 JavaScript 版本。可以搭配源码配合继续阅读文章。项目由 TypeScript 构建,npm 发布时自动转译成 JavaScript,因此可以随意使用 async/await 等等最新语法和类型检测。同时利用 ts-node直接在 TypeScript 环境下进行调试。项目代码量很少,适合作为类似小工具的模版~

TypeScript Setup

项目最终的结构如下,源码放在 src/ 目录下,最终转码到 lib/ 目录发布到 npm,test/目录下是测试代码。

.
├── src/
├── test/
├── lib/
├── node_modules/
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
└── tsconfig.json

首先使用 npm init 进行项目的初始化并安装 TypeScript

npm i typescript -D

输入完毕后打开 package.json 添加:

{
    "scripts": {
        "build": "tsc",
        "dev": "tsc -w",
        "prepare": "npm run build",
    }
},

tsc 是 TypeScript 转译的命令,-w 参数可以观察源码的变化持续转译,prepare 指令会在 npm installnpm publish 之前执行,用来保证发布时是最新转译的代码。

为了告诉 tsc 如何进行转译,需要一个配置文件 tsconfig.json,在命令行 tsc --init 可以生成一个默认的模版。如果要支持 Node6.x, 7.x,修改 "target": "ES2015",对于 Node 项目。模块生成需要 "module": "commonjs",之后指定以下包含的 ts 文件即可。

{
  "compilerOptions": {
    "target": "ES2015",
    "module": "commonjs",
    "outDir": "./lib",
    "strict": true
  },
  "exclude": [
    "node_modules",
    "lib"
  ],
  "include":[
    "src/**/*.ts"
  ]
}

现在我们就可以愉快地写 TS 代码啦,试验一下写一个 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 {
  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);
    }
  }
}

注意这里我们可以直接使用 async/await,并对传入参数进行类型标记,如果你使用有插件支持的编辑器,这时可以感受到智能补全带来的愉快体验了。

npm build 一下可以在 lib/ 里面看到转译出来的 ES2015 代码,稍微看一眼,可以发现 async 是通过定义了一个 __awaiter 函数来进行的,感兴趣的同学可以自行研究。

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(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());
    });
};
CLI

通过 node file.js 可以运行一个脚本,但要怎样安装一个 npm 的可执行文件呢,根据 npmjs.com 的描述,在 package.json 中添加

{
    "bin": {
        "prune": "lib/cli.js"
    }
}

之后就可以安装一个 prune 到系统路径中,而执行的文件顶部需要添加 #!/usr/bin/env node,否则不会被识别为 Node 脚本。

为了读取命令行传入的参数,可以使用 args,在 src/cli.ts 中这段代码

const argv = yargs
  .usage("Prune node_modules files and dependencies

Usage: node-prune ")
  .option("config", {
    alias: "c",
    description: " 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").alias("version", "v")
  .argv;

const path = argv._[0] || "node_modules";
const configs = {
  config: argv.config,
  dryrun: argv.dryrun,
  verbose: argv.verbose
};

可以生成这样的结果:

$ prune -h
Prune node_modules files and dependencies

Usage: node-prune 

Options:
  --config, -c    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]

获取参数后就可以 import 你写的业务代码进行操作,这里略去,可以在 Github 看一下例子。

之后我们可以通过 npm publis 发布后 npm install -g pruner-cli 下载安装工具之后执行 prune 直接调用。

Async Test

测试代码同样需要使用 TypeScript 以及 async/await。选用 mocha 进行 BDD 风格的测试。chai 是一个 assertions 库,搭配使用效果佳。

$ npm install mocha ts-node -g
$ npm install mocha chai ts-node --save-dev

正常使用 mocha 会在 test/ 目录下执行 JavaScript,为了跳过转译直接测试 TS 代码,我们可以绑定 ts-node 直接执行测试代码,在 package.json 中加入:

{
    "scripts": {
        "test": "mocha -r ts-node/register test/**/*.spec.ts"
    },
}

于是 test/ 下所有的 *.spec.ts 都会被测试,并且可以使用 await 异步,expect 实现 BDD。一个例子。

Travis

在项目下添加 .travis.yml 后添加项目语言的配置

language: node_js
node_js:
  - "6"
  - "7"
  - "8"
  - "9"

然后在 https://travis-ci.org/ 添加自己开源的项目就可以在每次 push 时自动测试编译和 test。

点击 build|passing 后将图片的链接贴到项目的 README 中就可以在 Github 上显示 CI 的状态了!

原文地址

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90082.html

相关文章

  • 2019 - Web开发技术指南和趋势

    摘要:以下内容来自我特别喜欢的一个频道这是一个年你成为前端,后端或全栈开发者的进阶指南你不需要学习所有的技术成为一个开发者这个指南只是通过简单分类列出了技术选项我将从我的经验和参考中给出建议首选我们会介绍通用的知识最后介绍年的的一些趋势基础前端开 以下内容来自我特别喜欢的一个Youtube频道: Traversy Media 这是一个2019年你成为前端,后端或全栈开发者的进阶指南: 你...

    sourcenode 评论0 收藏0
  • 使用 TypeScript 改造构建工具及测试用例

    摘要:第一个完全使用重构的纯项目已经上线并稳定运行了。测试用例的改造前边的改为大多数原因是因为强迫症所致。但是测试用例的改造则是一个能极大提高效率的操作。 最近的一段时间一直在搞TypeScript,一个巨硬出品、赋予JavaScript语言静态类型和编译的语言。 第一个完全使用TypeScript重构的纯Node.js项目已经上线并稳定运行了。 第二个前后端的项目目前也在重构中,关于前...

    Cristic 评论0 收藏0
  • 前端每周清单第 45 期: Safari 支持 Service Worker, Parcel 完整教

    摘要:的另一个核心特性,苹果表示也正在开发中,按开发进度可能几个月后就能与我们见面。是基于的本地化数据库,支持以及浏览器环境。 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎关注【前端之巅】微信公众号(ID: frontshow),及时获取前端每周清单。 本期是 2017 年的最后一...

    赵春朋 评论0 收藏0
  • Ionic2入坑基础教程和安装指南

    摘要:安装程序主要通过命令行工具来创建和开发,并使用来构建和部署为原生应用程序。基础教程确保完成之前的安装并测试启动成功。 安装Ionic Ionic 2 程序主要通过Ionic命令行工具CLI来创建和开发,并使用Cordova来构建和部署为原生应用程序。也就是说我们需要先安装一些工具来实现程序开发。 安装Ionic CLI 和 Cordova 要创建 Ionic 2 项目,你需要安装最新版...

    jayce 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<