Angular代碼風(fēng)格

寫在前面

自身的良好編碼風(fēng)格只能律己,而無法律人;我喜歡 Angular 其中主要一個因素是有一整套的工具風(fēng)格指南,它可以極大的簡化團隊開發(fā)溝通成本,但是有些小缺失例如在編碼風(fēng)格上官方只提供 TypeScript 的部分,對于其他文件并沒有一套指南以及智能化。

VSCode 是我開發(fā) Angular 應(yīng)用的首選,本文也將以此 IDE 為基準(zhǔn);任何提到的擴展都可以通過市場來獲取。

Angular 應(yīng)用是由組件樹組成,一個組件從文件來看包含:TypeScript、HTML、Less(或其他 CSS 預(yù)處理器),其中 HTML 可能被包含至 ts 文件里。

當(dāng)然除此之外還包含一些 JSON 文件、Bash 文件等,當(dāng)此部分不在本文討論內(nèi)。

TSLint

Angular 創(chuàng)建后就已經(jīng)包含 tslint.json(它是 TSLint 的配置文件),并且所有默認規(guī)則都按官方風(fēng)格指南具體踐行。

而 TSLint 的配置文件,默認使用內(nèi)置預(yù)設(shè) tslint:recommended 版本,并在此基礎(chǔ)上加入 Angular 質(zhì)量檢查工具 codelyzer,所有這些規(guī)則你可以通過 tslint rulescodelyzer 找到每項規(guī)則的說明。

規(guī)則的寫法要么是 boolean 類型,或者使用數(shù)組對該規(guī)則指定額外參數(shù)。

運行 ng lint 命令時,當(dāng)你某個字符串變量使用雙引號,它會提示:

ERROR: /src/app/app.component.ts[9, 16]: " should be '

我們也可以安裝 TSLint 擴展讓這個觸發(fā)機制放在正在編碼過程中實時反饋:

  1. 當(dāng)有不符合風(fēng)格指南會出現(xiàn)一個綠色的波浪線,按 command+. > Fix: " Should be '
  2. 通過終端 PROBLEMS 面板查看所有已打開文件且不符合風(fēng)格指南的明細

嗯,讓你按五次 command+. 快捷鍵,我一定會瘋掉;TSLint 擴展支持在保存文件時自動修復(fù),只需要在項目根目錄 .vscode/settings.json 配置:

{
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  }
}

配置

tsline.json 有許多規(guī)則是針對任何 TypeScript,而 codelyzer 是專門針對 Angular,以下幾個可能你需要認識項:

directive-selectorcomponent-selector

限定 Direcitve、Component 的 selector 選擇器屬性值的風(fēng)格,默認必須是 app 開頭,有時候?qū)τ谝恍┕蚕硇徒M件設(shè)置不同的風(fēng)格,例如一個業(yè)務(wù)型富文本框 xx-editor,需要在 tslint.json 修改配置:

"directive-selector": [
  true,
  "attribute",
  ["app", "xx"],
  "camelCase"
],
"component-selector": [
  true,
  "element",
  ["app", "xx"],
  "kebab-case"
]

component-class-suffixdirective-class-suffix

指令或組件類名必須是寫駝峰命名法來命名,且必須使用 Component、Directive 后綴;若團隊可能已經(jīng)習(xí)慣類似 View 作為后綴,則:

"component-class-suffix": [true, "Component", "View"],
"directive-class-suffix": [true, "Directive", "View"]

use-life-cycle-interface

強制實現(xiàn)生命周期鉤子接口,例如 ngOnInit

export class HeroButtonComponent implements OnInit {
  ngOnInit() {
    console.log('The component is initialized');
  }
}

interface-name

TypeScript 指導(dǎo)原則不建議使用 “I” 前綴;因此建議增加:

"interface-name": [true, "never-prefix"]
// 錯誤寫法
export interface IUser {
  id: number;
}
// 正確寫法
export interface User {
  id: number;
}

美化

TSLint 并不支持美化(雖然有幾個項看起來像是在“美化”),而美化的工作取決于你采用什么 IDE,例如 VSCode 默認是使用 4 個空格表示一個 Tab 鍵。

EditorConfig

我不建議依賴 IDE 默認的代碼格式配置,所以就有一個 .editorconfig 組織來規(guī)范一些簡單的統(tǒng)一規(guī)范配置。

