Next.js 13+ 原生内置 CSS Modules 支持,自动处理 .module.scss 的编译、作用域隔离与驼峰映射,无需安装 node-sass 等旧插件或修改 next.config.js;强行配置反而破坏默认行为,导致样式失效、全局污染或构建报错。

Next.js 13+ 不需要配置就能用 .module.scss,强行加配置反而引发冲突或构建失败。
为什么直接 import .module.scss 就行,不用装插件?
Next.js 自 v13 起已将 CSS Modules(含 .module.scss)作为原生能力内置。它复用了自身的 webpack 规则链,自动处理类名哈希、作用域隔离、嵌套编译等全部流程。
- 安装
@zeit/next-sass、node-sass或在next.config.js里写withSass—— 这些是 Next.js 12 及更早版本的遗留方案,v14/v15 中会破坏默认行为 - 常见后果包括:
className无法映射(styles.btn是undefined)、样式漏出成全局、构建时报Global CSS cannot be imported from files other than your Custom _app.js - 如果你项目里已有旧配置,请直接删掉
next.config.js中所有与css、sass、webpack相关的 override
.module.scss 和普通 .scss 的区别必须分清
Next.js 对这两类文件的处理逻辑完全不同,混用是全局冲突的主因。
-
.module.scss:只允许在组件中import styles from './X.module.scss',类名自动转驼峰,作用域严格隔离 -
.scss(无module):只能在app/layout.tsx顶层静态导入,比如import './globals.scss';一旦在组件里import,立刻报错 - 别试图“绕过”规则:用
require('./X.scss')、dynamic import、或放在useEffect里加载 —— 全部无效,且可能触发 HMR 异常
类名映射失效的三个高频原因
即使文件命名和导入都正确,styles.xxx 仍可能为 undefined,本质是 SCSS 类名与 JS 访问方式不匹配。
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
立即学习“前端免费学习笔记(深入)”;
- SCSS 中写了
.btn-primary,但 JS 里写styles.btn_primary或styles['btn-primary']—— 后者在 TypeScript 下类型丢失,前者根本不存在 - SCSS 用了非法字符,比如
.btn--large(双连字符),Next.js 默认不转换这种写法,styles.btnLarge会是undefined - 嵌套写法如
.btn { &__icon { } },生成的类名仍是btn__icon,JS 中必须写styles.btn__icon,不能靠父类推导
Storybook 里也一样开箱即用
只要用的是 @storybook/nextjs(v7.6+),.module.scss 在 Storybook 预览页中无需任何额外 loader 或 main.ts 配置。
- 源码证据在
@storybook/nextjs/dist/frameworks/nextjs/css/webpack.ts,它直接复用了 Next.js 的模块解析逻辑 - 验证方法:新建
Button.stories.tsx,import styles from './Button.module.scss',然后className={styles.button}—— 能跑通就说明没问题 - 如果 Storybook 报错而 Next.js 本身正常,大概率是你在
.storybook/main.ts里手动加了 webpack rule 覆盖,删掉即可
真正容易被忽略的点是:你不需要做任何事,但必须确保「什么都没做」——不装包、不改 config、不乱命名、不在错误位置导入。所有异常几乎都来自试图“主动配置”一个已被默认支持的功能。

















