auphone.net "揼曲"筆記
Written by Human, Not by AI

// 輕量版 NodeJS TypeScript Starter //

今天分享一下我的 TypeScript project 設定,當中包括了一些基本功能:

安裝和運行 #

先從 git 下載項目然後安裝模組

$ git clone https://github.com/auphone/node-typescript-starter.git
$ cd node-typescript-starter
$ npm install

打開兩個 terminalcmdshell,執行以下語句

第一個 terminal #

$ npm run watch-ts

另一個 terminal #

$ npm serve

最後打開瀏覽器測試 API

http://localhost:3000/api/env

全部指令 #

Tslint #

這是我的 tslint.json 設定,我覺得用 tslint --init 產生出來的設定太嚴緊了,所以修改了一下

{
  "rules": {
    "class-name": true,
    "comment-format": [true, "check-space"],
    "indent": [true, "spaces"],
    "one-line": [true, "check-open-brace", "check-whitespace"],
    "no-var-keyword": true,
    "quotemark": [true, "single", "avoid-escape"],
    "semicolon": [true, "always", "ignore-bound-class-methods"],
    "whitespace": [
      true,
      "check-branch",
      "check-decl",
      "check-operator",
      "check-module",
      "check-separator",
      "check-type"
    ],
    "typedef-whitespace": [
      true,
      {
        "call-signature": "nospace",
        "index-signature": "nospace",
        "parameter": "nospace",
        "property-declaration": "nospace",
        "variable-declaration": "nospace"
      },
      {
        "call-signature": "onespace",
        "index-signature": "onespace",
        "parameter": "onespace",
        "property-declaration": "onespace",
        "variable-declaration": "onespace"
      }
    ],
    "no-internal-module": true,
    "no-trailing-whitespace": true,
    "no-null-keyword": true,
    "prefer-const": true,
    "jsdoc-format": true
  }
}

paths 方便指向目錄 #

在 TypeScript 設定 paths 可以解決 import 很多層目錄時產生出的 ../,例如

import { app } from "../../../app";

這是我的 tsconfig.json,因為我同時有開發 Angular 所以使用了相似的設定

{
    "compilerOptions": {
      ...
      "paths": {
          "@app/*": ["*"],
          "@env/*": ["environments/*"]
      }
    }
}

設定好了以後我們就可以在任何地方用 @app 指向根目錄了

// 以前
import * as someModule from "../../modules/someModule";

// 現在我們可以寫成這樣
import * as someModule from "@app/modules/someModule";

然後我還會在每層資料夾設定一個 index.ts(barrel),再在裡面 export * 所有需要的模組

export * from "./server.model";

然後我們就可以這樣做

import * as fromModels from "@app/models/";

fromModels.doSomething();

Module Alias #

雖然 TypeScript 有 paths 的功能,但是在 NodeJS 我們不會用 WebPack,所以在 compile 的時候還是要自行添加一些設定,這邊我就用了 module-alias 這個模組,為了方便在不同環境和 unit test 的時候使用,我還會把它分拆成一個獨立模組使 spec 也能夠使用,而設定就跟 TypeScript 的 paths 指向一樣的地方

import * as alias from "module-alias";
import * as path from "path";

export const init = () => {
  alias.addAliases({
    "@app": __dirname,
    "@env": path.resolve(__dirname, "./environments"),
  });
};

Unit Test #

Unit Test 有幾種常用結構,我個人比較喜歡把 .spec 與模組放到同一個目錄亦即 src 內,也有人喜歡把它們全放在 test/ 內,都是因人而異,mochachai 也是個人喜好而採用的

import { expect } from "chai";
import * as path from "path";

// Init Alias
import * as alias from "../alias";
alias.init();

import * as fromServer from "./server.model";

describe("GET Environment", () => {
  it("should be equal to dev", () => {
    return expect(fromServer.getEnv()).eq("dev");
  });
});

Build #

預設有兩個指令,Dev 伺服器的 npm run build 和 Production 伺服器的 npm run build-prod,這邊只做了一個複製 environment.prod.tsenvironment.ts 的動作

後記 #

由於我經常會做很多 POC,但 Typescript 不像 JS 一樣只要一個 .js 那麼簡單,所以建立一個 starter 的確讓我省了不少時間