[譯文]一步步構建發佈一個 TypeScript NPM 包

原文:itnext.io/step-by-ste…javascript

介紹

在這篇文章中,咱們會使用 TypeScript, TSLint, Prettier, Jest 等構建併發佈一個 NPM TypeScript 包。下面將會是咱們要構建的:html

前提

  • 下載 Node.js 和 NPM。
    node -v // v8.12.0
    npm -v // v6.4.1
    複製代碼
  • 選一個好的包名。包名必須是 pascal-case 而且所有小寫。由於 NPM 上有 700k+ 的包,因此你須要在構建以前先去 www.npmjs.com/ 查詢你的包名有沒有被使用。在本文中,我取了 irene-awesome-gretter。

基本構建

  • 選擇一個合適的名字建立包文件夾。
    mkdir irene-awesome-greeter && cd irene-awesome-greeter
    複製代碼
  • 新建 .gitignore 文件並寫入 node_modules,新建 README 文件。
    echo "node_modules" >> .gitignore
    echo "# Irene Awesome Greeter" >> README.md
    複製代碼
  • Git 初始化包並關聯遠程倉庫。下面 Git Repository Url 是遠程倉庫的 Url。
    git init
    git add . && git commit -m "Initial commit"
    git remote add origin <Git Repository Url>
    git push -u origin master
    複製代碼
  • NPM 初始化包,後續咱們會修改生成的 package.json
    npm init -y
    複製代碼
    至此,生成的目錄結構以下:

添加 TypeScript as devDependencies

  • 下載 TypeScript。java

    npm i -D typescript
    複製代碼

    下載完後,在根目錄下多了 node_modules 文件夾和 package-lock.json 文件。node

  • 爲了編譯 TypeScript,咱們須要一個配置文件,在根目錄下新建 tsconfig.json,內容以下。⚠️注意我(譯者)在原文配置的基礎上添加了 lib,指定了 es6,緣由見 - 詳情git

    {
      "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "declaration": true,
        "outDir": "./lib",
        "strict": true"lib": ["es6"]
      },
      "include": ["src"],
      "exclude": ["node_modules", "**/__tests__/*"]
    }
    複製代碼

    下面解釋下配置文件字段:注意 ES6 = ES2015

    • target:編譯以後生成的 JavaScript 文件須要遵循的標準,可選值:"ES3"(默認),"ES5","ES6"/"ES2015","ES2016","ES2017"或"ESNext"。咱們選擇了 es5 爲了使包具備更好的瀏覽器兼容性。
    • module:指定生成哪一個模塊系統代碼,默認值:target === "ES3" or "ES5" ? "CommonJS" : "ES6"
    • declaration:是否生成對應的聲明文件,默認值:false。在構建包時,應該設置爲 true,這樣 TypeScript 會將生成的聲明文件和對應編譯後的 JavaScript 代碼一塊兒導出,以便包能夠在 TypeScriptJavaScript 項目中同時使用。本項目中生成的聲明文件是 /lib/index.d.ts。
    • outDir:指定輸出目錄。編譯後的 JavaScript 代碼會在與 tsconfig.json 同級的 lib 文件夾中。
    • strict:是否啓用全部嚴格類型檢查選項,默認值:false。
    • lib:編譯須要的庫文件,例如你指定的 target 是 ES5,可是在代碼中使用了 ES6 特性,就須要在 lib 中加上 ES6。默認值:若是 lib 沒有指定默認注入的庫的列表,默認注入的庫爲:
      • target ES5:DOM,ES5,ScriptHost。
      • target ES6:DOM,ES6,DOM.Iterable,ScriptHost。
    • include:指定要編譯的目錄。
    • exclude:指定不編譯的目錄。node_modules__tests__ 只是在開發階段使用,構建階段無需編譯。

    更多的編譯選項可參考 www.typescriptlang.org/docs/handbo…es6

  • 建立 src 文件夾,在其下新建一個 index.ts,內容以下:github

    export const Greeter = (name: string) => `Hello ${name}`;
    複製代碼
  • package.json 中添加 build script。typescript

    "build": "tsc"
    複製代碼

    在控制檯運行 npm run build,你會看到生成了一個新的 lib 文件夾,裏面是編譯後的 js 代碼和聲明文件。

  • 除了 package-lock.json 之外, 咱們通常都不但願提交自動生成的文件到 Git 上去,由於只要改變了源文件,每次 build 的時候它們都不一樣,就會形成不少衝突,因此咱們把 lib 文件夾放到 .gitignore 中。npm

    node_modules
    /lib
    複製代碼

