天天看點

Angular Schematics 三部曲之 Add

Angular Schematics 三部曲之 Add

因工作繁忙,差不多有三個月沒有寫過技術文章了,自八月份第一次編寫 schematics 以來,我一直打算分享關于 schematics 的編寫技巧,無奈還是拖到了年底。

Angular Schematics 是非常強大的一個功能,可以快速初始化項目,也可以自定義元件模闆。在去年 schematics 釋出以來,已經有部分開發者在項目中嘗試使用,但是學習資料還是比較匮乏。目前官網已經有了 schematics 的簡易教程,但在實際開發中僅靠官方教程還是會遇到很多問題。在開發 Ng-Matero 的過程中,編寫 schematics 就像闖關一樣,從 <code>ng add</code> 到 <code>ng generate</code> 再到 <code>ng update</code>,每個部分都耗費了部落客大量的精力,翻閱了無數源碼才得以實作。

在這個系列文章中,我将以 Ng-Matero 為例講解 schematics 開發過程中遇到的難點,梳理開發流程,幫助大家開發自定義的 schematics 生成器。

該系列文章的三部分将分别介紹 Add、Generation 以及 Update,即使分了三部分來講解 schematics,但我相信依然無法介紹的面面俱到。那遇到問題應該怎麼辦呢?沒錯,你需要看源碼,這聽起來可能讓人心生畏懼,但是不用緊張,閱讀源碼并沒有你想象的那麼困難。順便說一下,無論編寫元件庫還是 schematics,<code>Angular Material</code> 的源碼都是最好的教材。

在繼續閱讀文章之前,請務必将官網的 Schematics 教程撸一遍,有關方法的說明可以參考 Schematics 的 README 。

在我目前見過的項目中,<code>ng add</code> 主要有兩個用途:

初始化元件庫(比如 angular material,ng-zorro,ngx-bootstrap)

初始化項目模闆(比如 ng-matero,ng-alain)。

初始化元件庫相對簡單一點,有些庫的 <code>ng add</code> 甚至等同于 <code>npm install</code>。

相比之下,初始化項目模闆要複雜很多,不僅要對項目進行配置,還要對項目中的檔案進行增删改等操作。

本文将以初始化項目模闆為例介紹 <code>ng add</code> 的執行過程。

假設你的根目錄有一個 schematics 的檔案夾。

Angular Schematics 三部曲之 Add

在官網的教程中,已經列出了 schematics 目錄的兩種風格:

1、你可以在 schematics 檔案夾中單獨安裝 <code>node_modules</code>,這樣你在 <code>package.json</code> 中定義 scripts 的時候邏輯會比較清晰,但是整個項目會有兩套 <code>node_modules</code>,而大部分依賴都和根目錄重複;

2、另外也可以複用根目錄的 <code>node_modules</code>,這樣的話就會減少不必要的安裝了

使用 Angular CLI 來建立項目的話一般來說就是第一種情況,比如建立一個庫或者建立一個 schematics,核心檔案都會放在 src 目錄。

注意:使用 Angular CLI 的預設目錄對于 Generation 指令比較友好,Angular CLI 添加的預設路徑為 <code>src/app</code> 或者 <code>src/lib</code> 等,如果我們修改了預設目錄,則在使用 <code>ng generate</code> 指令時需要顯式的設定 <code>--path</code> 參數。

因為 schematics 就是一套執行腳本,是以在項目釋出之前需要将 schematics 的編譯檔案複制到項目目錄,否則也無法使用 schematics。

如果你開發的是一套元件庫,那麼你需要将 schematics 編譯的檔案拷貝到元件庫中一起釋出;

如果你開發的是一個項目模闆,那麼隻需要釋出 schematics 就可以了。

因為 schematics 目錄也是一個項目目錄,是以你可以在 schematics 的 <code>package.json</code> 中定義拷貝指令,和官網教程是一樣的,但是更恰當的方式應該是将複制指令寫在根目錄的 <code>package.json</code> 中。

現在我們可以開始 ng add 的編寫了,簡單梳理一下,如果要使用 schematics 添加項目檔案,我們需要做什麼?

初始化項目代碼(提供模闆配置項等)

删除 ng new 生成的重複檔案(因為 schematic 無法自動替換檔案)

把原始項目模闆檔案拷貝到項目目錄

調整一下 package.json 和 angular.json

添加一些額外的 module

執行 npm install 安裝 package

以下是 <code>@angular/material</code> 的 <code>ng add</code> 邏輯,<code>ng-matero</code> 與此類似。

Angular Schematics 三部曲之 Add

在 schematics 中,我們可以通過 <code>NodePackageInstallTask</code> 方法安裝 package

初始化的過程是先将依賴包添加到 package.json 中,然後執行 <code>npm install</code>,以上代碼實際執行了兩次 <code>npm install</code>,在執行 Add 主邏輯之前,首先安裝了 cdk,parse5 等依賴包。

