Webpack5+React16+TypeScript4项目中使用SASS时CSS类样式无法生效的问题求助
你遇到的这个问题其实很明确——你在webpack配置里启用了CSS Modules,但却用了普通类选择器的方式去引用类名。
当css-loader的modules: true被设置后,Webpack会对所有SCSS文件里的类名进行哈希转换,比如你写的.main-body-style会被编译成类似main-body-style_abc123这样的唯一类名,这时候你直接在JSX里写className="main-body-style"自然匹配不到,而元素选择器(比如body)不受CSS Modules影响,所以能正常生效。
下面给你两种解决方案,根据你的需求选择:
方案1:关闭CSS Modules(如果你不需要这个特性)
如果你只是想正常写普通的SCSS类名,不需要类名隔离,直接把css-loader的modules选项改成false或者删掉这个配置即可:
修改webpack.config.ts里的SCSS规则:
{ test: /\.s(a|c)ss$/, include: [path.resolve(__dirname, "src/assets")], use: [ "style-loader", { loader: "css-loader", options: { modules: false }, // 禁用CSS Modules }, "sass-loader", ], },
改完之后,你原来写的className="main-body-style"就能正常匹配SCSS里的类名了。
方案2:保留CSS Modules,按规则使用它
如果你想保留CSS Modules的类名隔离特性,需要按正确的方式导入和使用类名:
步骤1:修改组件里的样式导入方式
把原来的样式导入改成默认导入,拿到样式对象:
import React from "react"; import TopBarMenu from "../components/TopBarMenu"; import styles from "../assets/styles/main.scss"; // 导入样式对象 const App: React.FC = () => { return ( <> {/* 通过样式对象访问编译后的类名 */} <div className={styles["main-body-style"]}> <TopBarMenu /> </div> </> ); }; export default App;
(如果你的类名是驼峰式的,比如.mainBodyStyle,可以直接写styles.mainBodyStyle)
步骤2:添加TypeScript类型支持
因为你用了TypeScript,需要让它识别SCSS模块的类型。你已经安装了css-modules-typescript-loader,可以调整loader顺序来自动生成类型文件:
{ test: /\.s(a|c)ss$/, include: [path.resolve(__dirname, "src/assets")], use: [ "style-loader", "css-modules-typescript-loader", // 先处理类型生成 { loader: "css-loader", options: { modules: true }, }, "sass-loader", ], },
或者更简单的方式:在src目录下创建一个declarations.d.ts文件,手动声明SCSS模块类型:
declare module "*.scss" { const classes: Record<string, string>; export default classes; }
补充说明
你之前的Webpack4项目没遇到这个问题,应该是当时没有给css-loader配置modules: true,所以Webpack按普通CSS文件处理,类名不会被转换。现在Webpack5的配置里你开启了这个特性,就需要遵循对应的使用规则啦。
内容的提问来源于stack exchange,提问作者Francisco Souza

