# 多平台 Tailwind 排版 Elantris [TOC] --- ## 前言 公司有一個 React 專案環境是: - Vite - Husky - Prettier - [prettier-plugin-tailwindcss](https://github.com/tailwindlabs/prettier-plugin-tailwindcss) - Tailwind CSS 其中我們發現編輯器與 Husky pre-commit 的排版結果不一致,導致元件中 className 的內容一直被換位置,無端製造了很多不必要的改動。 ## 嘗試找出問題 ### 執行環境 一開始我覺得可能是作業系統的差別導致排版不一致的問題,畢竟其他同事都是用自己的 MacOS 只有我使用公司配備的 Windows 筆電。 但無論我重新安裝 nodejs、使用 WSL 等方式確保兩邊執行 prettier 時使用的 nodejs 都是指定的版本,問題依然存在。 而這時同事表示他們偶爾也會遇到同樣的問題,也許主因不是作業系統。 ### 理解排版規則 這個專案主要使用了 prettier-plugin-tailwindcss,它會將 `.jsx` 檔案中 className 的內容按照類型來排序。 如果遇到不是 Tailwind 提供的 class,這個 plugin 會將其排在最前面,並且維持這些陌生 class 彼此的原始排序。 它同時會去解析 `tailwind.config.js` 裡的自訂樣式,例如 `text-primary-500` 就會被視為 text 類別加入排序,跟其他 text 類別的屬性排在一起。 ### 重新觀察問題 仔細觀察這些位置錯亂的 className,主要都是自訂樣式在亂跑,當 prettier 錯誤解讀 Tailwind 設定時,自訂樣式會被視為陌生 class 而被排在最前面。 ![classname-diff](https://i.imgur.com/emaIEsH.png) 原先我們這個專案最外層的 `tailwind.config.js` 是根據環境變數中的 `APP_ID` 來產生: ```js export default { content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], theme: getTheme(env.APP_ID), } ``` 首先開啟 VSCode 的 Output Panel 仔細觀察 Prettier 的 log,按下排版的同時它會紀錄目標檔案的路徑與使用的設定。 這時才發現它不會動態載入更新後的設定檔,一旦 `prettier.config.js` 有任何變動都需要重新載入 extension。 再來是它無法根據環境變數中的 `APP_ID` 讀取動態生成的各平台 Tailwind 設定。 而使用 Prettier CLI 的時候它能夠正確解析環境變數中的 `APP_ID`、讀取正確的 Tailwind 設定,但同時這也顯現了另外一個問題:**當環境變數是 A 平台的時候它會用 A 平台的自訂樣式來排版 B 平台的檔案!** ## 動手解決 既然它無法動態生成,那解法自然就是將 Tailwind 設定檔改成純靜態檔案,而各個平台基本上需要客製的部分是 `theme`。 最外層的 Tailwind 設定檔一樣根據 `APP_ID` 動態產生: ```js // tailwind.config.js export default Object.assign({}, defaultConfig, configs[env.APP_ID]) ``` 各平台需要有自己獨立的 Tailwind 設定檔,但只需要 `theme` 的部分: ```js // src/[APP_ID]/tailwind.config.js export default { theme: { extends: { // ... } } } ``` Prettier 有提供 [Overrides](https://prettier.io/docs/en/configuration.html#configuration-overrides) 的方式,能夠根據元件檔案位置套用不同的設定選項。 使用 prettier-plugin-tailwindcss 提供的選項指定 Tailwind 設定檔路徑: ```json { "overrides": [ { files: "src/[APP_ID]/**/*.{js,jsx,ts,tsx,css,scss}", options: { tailwindConfig: "src/[APP_ID]/tailwind.config.js", }, }, ] } ``` 如此一來使用 VSCode Prettier 編輯檔案時就能根據檔案的路徑位置取得對應的樣式設定檔,同時 Husky 使用 Prettier CLI 也能使用相同的設定檔維持排版的一致性。