React SSR中webpack css-loader导致服务端与客户端className不匹配问题
解决React SSR中CSS Modules类名映射不匹配的问题
这个问题我之前也碰到过,核心原因就是服务端和客户端的css-loader导出结构不一样,导致两边获取类名的方式出现差异,进而引发了className不匹配的警告。
问题根源
你看到服务端打印的样式结果是一个带locals属性的数组,而客户端直接拿到类名映射对象,是因为:
- 在服务端(Node.js环境),css-loader默认会输出包含CSS代码内容的模块(那个数组就是CSS的内部表示),同时把类名映射附加在
locals属性上; - 在客户端,因为你通常会搭配style-loader/mini-css-extract-plugin一起使用,这些loader会处理CSS代码并将类名映射作为默认导出返回,所以你能直接用
styles.className。
两边的导出结构不一致,自然就出现了服务端拿不到正确类名、客户端className不匹配的问题。
解决方案
最干净的解决方式是给服务端的css-loader添加exportOnlyLocals: true配置,让服务端只导出类名映射对象,和客户端的导出结构保持一致:
服务端webpack配置修改:
{ test: /\.css$/, use: [ { loader: 'css-loader', options: { modules: true, localIdentName: '[local]__[hash:base64:4]', camelCase: true, exportOnlyLocals: true // 新增这个配置 } } ] }
添加这个配置后,服务端导入的样式就会直接是类名映射对象(和客户端一样),你可以直接用styles.className获取类名,两边的className就会匹配,警告也会消失。
备选方案(不区分环境配置时)
如果不想单独为服务端改配置,也可以写一个工具函数统一处理样式导入:
// utils/styleHelper.js export const getStyles = (rawStyles) => { // 判断是否存在locals属性,存在则取locals,否则直接用原对象 return rawStyles.locals ? rawStyles.locals : rawStyles; };
然后在组件里这样用:
import rawStyles from './YourComponent.css'; const styles = getStyles(rawStyles); // 正常使用styles.className
这样不管是服务端还是客户端,都能拿到正确的类名映射,不过这种方式不如修改webpack配置来得彻底。
内容的提问来源于stack exchange,提问作者Sanjay Bisht
相关产品推荐
相关产品推荐