Angular 項目時也會有 .editorconfig 的配置,雖然有這個配置文件,但在 VSCode 也有自己的一套規(guī)范并且優(yōu)先級更高,所以要想讓 EditorConfig 生效需要額外安裝 EditorConfig for VS Code 插件。

Editorconfig 只包含一些最基礎(chǔ)的項,要想讓代碼統(tǒng)一風(fēng)格的美化還是需要更強大的 Prettier。

Prettier

她支持市場上許多語言,其中包含 TypeScript、HTML、Less 這一些都符合 Angular 項目的必備;你需要引入 prettier 以及 VSCode Prettier - Code formatter 擴展。

配置

在根目錄下創(chuàng)建 .prettierrc 配置文件以及 .prettierignore 忽略美化配置文件;Editorconfig 選項與 Prettier 選項高度重疊,并且后者會強制替換前者,例如:

# .editorconfig
indent_size = 4
# .prettierrc
{
  "tabWidth": 2
}

表示一個 Tab 寬度使用 2 個空格;我個人建議 Prettier 不應(yīng)該覆蓋 EditorConfig 的部分,它們包含:tabWidth、useTabsendOfLine。

而一個簡單的 Prettier 配置差不多這樣:

{
  // 單行最大長度
  "printWidth": 140,
  // 語句末尾添加分號
  "semi": true,
  // 使用單引號而非雙引號
  "singleQuote": true,
  // 尾逗號
  "trailingComma": "all"
}

如果你想忽略一些不想美化的文件,例如 Markdown,則 . prettierignore

*.md

同樣如果你期望每次保存文件時自動美化代碼,只需要在項目根目錄 .vscode/settings.json 配置:

{
  "editor.formatOnSave": true
}

Prettier 與 TSLint

Prettier 配置 項會有部分與 tslint.json 項重復(fù),例如:Prettier 的 printWidthtsline.jsonmax-line-length,對于 Prettier 以她為優(yōu)先,反之使用 ng lint 會以 tslint.json 優(yōu)先。

這對我們來說有些困惑,TSLint 包含了一些代碼”美化性"(例如:max-line-length),事實上,這更應(yīng)該是 Prettier 的專長(所有配置都跟代碼美化相關(guān))。

tslint-config-prettier

好在 tslint-config-prettier 幫助清理這些可能會產(chǎn)生沖突規(guī)則的解決方案:

"extends": [
  "tslint:recommended",
  "tslint-config-prettier"
]

prettier 提供一種檢查機制:

tslint-config-prettier-check ./tslint.json

你會發(fā)現(xiàn)默認的 Angular 項目中會有 max-line-length、object-literal-key-quotes、quotemark 三項是沖突的,我們可以關(guān)掉 tsline.json 這三項的配置,讓 Prettier 來代替。

{
  "rules": {
    "max-line-length": [false, 140],
    "object-literal-key-quotes": [false, "as-needed"],
    "quotemark": [false, "single"]
  }
}

HTML

Prettier 默認會自動識別 Angular 項目并使用其引擎,當(dāng)然也包含對 templatetemplateUrl 兩種寫法。

printWidth

會決定一段 HTML 超出長度范圍后屬性會自動換行:

<h1 style="color: #f50;" data-long="long" data-long-long="long" data-long-long-long="long" data-long-long-long-long="long">
  Share Component
</h1>

變成:

<h1
  style="color: #f50;"
  data-long="long"
  data-long-long="long"
  data-long-long-long="long"
  data-long-long-long-long="long"
>
  Share Component
</h1>

htmlWhitespaceSensitivity

空白敏感這一點同 Angular 的 preserveWhitespaces 類似,如果你的 Angular 項目配置了 preserveWhitespaces: false 則無須理會;反之設(shè)定不同的參數(shù)會影響美化的效果,若項目對空白敏感有需求可以設(shè)定為 strict 會強制清除空白,例如:

<h1
  style="color: #f50;"
  data-long="long"
  data-long-long="long"
  data-long-long-long="long"
  data-long-long-long-long="long"
  >Share Component</h1
>

Less

不管哪種 CSS 預(yù)處理器都可以使用 stylelint 作為代碼檢查工具,安裝 stylelint、stylelint-config-standard 并在根目錄 .stylelintrc 配置:

{
  "extends": [ "stylelint-config-standard" ],
  "plugins": [ ],
  "rules": { },
  "ignoreFiles": [ "src/assets/**/*" ]
}

package.json 定義一條:

