Chakra UI表格表头样式在tsx与jsx后缀文件中显示不一致问题
问题现象
我在app.tsx中编写了如下简单函数用于渲染表格,此时表头显示正常(黑底白字),可读性良好。
import React from 'react'; import { Table, Thead, Tbody, Tr, Th, Td } from "@chakra-ui/react" export default function App() { return( <Table variant="simple" size="sm"> <Thead> <Tr> <Th>A</Th> <Th>B</Th> </Tr> </Thead> <Tbody> <Tr> <Td>a</Td> <Td>b</Td> </Tr> </Tbody> </Table> ) }
但如果我将文件重命名为app.jsx,同一表格渲染后表头显示模糊、难以辨认,效果如下:
复现步骤
git clone https://github.com/somguyth/chakra-ui-header-bug.git cd chakra-ui-header-bug npm install npm run dev
启动后访问localhost:9000,将app.jsx重命名为app.tsx,观察代码重编译后表头颜色发生变化。
显示正常时(app.tsx)的表头元素属性:
显示异常时(app.jsx)的表头元素属性:
补充说明
我尝试临时修复该问题,在index.tsx之外,额外在app.jsx中也添加<ChakraProvider theme={darkTheme}>包裹,此时表头恢复正常,检查元素发现th标签的class从错误的css-r10se1变回了正确的css-4v3u8n。我不清楚该问题的根因,也希望获得不需要重复声明ChakraProvider的正确修复方案。
相关配置代码
index.tsx
import React from "react"; import ReactDOM from "react-dom"; import { ChakraProvider, extendTheme } from "@chakra-ui/react" import App from "./app" const darkTheme = extendTheme({ config: { useSystemColorMode: false, initialColorMode: "dark" } }); ReactDOM.render( <ChakraProvider theme={darkTheme}> <App /> </ChakraProvider>, document.getElementById("root") );
webpack.config.js module规则配置
module: { rules: [ { test: /\.tsx?$/, use: "ts-loader", exclude: /node_modules/ }, { test: /\.m?jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', "@babel/preset-react"] } }, resolve: { fullySpecified: false, }, }, { test: /\.css$/, use: ['style-loader', 'css-loader'] } ], },
.babel.rc配置
{ "presets": ["@babel/preset-env", "@babel/preset-react"] }
package.json配置
{ "name": "test", "version": "1.0.0", "description": "", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack serve" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@chakra-ui/icons": "^1.0.14", "@chakra-ui/react": "^1.6.5", "@emotion/react": "^11.4.0", "@emotion/styled": "^11.3.0", "css-loader": "^5.2.7", "framer-motion": "^4.1.17", "react": "^17.0.2", "react-dom": "^17.0.2", "react-table": "^7.7.0", "typescript": "^4.3.5" }, "devDependencies": { "@babel/core": "^7.14.6", "@babel/preset-env": "^7.14.7", "@babel/preset-react": "^7.14.5", "@types/react-dom": "^17.0.9", "@types/react-table": "^7.7.2", "babel-loader": "^8.2.2", "html-webpack-plugin": "^5.3.2", "ts-loader": "^9.2.3", "webpack": "^5.45.1", "webpack-cli": "^4.7.2", "webpack-dev-server": "^3.11.2" } }
根因与解决方案
根因
该问题是Chakra UI v1版本混合TS/JS编译场景下的样式注入冲突导致的:
你的webpack配置中,TS/TSX文件走ts-loader编译,JS/JSX走babel-loader编译,两种编译链路对Chakra UI依赖的emotion样式库的class生成规则不一致,导致JSX文件中渲染的Chakra组件没有正确继承全局ChakraProvider注入的暗色主题配置,使用了默认的亮色主题样式,才会出现浅色表头在暗色背景下模糊的问题。
解决方案
不需要重复声明ChakraProvider,按以下任意一种方式调整即可:
- 统一编译链路:将JSX文件也纳入ts-loader的编译范围,修改webpack.config.js中的ts-loader匹配规则为
test: /\.[jt]sx?$/,移除单独的JSX babel-loader规则,同时在tsconfig.json中设置"allowJs": true即可。 - 给babel-loader添加emotion预设:安装
@emotion/babel-preset-css-prop,修改.babelrc的presets配置,新增emotion的预设,确保babel编译JSX时和ts-loader的样式生成规则对齐:
{ "presets": ["@babel/preset-env", "@babel/preset-react", "@emotion/babel-preset-css-prop"] }
- 显式指定组件样式:如果不想修改编译配置,可以直接给Th组件显式指定样式,例如
<Th color="white" bg="gray.800">即可强制覆盖默认样式。
内容的提问来源于stack exchange,提问作者ABC
相关产品推荐
相关产品推荐

