diff --git a/e2e/cases/css/css-modules-named-export/index.test.ts b/e2e/cases/css/css-modules-named-export/index.test.ts index 9e9927e75a..f591334212 100644 --- a/e2e/cases/css/css-modules-named-export/index.test.ts +++ b/e2e/cases/css/css-modules-named-export/index.test.ts @@ -8,15 +8,12 @@ rspackOnlyTest( cwd: __dirname, runServer: true, rsbuildConfig: { - tools: { - cssLoader: { - modules: { - // TODO: css-loader need support named export when namedExports: false. - namedExport: true - } - } - } - } + output: { + cssModules: { + namedExport: true, + }, + }, + }, }); const files = await rsbuild.unwrapOutputJSON(); diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index a351eb907c..717ac42c5e 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -150,6 +150,7 @@ const getDefaultOutputConfig = (): NormalizedOutputConfig => ({ inlineStyles: false, cssModules: { auto: true, + namedExport: false, exportGlobals: false, exportLocalsConvention: 'camelCase', }, diff --git a/packages/core/src/plugins/css.ts b/packages/core/src/plugins/css.ts index 027e55cf14..1e262d1b5c 100644 --- a/packages/core/src/plugins/css.ts +++ b/packages/core/src/plugins/css.ts @@ -221,7 +221,6 @@ const getCSSLoaderOptions = ({ modules: { ...cssModules, localIdentName, - namedExport: false, }, sourceMap: config.output.sourceMap.css, }; diff --git a/packages/shared/src/types/config/output.ts b/packages/shared/src/types/config/output.ts index 87d8245a16..413bd40247 100644 --- a/packages/shared/src/types/config/output.ts +++ b/packages/shared/src/types/config/output.ts @@ -164,6 +164,10 @@ export type CSSModules = { * Controls the level of compilation applied to the input styles. */ mode?: CSSLoaderModulesOptions['mode']; + /** + * Whether to enable ES modules named export for locals. + */ + namedExport?: boolean; }; export type Minify = @@ -326,6 +330,7 @@ export interface NormalizedOutputConfig extends OutputConfig { injectStyles: boolean; cssModules: { auto: CSSModules['auto']; + namedExport: boolean; exportGlobals: boolean; exportLocalsConvention: CSSModulesLocalsConvention; localIdentName?: string; diff --git a/website/docs/en/config/output/css-modules.mdx b/website/docs/en/config/output/css-modules.mdx index 2475dd781b..820ecc20cc 100644 --- a/website/docs/en/config/output/css-modules.mdx +++ b/website/docs/en/config/output/css-modules.mdx @@ -63,11 +63,11 @@ type CSSModulesLocalsConvention = Type description: -- `asIs` Class names will be exported as is. -- `camelCase` Class names will be camelized, the original class name will not to be removed from the locals. -- `camelCaseOnly` Class names will be camelized, the original class name will be removed from the locals. -- `dashes` Only dashes in class names will be camelized. -- `dashesOnly` Dashes in class names will be camelized, the original class name will be removed from the locals. +- `asIs`: Class names will be exported as is. +- `camelCase`: Class names will be camelized, the original class name will be exported. +- `camelCaseOnly`: Class names will be camelized, the original class name will not be exported. +- `dashes`: Only dashes in class names will be camelized, the original class name will be exported. +- `dashesOnly`: Dashes in class names will be camelized, the original class name will not be exported. ```ts export default { @@ -232,3 +232,51 @@ modules: { }; } ``` + +## cssModules.namedExport + +- **Type:** `boolean` +- **Default:** `false` + +Whether to enable ES modules named export for class names. + +```ts +export default { + output: { + cssModules: { + namedExport: true, + }, + }, +}; +``` + +### Example + +```css title="style.module.css" +.foo { + color: blue; +} +``` + +- `namedExport: false`: + +```js +import styles from './style.module.css'; + +console.log(styles.foo); +``` + +- `namedExport: true`: + +```js +import { foo } from './style.module.css'; +// or +import * as styles from './style.module.css'; + +console.log(foo); +console.log(styles.foo); +``` + +```tip +When `namedExport` is set to true, the `default` class exported by CSS Modules will be automatically renamed to `_default` class because `default` is a reserved word in ECMA modules. +``` diff --git a/website/docs/en/config/output/externals.mdx b/website/docs/en/config/output/externals.mdx index 6b2fa6f983..28938a7cef 100644 --- a/website/docs/en/config/output/externals.mdx +++ b/website/docs/en/config/output/externals.mdx @@ -5,7 +5,7 @@ At build time, prevent some `import` dependencies from being packed into bundles in your code, and instead fetch them externally at runtime. -For more information, please see: [Rspack Externals](https://rspack.dev/config/externals) +> For more information, please see: [Rspack Externals](https://rspack.dev/config/externals). ### Example diff --git a/website/docs/en/config/tools/css-loader.mdx b/website/docs/en/config/tools/css-loader.mdx index 8f4fd8206d..69bca93e04 100644 --- a/website/docs/en/config/tools/css-loader.mdx +++ b/website/docs/en/config/tools/css-loader.mdx @@ -4,13 +4,7 @@ ```js const defaultOptions = { - modules: { - auto: true, - namedExport: false, - exportLocalsConvention: 'camelCase', - localIdentName: rsbuildConfig.output.cssModules.localIdentName, - exportOnlyLocals: target !== 'web', - }, + modules: rsbuildConfig.output.cssModules, sourceMap: rsbuildConfig.output.sourceMap.css, // value is `1` when compiling css files, and is `2` when compiling sass/less files importLoaders: 1 || 2, diff --git a/website/docs/zh/config/output/css-modules.mdx b/website/docs/zh/config/output/css-modules.mdx index 8e4aa8f187..fca906cde6 100644 --- a/website/docs/zh/config/output/css-modules.mdx +++ b/website/docs/zh/config/output/css-modules.mdx @@ -63,11 +63,11 @@ type CSSModulesLocalsConvention = 类型说明: -- `asIs` 类名将按原样导出。 -- `camelCase` 类名将被驼峰化,原始类名仍然可用。 -- `camelCaseOnly` 类名将被驼峰化,原始类名不可用。 -- `dashes` 只有类名中的破折号会被驼峰化,原始类名仍然可用。 -- `dashesOnly` 只有类名中的破折号会被驼峰化,原始类名不可用。 +- `asIs`:类名将按原样导出。 +- `camelCase`:类名将被驼峰化,然后被导出。原始类名也会被导出。 +- `camelCaseOnly`:类名将被驼峰化,然后被导出。原始类名不会被导出。 +- `dashes`:只有类名中的破折号会被驼峰化,然后被导出。原始类名也会被导出。 +- `dashesOnly`:类名中的破折号会被驼峰化,然后被导出。原始类名不会被导出。 ```ts export default { @@ -236,3 +236,51 @@ export default { }, }; ``` + +## cssModules.namedExport + +- **类型:** `boolean` +- **默认值:** `false` + +是否具名导出 class names。 + +```ts +export default { + output: { + cssModules: { + namedExport: true, + }, + }, +}; +``` + +### 示例 + +```css title="style.module.css" +.foo { + color: blue; +} +``` + +- `namedExport: false`: + +```js +import styles from './style.module.css'; + +console.log(styles.foo); +``` + +- `namedExport: true`: + +```js +import { foo } from './style.module.css'; +// or +import * as styles from './style.module.css'; + +console.log(foo); +console.log(styles.foo); +``` + +```tip +当 namedExport 为 true 时,CSS Modules 导出的 `default` class 会被自动重命名为 `_default` class,因为 default 是 ECMA modules 的保留字。 +``` diff --git a/website/docs/zh/config/output/externals.mdx b/website/docs/zh/config/output/externals.mdx index dd286e1906..74ecf92dd6 100644 --- a/website/docs/zh/config/output/externals.mdx +++ b/website/docs/zh/config/output/externals.mdx @@ -5,7 +5,7 @@ 在构建时,防止将代码中某些 `import` 的依赖包打包到 bundle 中,而是在运行时再去从外部获取这些依赖。 -详情请见: [Rspack Externals](https://rspack.dev/zh/config/externals) +> 更多用法供参考:[Rspack Externals](https://rspack.dev/zh/config/externals)。 ### 示例 diff --git a/website/docs/zh/config/tools/css-loader.mdx b/website/docs/zh/config/tools/css-loader.mdx index a51b66408c..102fb4eb15 100644 --- a/website/docs/zh/config/tools/css-loader.mdx +++ b/website/docs/zh/config/tools/css-loader.mdx @@ -5,13 +5,7 @@ ```js const defaultOptions = { - modules: { - auto: true, - namedExport: false, - exportLocalsConvention: 'camelCase', - localIdentName: rsbuildConfig.output.cssModules.localIdentName, - exportOnlyLocals: target !== 'web', - }, + modules: rsbuildConfig.output.cssModules, sourceMap: rsbuildConfig.output.sourceMap.css, // 在编译 css 文件时为 `1`,在编译 sass/less 文件时为 `2` importLoaders: 1 || 2,