如何編寫型別安全的CSS模組

前端小智發表於2023-05-12
本文首發於微信公眾號:大遷世界, 我的微信:qq449245884,我會第一時間和你分享前端行業趨勢,學習途徑等等。
更多開源作品請看 GitHub https://github.com/qq449245884/xiaozhi ,包含一線大廠面試完整考點、資料以及我的系列文章。

快來免費體驗ChatGpt plus版本的,我們出的錢
體驗地址:https://chat.waixingyun.cn
可以加入網站底部技術群,一起找bug.

在這篇文章中,作者討論瞭如何在 CSS 模組中使用型別安全。由於 CSS 模組在執行時生成類名並在構建之間更改,因此很難以型別安全的方式使用它們。一種解決方案是使用 TypeScript 定義檔案為每個 CSS 模組手動建立型別,但更新這些檔案非常繁瑣。文章提出了一個問題,即假設在 CSS 模組中新增或刪除了一個類名。

下面是正文~

使用TypeScript的好處之一是它顯著減少了特定錯誤的發生,例如拼寫錯誤;它甚至使訪問原型方法和執行重構更加容易。在編譯時捕獲的錯誤可以提高正常執行時間,讓客戶更加滿意,並減少開發人員的緊急呼叫壓力。

使用TypeScript,很容易為我們的應用程式的業務邏輯和控制流程進行型別標註,但如果我們也能使CSS類安全,那該多好呢?確保正確的CSS類名已經就位可以確保所需的樣式應用於給定的元件,從而防止由於排版錯誤而導致樣式錯位。

在本文中,我們將討論CSS模組是什麼,探討它們的開發者體驗缺陷,並學習如何透過使用TypeScript自動化來解決這些問題。讓我們開始吧!

什麼是CSS模組?

CSS模組提供了一種在現代Web應用程式中編寫模組化和作用域CSS樣式的方法。這些樣式特定於你的應用程式的特定元件或模組。你可以使用常規CSS編寫CSS模組。

在構建時,使用 Vite 或其他類似的工具,CSS 模組為 CSS 檔案中定義的每個類生成唯一的類名。然後在 JavaScript 中使用生成的類名來引用 CSS,從而使 CSS 模組化和可重用,避免類名衝突或不必要的重複。

在撰寫本文時,CSS類名不再是全域性的,解決了許多像BEM這樣的方法論旨在解決的問題,但無需手動努力。然而,在CSS模組中遵循BEM仍然取決於用例而有益。

將 CSS 模組新增到你的專案中

如果你想在下一個 TypeScript 應用程式中使用 CSS 模組,則有幾個選項。

現代構建工具如 Vite 和 Snowpack 支援 CSS 模組化,但如果你使用的是 webpack,可能需要包含一些小的配置。

一旦構建設定完成,可以按照CSS模組約定新增帶有 module.css 副檔名的CSS檔案:

// button.module.css
.green {
    background-color: 'green';
}

.blue {
    background-color: 'blue';
}

.red {
    background-color: 'red';
}

為了應用這些樣式並利用上述好處,我們應該從 TypeScript 檔案中匯入 CSS 模組並繫結 HTML。請記住,下面的示例是用 React 編寫的,但語法與其他 UI 庫非常相似:

// Component.tsx
import styles from './button.module.css'

const Component = () => (
    <>
        <button className={styles.green}>I am green!</button>
        <button className={styles.blue}>I am blue!</button>
        <button className={styles.red}>I am red!</button>
    </>
)

如果你在本地執行上面的程式碼,您會注意到返回的 styles 沒有被嚴格限制型別。相反,它們被視為任何型別。此外,TypeScript 編譯器不會在類名不存在時通知你。

開發者體驗的改進

CSS模組是一個很好的工具,但由於類名是在執行時生成的並且在構建之間發生更改,因此很難以型別安全的方式使用它們。

你可以使用TypeScript定義檔案手動為每個CSS模組建立型別,但更新它們很繁瑣。假設從CSS模組中新增或刪除了一個類名。在這種情況下,必須手動更新型別,否則型別安全性將無法按預期工作。

對於上面的例子,輸入應該如下:

declare const styles: {
  readonly green: string;
  readonly blue: string;
  readonly red: string;
};
export default styles;

這些型別在我們修改相關的CSS模組之前都能很好地工作。一旦我們修改了它,我們就必須更新型別。如果我們忘記手動更新型別,可能會出現一些討厭的UI錯誤。

我們忘記修改相關的型別檔案:


// button.module.css.d.ts
declare const styles: {
  readonly green: string;
  readonly blue: string;
  readonly red: string; 
 we forgot to update the types! 

};
export default styles;


// Component.tsx
import styles from './button.module.css'

const Component = () => (
    <>
        <button className={styles.green}>I am green!</button>
        <button className={styles.blue}>I am blue!</button>
        <button className={styles.red}>I am red!</button>
    </>
)

在這個例子中展示的情況可能看起來不相關,但隨著程式碼庫和貢獻者數量的增長,這種重複和容易出錯的過程將會阻礙對型別系統的信任。引用不存在或打錯字的 CSS 類將無法按預期樣式化 HTML,這可能很快演變成開發人員失去對工具的信任。讓我們學習如何自動化它!

自動化

在這種情況下,自動化解決方案很簡單。我們將自動生成型別,而不是手動建立,並提供一個指令碼來驗證生成的型別是否最新,以避免不正確的 CSS 模組型別洩漏到編譯步驟中。

有多種方法可以實現這一點。例如,我們可以構建一個將 CSS 轉換為 TypeScript 定義的提取器。但是,為了避免重複造輪子,我們將利用開源包 typed-css-modules

使用 npm i typed-css-modules 在你的專案中安裝包,然後將型別生成新增到你的主開發指令碼中的 package.json 指令碼中:

"watch": "vite & tcm --watch .",

新增檢查最新型別的功能。如果生成的型別在 package.json 指令碼中不正確,則會失敗:

"check:up-to-date-types": "tcm --listDifferent .",

有了這兩個指令碼,現在可以自動保持 CSS 模組型別定義的同步,並檢查型別是否保持最新。

根據專案的不同,你可能更喜歡在本地或伺服器上執行這些指令碼,可能作為你的 CI 流水線的一部分。為了完善示例,我們將描述如何使用 husky 將它們作為 Git Hook 執行。

使用 npx husky-init && npm install 安裝並設定 Git Hook runner。要設定在每次提交之前執行 CSS 模組型別檢查的 pre-commit Hook,請將 .husky/pre-commit 檔案修改為以下內容:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run check:up-to-date-types

在每次提交之前,鉤子將執行並驗證型別是否最新。

總結

在TypeScript生態系統中工作具有巨大的潛力,但是,當過度依賴手動流程時,很容易破壞型別系統的信任或產生不必要的摩擦。

CSS模組非常棒,透過一些額外的配置,很容易為生成的類新增型別安全性。您應該自動化繁瑣的工作,以便你的團隊可以專注於構建出色的產品。

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章