前段时间探索了 Next.js,很是惊讶于它对各种前沿特性(如 RSC)的支持。但囿于 RSC 和 Next.js 在最近可谓是漏洞不断(比如大名鼎鼎的 CVE-2025-55182),加上仔细思考之后意识到很多情景并不需要 SSR 或者 RSC,我决定返回 CSR 的领域。
在各种项目搭建工具都很成熟的当今,已经没必要从零开始手搓 webpack 配置了——我选择的工具是 Vite。Vite 会帮助你配置大部分的组件,如打包器、TypeScript、React、ESLint。一些额外的组件,比如 React Router、i18next、Stylelint、Prettier,也很容易添加。唯一有点麻烦的,是让 TailwindCSS 和 Ant Design 共存,并且共享暗黑模式的状态。这里记录一下我的配置思路和过程。
TailwindCSS
在 Vite 中使用 TailwindCSS 首先需要安装以下包:
1
| pnpm add -D tailwindcss @tailwindcss/vite
|
接着,修改 vite.config.js:
1 2 3 4 5 6 7 8
| import { defineConfig } from 'vite' + import tailwindcss from '@tailwindcss/vite'
export default defineConfig({ plugins: [ + tailwindcss(), ], })
|
最后,修改顶层 CSS 文件:
这样就可以开始使用 TailwindCSS 了。
Ant Design
在 Vite 中使用 Ant Design 只需要安装以下包:
1
| pnpm add antd @ant-design/cssinjs
|
需要注意的是,Ant Design 默认不使用 CSS 的 @layer,而 TailwindCSS 使用,因此 Ant Design 的样式会直接覆盖 TailwindCSS 的样式。为了解决这个问题,需要让 Ant Design 也使用 CSS 的 @layer 并手动配置不同分层的优先级。
在顶层组件中,用 <StyleProvider> (来自 @ant-design/cssinjs)包裹应用组件:
1 2 3 4 5 6 7 8 9 10 11 12
| + import { StyleProvider } from '@ant-design/cssinjs'; + import { ConfigProvider } from 'antd';
export default () => { return ( + <StyleProvider layer> + <ConfigProvider> <App /> + </ConfigProvider> + </StyleProvider> ); };
|
同时,在顶层 CSS 中,配置不同分层的优先级:
1 2 3
| + @layer theme, base, antd, components, utilities; + @import 'tailwindcss';
|
暗黑模式
TailwindCSS 的 dark: 变体默认由 prefers-color-scheme 媒体查询决定是否激活,而媒体查询并不受 JavaScript 控制。Ant Design 的暗黑主题则需要通过 React 状态控制。为了能统一控制它们的暗黑模式的开关,需要做以下几件事。
首先,在顶层 CSS 中,让 TailwindCSS 根据 <html> 标签上是否存在 class="dark" 来决定是否激活 dark: 变体:
1 2 3 4 5
| @layer theme, base, antd, components, utilities;
@import "tailwindcss"; + + @custom-variant dark (&:where(.dark, .dark *));
|
接着,安装 usehooks-ts,它提供了 useDarkMode() 等钩子来管理暗黑模式状态:
最后,在顶层组件中,用 useDarkMode() 获取暗黑模式状态,通过 useEffect 将其同步到 <html> 标签的 class="dark" 上,再将其传给 Ant Design 的 <ConfigProvider>:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| + import { useEffect } from 'react'; + import { useDarkMode } from 'usehooks-ts'; import { StyleProvider } from '@ant-design/cssinjs'; - import { ConfigProvider } from 'antd'; + import { ConfigProvider, theme } from 'antd';
export default () => { + const { isDarkMode } = useDarkMode(); + + useEffect(() => { + document.documentElement.classList.toggle('dark', isDarkMode); + }, [isDarkMode]); + return ( <StyleProvider layer> - <ConfigProvider> + <ConfigProvider theme={{ algorithm: isDarkMode ? theme.darkAlgorithm : theme.defaultAlgorithm }}> <App /> </ConfigProvider> </StyleProvider> ); };
|
这样,useDarkMode() 的状态就同时控制了 TailwindCSS 和 Ant Design 的暗黑模式的开关。如图:
1 2 3 4 5 6 7 8
| useDarkMode() │ ┌───────┴───────┐ ▼ ▼ <html class="dark"> <ConfigProvider> │ │ ▼ ▼ TailwindCSS Ant Design
|
参考资料