通过 Babel
实现 JSX
中无感知使用 CSS Modules
不需要显式调用 styles
变量或自定义 props
如 styleName
需确保已启用 CSS Modules 功能
Babel 6/7 均可用
-
安装插件
npm install babel-plugin-jsx-css-modules --save
-
配置
.babelrc
文件{ "plugins": [ "jsx-css-modules" ] }
-
调整构建配置以启用
cssModules
功能启用方式可参考:
- https://github.com/css-modules/css-modules#implementations
- https://github.com/webpack-contrib/css-loader#modules
- https://github.com/css-modules/postcss-modules
注意:未启用
cssModules
功能的样式文件不会有效果
import './styles.module.scss'
const Example = ({ customerClassName }) => (
<div>
<div className="module-class-name">Example</div>
<div className={customerClassName}>Example</div>
</div>
)
将转化为
import styles from './styles.module.scss'
const matcher = classNames =>
classNames.split(' ').map(className => styles[className] || className).join(' ')
const Example = ({ customerClassName }) => (
<div>
<div className={matcher('module-class-name')}>Example</div>
<div className={matcher(customerClassName)}>Example</div>
</div>
)
以上是对该插件运作方式的简单解释,实际上,matcher
函数还可完成对全局样式的甄选,参考如下说明
依照 cssModules 规则,在类名上拓展了 :global
/ :local
修饰器语法,以区分全局、局部样式
未添加修饰器的类名默认属于 :local
样式,此行为通过 prefer
参数修改
import './styles.module.scss'
const Example = () => (
<div className={`
:global(global_1 global_2)
:local(module_1 module_2)
rest_1 rest_2
`}>
Example
</div>
)
注意:不支持嵌套使用修饰器,不支持形如 :global(xxx :global(yyy zzz) aaa)
的使用方式
{
"plugins": [
["jsx-css-modules", {
"styleFileReg": [
"\\.(css|scss|sass|less)$"
],
"prefer": "local",
"helperImportType": "cjs"
}]
]
}
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
styleFileReg | Array of RegExp |
[/\.(css|scss|sass|less)$/] |
用以匹配需要处理的 css 模块文件 |
prefer | String |
'local' |
声明未修饰的类名归属于何种类型,取值为 'local' 或 'global' |
helperImportType | String |
'cjs' |
声明辅助函数的导入方式,取值为 'cjs' 或 'esm' |
当存在多个 cssModules
样式文件时,若文件内存在同名模块,则只会保留最后被引用文件内的模块
// style1.module.scss
.test {
color: red;
}
// style2.module.scss
.test {
color: blue;
}
import './style1.module.scss'
import './style2.module.scss'
const Example = () => (
<div className="test">我将会是蓝色的</div>
)
考虑到插件功能关注点不同,目前不太清楚是否有必要支持如下两种、或更多可能性的书写方式,可以在 issue 中交流
若添加如下特性,插件有可能需要进行更名,含义类似于 className-all-in-one
或 jsx-className-expansion
-
无感知使用CSS Modules
-
兼容
styleName
(prefer
选项固定为'global'
) -
无感知集成 classnames 功能,示例如下
const Example = () => ( <div> <span className={{ xxx: true, yyy: false }} /> <span className={[ 'zzz', { xxx: 1, yyy: 0 } ]} /> </div> )