Formatting & Linting

  • 下載 prettier tslint tslint-config-prettier。和 TypeScript 同樣,它們只是在包開發階段所需的工具,因此是 devDependencies。
    npm i -D prettier tslint tslint-config-prettier
    複製代碼
    一個好的包應該包括嚴格的代碼規範,尤爲是有其餘協做者共同開發時。tslint-config-prettier 能防止 TSLintPrettier 格式化規則的衝突。
  • 在根目錄下,新建 tslint.json,添加以下內容:
    {
      "extends": ["tslint:recommended", "tslint-config-prettier"]
    }
    複製代碼
  • 在根目錄下,新建 .prettierrc,添加以下內容:
    {
      "printWidth": 120,
      "trailingComma": "all",
      "singleQuote": true
    }
    複製代碼
  • 最後,在 package.json 中添加 lint 和 format script。
    "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
    "lint": "tslint -p tsconfig.json"
    複製代碼
    如今,你的 package.json 應該長這樣:
    在控制檯運行 npm run lint / npm run format
    npm run lint
    npm run format
    複製代碼

移除沒必要要文件

.gitignore 中,咱們添加 /lib 是由於不想 Git 遠程倉庫中有編譯後的文件,但對於要發佈的包則偏偏相反,咱們不要源代碼,只須要編譯後的文件!有兩種方式能夠實現:json

  • 黑名單:新建一個 .npmignore 文件,在其中添加不要的文件(夾)。
    src
    tsconfig.json
    tslint.json
    .prettierrc
    複製代碼
    可是,這並非一個好的實踐,由於根目錄下每次新增長一個文件(夾)都須要添加到 .npmignore 中,因而有了下面這種方式。
  • 白名單:在 package.json 中設置一個要發佈的文件(夾)白名單
    "files": ["lib/**/*"]
    複製代碼
    就是這麼的簡單!只有 lib 文件夾會出如今發佈的包裏(README.md 和 package.json 會被默認添加)。更多關於黑名單 VS 白名單的內容能夠參考 blog.npmjs.org/post/165769…

Jest Testing

一個好的包應該要包括單元測試。接下來,咱們添加 Jest —— Facebook 開發的一個很是棒的測試框架。

  • 由於咱們是針對 ts 源文件編寫測試用例,因此除了 jest 還須要 ts-jest @types/jest,它們只是在開發階段須要,因此添加到 devDependencies。
    npm i -D jest ts-jest @types/jest
    複製代碼
  • 配置 Jest。有兩種方式,在 package.json 添加 "jest" 字段 或者 新建一個單獨的配置文件。咱們選擇後者,由於前者配置內容會被添加到發佈的包中然後者不會。新建 jestconfig.json,添加以下內容:
    {
      "transform": {
        "^.+\\.(t|j)sx?$": "ts-jest"
      },
      "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
      "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
    }
    複製代碼
    移除 package.json 中的 "test" script,添加一個新的 test script。
    "test": "jest --config jestconfig.json",
    複製代碼
    如今,你的 package.json 長下面這樣:

寫一個測試用例

是時候寫一個測試用例了。在 src 目錄下,新建一個 __tests__ 文件夾,在其中新建一個測試文件,文件名必須以 test.ts 結尾,例如:Greeter.test.ts。

import { Greeter } from '../index';
test('My Greeter', () => {
  expect(Greeter('Carl')).toBe('Hello Carl');
});
複製代碼

這個測試用例驗證了當輸入 'Carl' 的時候,Greeter 方法是否返回 'Hello Carl'。 接下來咱們運行一下

npm run test
複製代碼

運行成功!能夠看到測試用例經過了。

scripts in NPM

