stylelint 接入實戰踩坑總結

greet_eason發表於2021-11-05

前言

團隊合作時,當每個人的程式碼都擁有自定義的格式化方式時,在提交merge的時候往往要解決很多衝突,此時我們可以使用eslint+stylelint來對團隊的程式碼進行約束。eslint的配置引入比較簡單,網上有比較多的教程,而stylelint的教程大多語焉不詳。在這裡,我會介紹一下我在引入stylelint所遇到的坑,以及解決方法。

正文

stylelint是一個強大的,現代的程式碼檢查工具,可以幫助你在團隊合作中強制執行樣式約定

1. 安裝stylelint

yarn add -D stylelint

2. 配置檔案

使用 stylelint檢測器需要一個配置物件,你可以使用三種方式來建立這個物件。

  • package.json 中的stylelint 屬性。
  • .stylelintrc.js檔案
  • stylelint.config.js 檔案輸出的js物件

一旦發現它們中的任何一個,將不再繼續進行查詢,進行解析,將使用解析後的物件。 本次使用的是.stylelintrc.js 檔案來進行配置。

3. 使用stylelint

安裝官方文件的說法你可以按照以下方法執行stylelint檢測樣式程式碼。

--fix 用來自動修復,但不能修復所有的問題。

// package.json
"scripts":{
  "lint:css":"stylelint src/**/*.css --fix"
}

踩坑點1:

由於我的專案裡使用的樣式語言是less。所以檢測css是肯定不對的,所以這裡我們需要做一點改動

// package.json
"scripts":{
  "lint:css":"stylelint src/**/*.less --fix"
}

於是我們可以執行這串程式碼了

yarn lint:css postcss-less

image.png

大家可以看到,這裡報了一些提醒,簡單翻譯為讓我們用對應的語法去解析我們的樣式。而這對應的語法解析器是需要我們去安裝的。

yarn add -D   postcss-less

於是再次對指令碼進行修改。

// package.json
"scripts":{
  "lint:css":"stylelint src/**/*.less --fix  --custom-syntax postcss-less"
}

OK 到這裡我們就可以正常的去跑lint命令對我們的樣式程式碼進行格式化了。接下來我們來配置lint規則

4. 配置規則

stylelint目前是有些工作者幫忙翻譯出了中文文件,如果對閱讀英文文件有一定排斥性的同學可以檢視中文文件

我們首先需要安裝三個npm包幫助我們完善規則

yarn add -D stylelint-config-standard stylelint-order stylelint-config-css-modules

stylelint-config-standard 是stylelint的推薦配置,stylelint-order是用來在格式化css檔案時對程式碼的屬性進行排序。 stylelint-config-css-modulescss-module的方案來處理樣式檔案

我的配置檔案長這樣:

// .stylelintrc.js
module.exports = {
    processors: [],
    plugins: ['stylelint-order'],
    extends: [
        "stylelint-config-standard",
        "stylelint-config-css-modules"
    ],
    rules: {
        "selector-class-pattern": [ // 命名規範 -
            "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
            {
                "message": "Expected class selector to be kebab-case"
            }
        ],
        "string-quotes":"single", // 單引號
        "at-rule-empty-line-before": null,
        "at-rule-no-unknown":null,
        "at-rule-name-case": "lower",// 指定@規則名的大小寫
        "length-zero-no-unit": true,  // 禁止零長度的單位(可自動修復)
        "shorthand-property-no-redundant-values": true, // 簡寫屬性
        "number-leading-zero": "never", // 小數不帶0
        "declaration-block-no-duplicate-properties": true, // 禁止宣告快重複屬性
        "no-descending-specificity": true, // 禁止在具有較高優先順序的選擇器後出現被其覆蓋的較低優先順序的選擇器。
        "selector-max-id": 0, // 限制一個選擇器中 ID 選擇器的數量
        "max-nesting-depth": 3,
        "indentation": [2, {  // 指定縮排  warning 提醒
            "severity": "warning"
        }],
        "order/properties-order": [ // 規則順序
            "position",
            "top",
            "right",
            "bottom",
            "left",
            "z-index",
            "display",
            "float",
            "width",
            "height",
            'max-width',
            'max-height',
            'min-width',
            'min-height',
            'padding',
            'padding-top',
            'padding-right',
            'padding-bottom',
            'padding-left',
            'margin',
            'margin-top',
            'margin-right',
            'margin-bottom',
            'margin-left',
            'margin-collapse',
            'margin-top-collapse',
            'margin-right-collapse',
            'margin-bottom-collapse',
            'margin-left-collapse',
            'overflow',
            'overflow-x',
            'overflow-y',
            'clip',
            'clear',
            'font',
            'font-family',
            'font-size',
            'font-smoothing',
            'osx-font-smoothing',
            'font-style',
            'font-weight',
            "line-height",
            'letter-spacing',
            'word-spacing',
            "color",
            "text-align",
            'text-decoration',
            'text-indent',
            'text-overflow',
            'text-rendering',
            'text-size-adjust',
            'text-shadow',
            'text-transform',
            'word-break',
            'word-wrap',
            'white-space',
            'vertical-align',
            'list-style',
            'list-style-type',
            'list-style-position',
            'list-style-image',
            'pointer-events',
            'cursor',
            "background",
            "background-color",
            "border",
            "border-radius",
            'content',
            'outline',
            'outline-offset',
            'opacity',
            'filter',
            'visibility',
            'size',
            'transform',
        ],
    }
};
  • processors 屬性由於此次並沒有使用,所以不做介紹,有興趣的同學可以查詢官方文件。
  • plugins 是由社群建立的規則或規則集,支援方法論、工具集,非標準 的 CSS 特性,或非常特定的用例。
  • extends 繼承一個已存在的配置檔案。(在我的配置中,繼承了css-module和官方推薦的配置)
  • rules 規則決定檢測器要查詢什麼和要解決什麼,所以,通過該選項你就可以開啟相應規則,進行相應的檢測。所有規則必須顯式的進行配置,因為 沒有預設值