除了在代碼中安裝依賴以外,也可以在 schematics 的 package.json 中定義 cdk、parse5,隻要保證在執行 Add 主邏輯的時候已經安裝了上述包即可,但是這種方式過于死闆,在 package.json 中更新依賴包的版本号有些繁瑣。

在執行 <code>ng add</code> 拷貝項目模闆的時候,會有一些需要更新的檔案,但是 schematics 沒有辦法直接替換這些檔案,是以必須先删除再拷貝,如果沒有提前删除重複的檔案,則會報錯終止。

以下是安裝 Ng-Matero 時對 <code>ng new</code> 生成的項目檔案進行删除的方法。

注意:在删除檔案時先要周遊檔案确定目錄中有該檔案再删除,否則同樣會報錯終止。

在執行完一系列規則之後,最終需要将 <code>files</code> 檔案夾中的檔案複制到項目目錄,直接拷貝整個檔案夾就可以,方法如下:

在拷貝完成之後,指令行會列出檔案的建立、更新等資訊。

關于 <code>chain</code> <code>mergeWith</code> <code>apply</code> <code>template</code> 等方法的使用詳見 Schematics 的 README ,不過 Schematics 的 README 上面的方法并不全,很多方法還是需要參考 <code>@angular/material</code> 以及其它庫的使用方式。

簡單說一下 <code>template</code> 和 <code>applyTemplates</code> 的不同之處:

<code>template</code> 作用于原始檔案

<code>applyTemplates</code> 作用于字尾名為 <code>.template</code> 的檔案。

添加 <code>.template</code> 字尾的檔案可以避免 VS Code 報錯。

schematics 中的 <code>files</code> 模闆檔案是從 Ng-Matero 項目中拷貝的,拷貝方式有多種,可以通過 shell 指令,也可以通過 gulp,這取決于你的喜好。

JSON 檔案的修改非常簡單,比如在 <code>angular.json</code> 中添加 hmr 的設定。

對于 JSON 檔案的修改主要用到的就是 <code>overwrite</code> 方法。而對于非 JSON 檔案的修改,相對麻煩一點,比如添加 hammer.js 的聲明:

關于 <code>host.beginUpdate</code>、<code>recorder.insertRight</code>、<code>host.commitUpdate</code> 這幾個方法,可以看一下 angular cli 的源碼。

除了上述提到的方法之外,在修改檔案的時候,還可能用到 <code>AST</code>,需要更精細的操作代碼檔案,我會在 Generation 部分重點講解。

在編寫 schematics 的時候,調試很重要,簡單說一下關于調試的問題以及技巧。

編寫完 schematics 之後,我們需要通過 npm link 進行測試。假設我們已經在項目的根目錄建立了一個測試項目。npm link 其實就是将打包目錄的快捷方式拷貝到 <code>node_modules</code> 中。

<code>ng add</code> 的測試比較麻煩,如果将模闆安裝到項目之後,再次測試需要重新初始化一個 ng 項目。另外,切記在 npm link 之後,執行 <code>ng add</code> 之前,先删除 <code>package-lock.json</code> 檔案,否則 npm link 的項目會被更新删除。

有時為了更友善的測試,可能需要直接更改 <code>node_modules</code> 中的源代碼,其實編譯後的代碼并非難以辨認,和原始檔案差别并不是很大。這些問題也會在 Generation 部分重點講解。

在最開始寫 Ng-Matero 這個項目的時候,我一直覺得 schematics 是最關鍵的組成部分。為了讓 Ng-Matero 不僅僅隻是一個模闆項目,我耗費了大量精力實作了一套比較簡單的 schematics,這讓我多少感到欣慰,也希望大家在使用 Schematics 時候可以提出更多寶貴意見。

本文拖沓了很久,但是依然比較表淺,如果大家有什麼問題,歡迎留言評論,或者加入 Ng-Matero 自主群。

Angular Schematics 三部曲之 Add

感謝您的閱讀,如果您對我的文章感興趣,可以關注我的部落格,我是叙帝利,下篇文章再見!

開發低代碼平台的必備拖拽庫 https://github.com/ng-dnd/ng-dnd

基于 Angular Material 的中背景管理架構 https://github.com/ng-matero/ng-matero

Angular Material Extensions 擴充元件庫 https://github.com/ng-matero/extensions

仿 Windows 照片檢視器插件 https://github.com/nzbin/photoviewer

仿 Windows 照片檢視器插件 jQuery 版 https://github.com/nzbin/magnify

完美替代 jQuery 的子產品化 DOM 庫 https://github.com/nzbin/domq

簡化類名的輕量級 CSS 架構 https://github.com/nzbin/snack

與任意 UI 架構搭配使用的通用輔助類 https://github.com/nzbin/snack-helper

單元素純 CSS 加載動畫 https://github.com/nzbin/three-dots

有趣的 jQuery 卡片抽獎插件 https://github.com/nzbin/CardShow

懸疑科幻電影推薦 https://github.com/nzbin/movie-gallery

鍛煉記憶力的小程式 https://github.com/nzbin/memory-stake