昨天寫了一個小工具,可以自動將現有 Angular CLI 建立的專案,轉換成有 Hot Module Replacement (HMR) 功能的版本,只要簡單一個命令 ng add hmr-enabled
就可以搞定,非常方便。不過我在發布專案到 npm registry 的過程中,卻意外遺漏了幾個重要的檔案,原來是有檔案被 .npmignore
給忽略掉了,到了今天傍晚才修復。我們就立刻來看看這個錯誤是怎樣發生的!
建立 Angular Schematics 專案
這邊我就先示範一個簡單的 Schematics 程式產生器設計過程。
-
安裝開發工具
npm install -g @angular-devkit/schematics-cli
-
建立專案骨架
schematics blank --name=willh
如果你想建立一個含有範例程式的專案,也可以考慮用以下命令建立範本:
schematics schematic --name=willh-with-example
上述兩種語法,也有另外一種寫法,不過比原本的指令會長很多:
schematics @schematics/schematics:blank --name my-schematics-1
schematics @schematics/schematics:schematic --name my-schematics-2
-
安裝 npm 套件
cd willh
npm install
建立第一支程式碼產生器
這邊我來示範一個可以自動產生 /src/environments/environment.{name}.ts
檔案的程式產生器,而且只要執行 ng g willh:env hmr
就會自動產生 /src/environments/environment.hmr.ts
檔案。我們第一版先不用做太複雜,產生固定的內容就好。
-
檢查 package.json
所定義的 schematics
設定,預設會指向 ./src/collection.json
這個檔案。
-
調整 src/collection.json
檔案內容如下:
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"env": {
"description": "generates environment file",
"factory": "./env/index#env",
"schema": "./env/schema.json"
}
}
}
-
建立 src/env/schema.json
檔案,讓程式可以接受 name
參數,並且讓 name
參數直接接在參數列上,不用特別透過 --name
選項進行設定。檔案內容如下:
{
"$schema": "http://json-schema.org/schema",
"id": "EnvSchema",
"title": "Env Schematics Schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the environment.",
"$default": {
"$source": "argv",
"index": 0
}
}
}
}
-
建立 src/env/index.ts
檔案內容如下:
import {
Rule, mergeWith, template, apply, url
} from '@angular-devkit/schematics';
export function env(options: any): Rule {
return () => {
return mergeWith(
apply(url('./files'), [
template({
name: options.name
})
])
);
};
}
-
建立一個 src/env/files/src/environments/environment.__name__.ts
檔案,檔名的部分 __name__
會在產生檔案的時候,動態置換成 name
參數的內容。
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* In development mode, for easier debugging, you can ignore zone related error
* stack frames such as `zone.run`/`zoneDelegate.invokeTask` by importing the
* below file. Don't forget to comment it out in production mode
* because it will have a performance impact when errors are thrown
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
-
建置專案
npm run build
-
本地測試安裝
npm link
執行 npm link
會將目前專案自動連結到 npm 的全域模組中。
-
本地測試執行
透過全域的 schematics
工具就可以執行這個命令。如下範例命令執行完後,就會自動產生 /src/environments/environment.ok.ts
檔案:
schematics willh:env ok
-
在 Angular CLI 專案中透過 ng generate
進行測試
要在特定專案中執行 ng generate
的話,必須透過本地 npm 安裝才能使用。你可以直接透過 npm install <folder>
直接將開發中的目錄,當成套件安裝到目前的 Angular 開發專案目錄中。
npm install G:\Projects\willh
安裝好之後,就可以順利的使用 ng g willh:env ok
命令來產生檔案。
準備發行 npm 套件
一切準備就緒的時候,就是魔鬼出現的時刻!
我今天就是發現到,透過 schematics blank
產生的專案範本,預設所建立的 .npmignore
檔案是有問題的。這份檔案,主要是將 *.ts
檔案從發行檔案中排除,只留下 TypeScript 編譯後的 *.js
檔。但留下所有 *.d.ts
模組定義檔。檔案內容如下:
# Ignores TypeScript files, but keeps definitions.
*.ts
!*.d.ts
這個 .npmignore 檔案,最主要的目的,就是讓 npm 套件在發布的時候,將特定檔案/目錄排除在發行的檔案清單中。正常來說,排除掉 *.ts
與保留 *.d.ts
是蠻合理的。但在我們本次建立的 Angular Schematics 專案中,有個 src/env/files/
目錄,裡面的檔案預設會原封不動的合併到目的專案中,所以無論如何,這裡面的檔案,都是不能被排除的。
原則上來說,.npmignore
的內容格式與 .gitignore
完全一致,應該不會太難理解才對。我從發現這個問題後,就做出了幾種不同的嘗試,但是都是不對的,感覺頗地雷,各位要小心!
首先,先教大家怎樣在 npm 發行之前,如何才能預先知道有哪些套件會上傳到 npm registry 之中。這個命令,就是:
npm pack
這個命令執行完後,預設就會將所有要發行的檔案,打包成 {name}-{version}.tgz
的壓縮檔,你從壓縮檔案中,就可以得知會發布哪些檔案,不需要等 npm publish
之後才進行測試。
以下我列出幾個錯誤的嘗試:
-
嘗試將 /src/env/files/
目錄排除在忽略清單外,避免 /src/env/files/
目錄下的 *.ts
檔被排除掉了!(失敗)
*.ts
!*.d.ts
!/src/env/files/
-
由於設定完全無效,所以調整一下 /src/env/files/
的順序到第一順位,但依然無效!(失敗)
!/src/env/files/
*.ts
!*.d.ts
到最後,我終於理解到一件官網文件沒有寫的細節。那就是 如果你將特定檔案類型加入到忽略清單裝,如果要透過 !
再把檔案加回來,那就必須要寫成針對定檔案進行描述,不能直接透過「特定目錄」進行設定!
最後,正確的寫法如下:
*.ts
!*.d.ts
!src/*/files/**/*
寫成這樣也可以:
*.ts
!*.d.ts
!src/**/files/**/*
是不是很雷!真的遇到了才會知道啊!
相關連結