另外還有 defaultSeverityignoreFiles也可以在這裡配置,有需要的同學可以在文件中找到。

由於我在配置檔案中已經對相應規則做了註釋,解釋了他的作用,如果有同學對此有疑問,歡迎留言或者加我好友進行交流~

注意: null為禁用規則。可以在rules裡面重寫覆蓋官方推薦的配置規則。

5. 忽略lint檔案

此時我們已經可以正常的使用stylelint來格式化樣式程式碼了。但是在專案中往往會存在一些不需要格式化的程式碼,比如我們會單獨抽離一個overrides檔案來重寫antd的樣式。顯然這裡是不需要格式化的,因為antd的選擇器命名可能跟我們的規範不盡相同。所以我們需要在執行lint時忽略這個檔案。

    1. 我們可以在.stylelintrc.js中配置ignoreFiles
    1. 建立.stylelintignore檔案。
    1. 我們可以通過 /* stylelint-disable */的方法,來對程式碼快進行忽略lint檢測。

我採用的是第二種方法,配置如下:

// .stylelintignore
*.js
*.tsx
*.ts
*.json
*.png
*.eot
*.ttf
*.woff
*.css
src/styles/antd-overrides.less

6. 自動格式化

在進行完上文的配置之後,其實我們已經達到了規範的目的,但是如果每次都要跑一次lint無疑就會加重我們的編碼負擔。這裡介紹兩種方式在我們寫樣式程式碼時,對程式碼自動格式化的方法。

6.1 stylelint vs-code 外掛

我們可以在vs-code外掛市場中搜尋stylelint外掛,它大概長這個樣子

image.png

可以看到我這裡是黑色的,這是因為我不用這個外掛,它有一些bug。

簡單介紹一下bug所在:

在antd-overrides中有一些程式碼過了我們配置的lint規則,但是沒有這個外掛會給我們報一個CssSyntaxError。而且在刪除一些問題程式碼之後,這個外掛還會報一些邏輯程式碼錯誤。這是我不能接受的。於是果斷棄用。大家可以按照自己專案實際情況進行選擇~

6.2 webpack plugin

你可以很輕鬆的找到webpack的stylelint-plugin。代表這個外掛已經廣泛使用~你可以放心的接入。

為什麼一個webpack外掛可以幫助我們格式化樣式程式碼呢,這是因為我們在熱更新重新編譯的時候,這個外掛會幫我們檢測程式碼。並根據.stylelintrc.js檔案中配置的規則進行fix。 如果有lint錯誤可以選擇讓專案無法執行,避免將沒有lint的樣式上傳到程式碼庫。

於是我在使用這個外掛的時候踩了好多坑,接下來我一一的說。

6.3 外掛踩坑集錦

最開始時。按百度到的各路大神的寫法,只需要這麼配置就可以:

new StyleLintPlugin({
    context: "src",
    configFile: path.resolve(__dirname, './stylelintrc.js'),
    files: '**/*.less',
    failOnError: false,
    quiet: true,
    syntax: 'less'
})

結局不出意料,沒有用。最恐怖的是他會給你一種假象,你本地執行的時候沒有任務問題,讓你誤以為你的程式碼沒有任何問題!其實,是這個外掛沒有作用到。

另外這麼配置如果使用stylelint的vscode擴充套件時,還會有一大堆的讓你心態爆炸的紅波浪~~~~

經過我的踩坑,終於完成了一個沒有報錯,沒有假象,沒有錯誤檢查,沒有忽略我的忽略配置的配置!

    new StylelintPlugin({
      configFile: path.resolve(__dirname, './.stylelintrc.js'),
      extensions: ['less'],
      files: 'src/**/*.less',
      fix: true,
      customSyntax: 'postcss-less',
      lintDirtyModulesOnly: true,
      threads: true,
      exclude: ['node_modules', 'src/styles/antd-overrides.less'],
    })

