tailwind config 使用 ESM

Lastor
Code 隨筆放置場
5 min readFeb 22, 2023

給自己筆記一下。有用過 tailwind + vite 的話,應該會注意到 tailwind 使用的是 CommonJS 的 module 格式,而不是 ES6 Module。

所以配合預設採用 ESM 的 vite 使用時,需要將 postcss 與 tailwind 的設定檔改為 .cjs 才能運作。

// postcss.config.cjs

/** @type {ProcessOptions & { plugins?: AcceptedPlugin[] }} */
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}

註: postcss 的設定檔 type 可以參考 Vite 文件,tailwind 跟 postcss 官網都沒寫。

// tailwind.config.cjs

/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,js}"],
theme: {
extend: {},
},
plugins: [],
}

這設定是 tailwind 官網給的 example。可以看出,採用的是 CommonJS 規格。

大部分使用情境這樣就夠了,但這次碰到一個需求,希望把 theme 設定寫在外面跟其他 UI 庫共用,讓各自 import 進來,這下就碰到問題了。

如果外部設定檔用 ESM 寫,就無法 import 到 CJS 的 tailwind config。但如果用 CJS 來寫,就無法 import 到其他使用 ESM 的檔案……

後來研究老半天,發現網上其實有解。

這篇樓主遇上跟我一樣的問題,他直接跑去 Vite 官方 Discord 詢問,結果真問到了一種寫法。雖然他沒說原理,但乍看之下,重點在於最後把 postcss config 給引入到了 vite 集成打包。

由於改成了 ESM 格式,所以也能直接換成 typescript。

// postcss.config.ts
import tailwind from 'tailwindcss'
import autoprefixer from 'autoprefixer'
import tailwindConfig from './tailwind.config'
import type { ProcessOptions, AcceptedPlugin } from 'postcss'

const config: ProcessOptions & { plugins?: AcceptedPlugin[] } = {
plugins: [
tailwind(tailwindConfig),
autoprefixer,
],
}

export default config

postcss 這邊要注意,原本 plugins 是用 object,這邊改成了 array。這個注意點其實 vite 的文件也有寫。

// tailwind.config.ts
import type { Config } from 'tailwindcss'

const config: Config = {
content: ["./src/**/*.{html,js}"],
theme: {
extend: {},
},
plugins: [],
}

export default config

tailwind 基本上一樣,只是改成了 ESM 跟 typescript 上型別而已。

然後最重要的動作,把 postcss config 引入給 vite config 使用。

import postcss from './postcss.config'

export default defineConfig({
// ...
css: { postcss },
})

這樣修改一波,就可以讓 tailwind config 順利使用 ESM,並且 import 其他基於 ESM 的 js / ts 檔案。

原理上,猜測是原本 tailwind 編譯主導的是 postcss,但它是用 CJS 寫的,所以無法改成 ESM。這邊將其用 vite 規定的 plugins 格式改寫 postcss config,導入到 vite 之後,編譯的主導者就變成了 vite,然後內部運作就稀哩呼嚕解決了。

注意點

使用這種作法雖然可以 work,可這其實不是完美解…… 終究 tailwind 現況仍舊是用 CJS 寫的,這問題會反映在 VScode 的 tailwind 插件上面。

如果我們改用了 ESM 來寫 config,那 tailwind 的語法提示插件就會直接陣亡,因為它看不懂基於 ESM 的 tailwind config。

万策尽きた!!

不依賴這個插件的人或許不影響,但我個人覺得少了這插件寫起來的爽度差異非常巨大。

所以最後還是默默地退回 .cjs,然後把共用的 theme 設定檔改用 json 來寫,這樣管你是 ESM 還是 CJS 都能 import 了。

tailwind 的 ESM 支援問題,官方有在 issues 回說這是有計畫要處理的事,只是時間還沒定下,只能等官方更新了。

--

--

Lastor
Code 隨筆放置場

Web Frontend / 3D Modeling / Game and Animation. 設計本科生,前遊戲業 3D Artist,專擅日本動畫與遊戲相關領域。現在轉職為前端工程師,以專業遊戲美術的角度涉足 Web 前端開發。