# 多平台 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 而被排在最前面。

原先我們這個專案最外層的 `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 也能使用相同的設定檔維持排版的一致性。