這裡我想詳細的解釋一下各欄位的用法。

  • configFile 沒什麼好說的,載入配置檔案。
  • extensions 指定要檢查的副檔名。 這裡一定要配置,不然會去檢測你的tsx。
  • files 指定檢測目錄。
  • fix 這個是重點。這就是自動格式化的關鍵配置所在。
  • customSyntax 這又是關鍵!!!! 一定要加這個配置,百度到的大佬配置中使用的是syntax。這個配置已經過時了,需要使用customSyntax,並且value一定要是你之前安裝過的postcss-less包。這個配置竟然連webpack官方文件中都沒有。我已經準備去提issue了
  • lintDirtyModulesOnly僅檢查有變化的檔案,啟動時跳過檢查。
  • threads 會根據 cpu 的數量自動決定池子的大小。
  • exclude 這個非常重要。因為我在實踐中發現webpack-plugin沒有讀取我在.stylelintignore中配置的忽略規則,而導致專案在執行時報了一大堆錯誤。一定要配!!!!

7. commit檢測

這個就比較簡單了,如果專案之前配置過eslint時的commit檢測,這裡只需要在指令碼中加入檢測樣式就可以。配置如下

  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --ext js,ts,tsx --fix",
      "git add"
    ],
    "*.less": [
      "stylelint --fix  --custom-syntax postcss-less",
      "git add"
    ]
  }

這裡其實是不需要跑yarn lint:css的,因為如果這樣在commit時會全量檢測所有src下的樣式,然而其實我們只需要檢測修改的檔案即可。特別注意: 一定要加上 --custom-syntax postcss-less

好了,到這裡我們就。。。。還沒結束。

我們來梳理一下stylelint的工作流程

  • .stylelintrc配置規則。
  • package.json配置指令碼命令
  • .stylelintignore配置忽略規則
  • stylelint-webpack-plugin配置自動格式化規則
  • lint-staged配置commit規則

首先執行專案時會去讀取.stylelintrc檔案,並根據裡面的規則通過webpack-plugin去檢查程式碼,自動格式化。在執行 lint:css時,會讀取.stylelintignore檢測時忽略相關檔案。在修改完程式碼後commit時lint-staged會幫我們在做一次提交前檢測,避免上傳沒有格式化的程式碼。

7.1 梳理流程時發現的坑

在我做完stylelint相關配置之後,開始了激情編碼環節。然而我根據設計圖去給元素設定一個帶有透明度的顏色rgba時。貼心的外掛就會幫助我,把rgba格式化成rbg顏色。像這樣:

image.png

自動格式化後,嘟 變成了這樣

image.png

rgb(0 0 0 / 12%) 這是什麼東西? 起初我並不在意,直到我發現了在頁面上這個樣式變成了這樣

image.png

這不是逗我嗎,你格式化就格式化,怎麼變成了這玩意???

image.png

於是連忙去百度,百度不到答案。。。然後又谷歌,終於找到了一個看起來像答案的答案

image.png

簡單解釋一下。這是一個比較新的css規範。sass規範還不支援。類比到我的less。也就是我的less規範還不支援。因為專案裡用的less版本是3+。還不是最新的。所以不支援簡直是再正常不過的事。我的less把我的新規範的帶透明度的rgb識別成了第三個引數後面的/是除法。0除以12%大聲告訴我是多少?還是0吧

所以我的less沒有錯 錯的是這個世界!

報著嘗試的心態我去瀏覽器直接寫了一個rgb(0 0 0 / 12%) 看看支不支援。結果如下:

image.png

沒錯,瀏覽器支援!那好辦了,擺在我們面前有兩個解決方法

  1. 讓less支援這種色值方案
  2. 讓stylelint不格式化

image.png

帶著方法我去查詢了less的官方倉庫的 changelog 我妄圖嘗試在最新版的更新裡哪怕提到半個rgb的字眼,然而並沒有。也可能是我的眼神不太好~~ 。 總之第一條方法失敗了。

那麼我們用第二種方法,首先要知道是stylelint的哪條規則把rgba格式化成了rgb。我做了大量的嘗試。並且做了大量的百度。不出我所料。百度不到。嘗試也都不對。路走窄了。

於是我換了一個思路,我去看看官方推薦的stylelint-config-standard 配置庫。如圖:大家注意紅框

image.png

在23版本時,顏色已經是百分比了。這也是最新版本,也是我專案裡的版本。那麼可以確定的是,一定是這個庫幫我格式化了!!!

那麼我們該怎麼讓他不格式化呢?去檢視這個庫其他的版本,但凡哪個版本里出現了rgba,那他這個版本就不會自動格式化。

功夫不負有心人。我只找了一個版本,就找到了

image.png

於是對專案裡的庫版本做降級處理~ ,這樣就不會把rgba格式化成rgb了! 大功告成。

後記

遇到問題不可怕,可怕的是百度不到答案。

如果百度不到還可以谷歌。 切記切記。

相關文章