使用 CSS Modules

CSS Modules 让我们能以模块化的方式编写 CSS 代码,并且可以在 JavaScript 文件中导入和使用这些样式。使用 CSS Modules 可以自动生成唯一的类名,隔离不同模块之间的样式,避免类名冲突。

Rsbuild 默认支持使用 CSS Modules,无需添加额外的配置。我们约定使用 [name].module.css 文件名来启用 CSS Modules。

以下样式文件会被视为 CSS Modules:

  • *.module.scss
  • *.module.less
  • *.module.css

示例

  • 编写样式:
/* button.module.css */
.error {
  background: red;
}
  • 使用样式:
// Button.tsx
import React, { Component } from 'react';
// 引入样式文件
import styles from './button.module.css';

export default () => {
  return <button className={styles.error}>Error Button</button>;
};

CSS Modules 识别规则

在默认情况下,只有 *.module.css 结尾的文件才被视为 CSS Modules 模块。

如果你想将其他 CSS 文件也当做 CSS Modules 模块进行处理,可以通过配置 output.cssModules.auto 来实现。

比如:

export default {
  output: {
    cssModules: {
      auto: (resource) => {
        return resource.includes('.module.') || resource.includes('shared/');
      },
    },
  },
};

设置后,以下两个文件都会被视为 CSS Modules:

import styles1 from './foo.module.css';
import styles2 from './shared/bar.css';

自定义类名

自定义 CSS Modules 生成的类名也是我们比较常用的功能,你可以使用 output.cssModules.localIdentName 来进行配置。

export default {
  output: {
    cssModules: {
      localIdentName: '[hash:base64:4]',
    },
  },
};

如果你需要自定义 CSS Modules 的其他配置,可以通过 output.cssModules 进行设置。

类型声明

当你在 TypeScript 代码中引用 CSS Modules 时,TypeScript 可能会提示该模块缺少类型定义:

TS2307: Cannot find module './index.module.css' or its corresponding type declarations.

此时你需要为 CSS Modules 添加类型声明文件,请在项目中创建 src/env.d.ts 文件,并添加相应的类型声明。

  • 方法一:如果项目里安装了 @rsbuild/core 包,你可以直接引用 @rsbuild/core 提供的类型声明:
/// <reference types="@rsbuild/core/types" />
  • 方法二:手动添加需要的类型声明:
src/env.d.ts
declare module '*.module.css' {
  const classes: { readonly [key: string]: string };
  export default classes;
}
declare module '*.module.scss' {
  const classes: { readonly [key: string]: string };
  export default classes;
}
declare module '*.module.sass' {
  const classes: { readonly [key: string]: string };
  export default classes;
}
declare module '*.module.less' {
  const classes: { readonly [key: string]: string };
  export default classes;
}
declare module '*.module.styl' {
  const classes: { readonly [key: string]: string };
  export default classes;
}
declare module '*.module.stylus' {
  const classes: { readonly [key: string]: string };
  export default classes;
}

添加类型声明后,如果依然存在上述错误提示,请尝试重启当前 IDE,或者调整 env.d.ts 所在的目录,使 TypeScript 能够正确识别类型定义。

示例

例如某个文件夹下面有 src/index.tssrc/index.module.scss 两个文件:

src/index.ts
import styles from './index.module.scss';

export default () => {
  <div>
    <div className={styles.pageHeader}>Page Header</div>
  </div>;
};
// index.module.scss
.page-header {
  color: black;
}

执行构建命令后,会自动生成 src/index.module.scss.d.ts 类型声明文件:

src/index.module.scss.d.ts
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
  'page-header': string;
  pageHeader: string;
}
export const cssExports: CssExports;
export default cssExports;

此时再打开 src/index.ts 文件,可以看到 styles 对象已经具备了准确的类型。

相关配置

在上述例子中,src/index.module.scss.d.ts 是编译生成的代码,你可以选择将它们提交到 Git 仓库里,也可以选择在 .gitignore 文件中忽略它们:

# Ignore auto generated CSS declarations
*.module.css.d.ts
*.module.sass.d.ts
*.module.scss.d.ts
*.module.less.d.ts
*.module.styl.d.ts
*.module.stylus.d.ts

此外,如果生成的代码导致了 ESLint 报错,你也可以将上述配置添加到 .eslintignore 文件里。