一個好的包應該儘量自動化。接下來,咱們來看看 NPM 中其餘的 scripts:prepare,prepublishOnly,perversion,version,postversion

  • prepare:會在打包和發佈包以前以及本地 npm install (不帶任何參數)時運行。
    "prepare": "npm run build"
    複製代碼
  • prepublishOnly:在 prepare script 以前運行,而且僅在 npm publish 運行。在這裏,咱們能夠運行 npm run test & npm run lint 以確保咱們不會發布錯誤的不規範的代碼。
    "prepublishOnly": "npm run test && npm run lint"
    複製代碼
  • preversion:在發佈新版本包以前運行,爲了更加確保新版本包的代碼規範,咱們能夠在此運行 npm run lint
    "preversion": "npm run lint"
    複製代碼
  • version:在發佈新版本包以後運行。若是您的包有關聯遠程 Git 倉庫,像咱們的狀況同樣,每次發佈新版本時都會生成一個提交和一個新的版本標記,那麼就能夠在此添加規範代碼的命令。又由於 version script 在 git commit 以前運行,因此還能夠在此添加 git add
    "version": "npm run format && git add -A src"
    複製代碼
  • postversion:在發佈新版本包以後運行,在 git commit以後運行,因此很是適合推送。
    "postversion": "git push && git push --tags"
    複製代碼

截至目前,咱們的 NPM scripts 長下面這樣:

"scripts": {
  "test": "jest --config jestconfig.json",
  "build": "tsc",
  "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
  "lint": "tslint -p tsconfig.json",
  "prepare": "npm run build",
  "prepublishOnly": "npm run test && npm run lint",
  "preversion": "npm run lint",
  "version": "npm run format && git add -A src",
  "postversion": "git push && git push --tags"
}
複製代碼

終極版 package.json

{
  "name": "irene-awesome-greeter",
  "version": "1.0.0",
  "description": "A nice greeter", // 
  "main": "lib/index.js", // 
  "types": "lib/index.d.ts", // 
  "scripts": {
    "test": "jest --config jestconfig.json",
    "build": "tsc",
    "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
    "lint": "tslint -p tsconfig.json",
    "prepare": "npm run build",
    "prepublishOnly": "npm run test && npm run lint",
    "preversion": "npm run lint",
    "version": "npm run format && git add -A src",
    "postversion": "git push && git push --tags"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/irenetang1993/irene-awesome-greeter.git"
  },
  "keywords": ["Hello", "Greeter"], // 
  "author": "Irene Tang", // 
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/irenetang1993/irene-awesome-greeter/issues"
  },
  "homepage": "https://github.com/irenetang1993/irene-awesome-greeter#readme",
  "devDependencies": {
    "@types/jest": "^24.0.15",
    "jest": "^24.8.0",
    "prettier": "^1.18.2",
    "ts-jest": "^24.0.2",
    "tslint": "^5.18.0",
    "tslint-config-prettier": "^1.18.0",
    "typescript": "^3.5.2"
  },
  "files": [
    "lib/**/*"
  ]
}
複製代碼

咱們完善了 description,author,keywords 信息,修改了 main,新增了 typesmain 字段很是重要,由於指明瞭模塊的入口。types 字段指明瞭聲明文件的入口。

提交併推送到 Git

git add -A && git commit -m "Setup Package"
git push
複製代碼

發佈

在發佈以前,若是你沒有 NPM 帳號的話,必須先註冊一個。你能夠在 www.npmjs.com/signup 上註冊或者經過運行 npm adduser 註冊。若是你已經有帳號了,運行 npm login 登錄你的 NPM 帳號。

好了!如今你能夠發佈了。

npm publish
複製代碼

能夠看到,先運行 prepare script,在其中運行了 npm run build,而後運行 prepublishOnly script,在其中運行了 npm run test && npm run lint

查看你的發佈

如今,你能夠去 NPM 上查看你剛剛發佈的包。URL 是 https://npmjs.com/package/<your-package-name>,我發佈的包就是 npmjs.com/package/ire…

建立一個新版本

執行以下命令會建立一個新版本, preversion,version,postversion scripts 會被執行:建立一個新的 tag 而且推送到咱們的遠程倉庫。

npm version patch
複製代碼

咱們再發布一次:

npm publish
複製代碼

如今,咱們的包就有了一個 1.0.1 的版本:

其餘文章連接

TypeScript 踩坑之旅

[譯文]一步步構建發佈一個 TypeScript NPM 包

npm install package-lock.json 的更新策略

[譯]瀏覽器語言首選項

Date.prototype.toLocaleString()

相關文章
相關標籤/搜索