{
  "scripts": {
    "lint:style": "stylelint 'src/**/*.less' --syntax less"
  }
}

若缺少 ; 會被收到 Missed semicolon 錯誤:

:host {
  width: 100px;
  height: 100px
  display: block;
}
src/app/app.component.less
 3:11  ?  Missed semicolon   CssSyntaxError

stylelint 有自己的一套規(guī)則,而 stylelint-config-standard 只是官方提供一種默認規(guī)則。

Prettier

前面提到 Prettier 也支持 Less,需要額外安裝依賴包 prettier-stylelint ,并修改 .stylelintrc 配置:

{
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-prettier"
  ],
  "plugins": [ ],
  "rules": {
    "selector-type-no-unknown": [
      true,
      {
        "ignoreTypes": [
          "/^app-/"
        ]
      }
    ],
    "selector-pseudo-element-no-unknown": [
      true,
      {
        "ignorePseudoElements": [
          "ng-deep"
        ]
      }
    ]
  },
  "ignoreFiles": [ "src/assets/**/*" ]
}

但是依然無法生效,由于在 VSCode 下面 EditorConfig for VS Code 擴展默認并沒有開啟它,在 .vscode/settings.json 增加:

{
  "prettier.stylelintIntegration": true
}

加上之前已經(jīng)開啟保存時自動修復(fù)功能,同樣也適用 Less 即保存時根據(jù) .stylelintrc 配置修復(fù)及美化。

一些有趣的插件

stylelint-config-rational-order

Css 語言同一類型的相關(guān)屬性可能會很多,而將這些相關(guān)屬性進行分組對于維護非常有幫助,安裝 stylelint-order、stylelint-config-rational-order,并修改 .stylelintrc 配置:

{
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-rational-order",
    "stylelint-config-prettier"
  ],
  "plugins": [
    "stylelint-order"
  ],
  "rules": { },
  "ignoreFiles": [ "src/assets/**/*" ]
}

stylelint-declaration-block-no-ignored-properties

當(dāng)設(shè)置 display: inline 內(nèi)聯(lián)時,此時再寫 width: 100px 是無意義的,而該組件可以自動移除這種無效屬性。

{
  "plugins": [
    "stylelint-declaration-block-no-ignored-properties"
  ],
  "rules": {
    "plugin/declaration-block-no-ignored-properties": true,
  }
}

智能點

至此,涉及 Angular 所需要的代碼風(fēng)格運用已全部完結(jié),這些檢查我們都大多數(shù)是依靠 VSCode 編輯器的擴展輔助完成。

事實上,我們只需要增加幾個命令來對整個項目進行檢查,確保整個項目的代碼能按所配置的風(fēng)格執(zhí)行。

命令行

{
  "scripts": {
    "lint": "npm run lint:ts && npm run lint:style",
    "lint:ts": "tslint -p tsconfig.app.json -c tslint.json 'src/**/*.ts' --fix",
    "lint:style": "stylelint 'src/**/*.less' --syntax less --fix"
  }
}

tslint、stylelint 命令行對應(yīng)的參數(shù)說明,都可以通過上述提供官網(wǎng)找得到。

運行 npm run lint 可以對整個項目進行檢查及修復(fù);若有包含 CI 可以直接使用它。

Git

如果可以將這一過程在向源碼倉庫提交代碼時進行檢查的話,可以在向代碼倉儲提交前就發(fā)現(xiàn)問題,需要安裝 huskylint-staged,并且修改 package.json

{
  "lint-staged": {
    "src/**/*.ts": [
      "npm run lint:ts",
      "git add"
    ],
    "src/**/*.less": [
      "npm run lint:style",
      "git add"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }
}

當(dāng)向源碼倉庫 Commit 時會自動先執(zhí)行命令行才會 git add。

總結(jié)

當(dāng)我寫完最后一節(jié)時,Angular8 發(fā)布了正式版;所以我把原本準(zhǔn)備的樣板項目 ng-code-style-boilerplatef526a0c) 切換成 Angular8,但完全適用 Angular7.x 版本。

Angular 風(fēng)格指南中文版)對于喜愛 Angular 是必讀、常讀的文章,它指引團隊更友好的編寫代碼,個人良好編碼風(fēng)格可能律己,但無法律人,而這種風(fēng)格指南可以減少無差別的團隊溝通。

本文雖然以 Angular 的角度出發(fā),但大部分內(nèi)容同樣適用 React、Vue 等。

(完)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容