README
module-classnames-loader
module-classnames-loader
是一个 webpack loader. 当你需要在 react 项目里使用模块化类名时, 它能在运行时聪明的应用你的模块化类名, 从而减少你的工作量. :hibiscus::hibiscus:
开始使用
你可这样安装:
npm install --save-dev module-classnames-loader
然后在 webpack
里配置好 loader, 假如有如下配置:
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader', 'module-classnames-loader'],
},
// 依然需要 css loader 来处理模块化
{
test: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
],
},
};
注意, 你应该把 module-classnames-loader
放到处理js文件loader的右侧. 因为它会通过分析你的 jsx
语法来定位类名位置. 所以务必要在 babel-loader 处理完 jsx 语法之前使用.
最终的模块化处理依然是基于 css-loader. 所以务必做好 css-loader 的相关配置.
如果你使用 less/scss , 只需按照原样逻辑配置好相关 loader 即可. :point_right::point_right: less-loader | :point_right::point_right: sass-loader
注意: 要模块化的css文件, 务必要命名成
*.module.(css|less|scss)
的形式
如: 'syle.module.css',
create-react-app 正是使用这种方式来进行模块化css文件, 使用create-react-app
将可以无缝衔接
假设你的程序有如下文件:
module.js
在使用 module-classnames-loader 之前, 你可能需要使用以下方式来使用模块化类名:
import React from 'resct'
import style from './style.module.css'
function Banner(){
return (
//
<div className={`${ style.name1 } ${ style.name2 }`}>...</div>
)
}
而现在, 你只需要这样:
import React from 'resct'
import './style.module.css'
function Banner(){
return (
//
<div className="name1 name2">...</div>
)
}
:school_satchel::school_satchel:怎么样, 是不是已经有点心跳加速了. 别急, 再看看以下用例的对比::school_satchel::school_satchel:
注: 为了行文方便, 我将直接使用 jsx 表示使用方式.
假设你用了classnames 库:
before
import style from './style.module.css'
import 'classnames'
<div
className={classnames{
[style.name1]: true,
[style.name2]: true,
}}
>...</div>
after
import './style.module.css'
import 'classnames'
<div
className={classnames{
name1: true,
name2: true,
}}
>...</div>
事实上, 你可以随意使用表达式而无需担心:
import './style.module.css'
let names = 'n1 n2'
<div
className={names + 'n3'}
>...</div>
我们再看一些你关心的问题:
假设你有两个模块化的 css 文件:
// file1.module.css
.name1{
margin: 0;
}
// file2.module.css
.name1{
margin: 0;
}
.name2{
margin: 0;
}
我们先引入 file1.module.css :
import './file1.module.css'
// 假设 file1.module.css 能够得到如下对象
{
name1: wcz_Nlfc_o3
}
<div className="name1 box">...</div>
// 最终, div 的类名会变成 ======>>>
<div class="wcz_Nlfc_o3 box">...</div>
看到了吧, 'box' 不在模块化的类名里, 它会被原样保留. :scream::scream:
看看我们引入了两个css文件的情况:
import './file1.module.css'
import './file2.module.css'
// 假设 file1.module.css 能够得到如下对象
{
name1: f1_name1,
name2: f1_name2,
}
// 假设 file2.module.css 能够得到如下对象
{
name1: f2_name1,
name3: f2_name3
}
<div className="name1 name2 name3 box">...</div>
// 最终, div 的类名会变成 ======>>>
<div class="f2_name1 f1_name2 f2_name3 box">...</div>
这里有两个重要的点:
- 如果位于不同模块化对象的类名, 会分别查找应用
- 如果出现同名的模块化类名, 后面引入的 'css' 会覆盖前面的, 看看上面的 'name1'
如果不想被覆盖, 而只想使用 file1.module.css
的 'name1' 只需单独处理即可(继承上面代码):
import s1 from './file1.module.css'
import './file2.module.css'
<div class={`${s1.name1} name2 name3 box`}>...</div>
// 此时, div 会变成 =======>>>
<div class="f1_name1 f1_name2 f2_name3 box">...</div>
options
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
'babel-loader',
{
loader: 'module-classnames-loader',
options: {
sourceMap: false // true 会开启sourceMap
identifier: 'module', // default: module, 模块化的名字需要为: '*.module.(css|less|scss)'
}
}
],
},
],
},
};
options todo:
sourceMap:
boolean, default: false, 是否生成sourceMapidentifier:
default: 'module', 用于配置需要模块化样式文件名的样板符号, 例如改成: 'mod', 那么你的文件名应为:*.mod.(css|less|scss)
, 其他符号依次类推defaultImport
: boolean, default: false. 和 identifier互斥.- parserOptions: 能够解析的语法, 默认开启以下特性:
- 'jsx',
- 'typescript',
- 'flowComments',
- 'asyncGenerators',
- 'bigInt',
- 'classProperties',
- 'classPrivateProperties',
- 'classPrivateMethods',
- ['decorators',{ decoratorsBeforeExport: true }],
- 'doExpressions',
- 'dynamicImport',
- 'exportDefaultFrom',
- 'exportNamespaceFrom',
- 'functionBind',
- 'functionSent',
- 'importMeta',
- 'logicalAssignment',
- 'nullishCoalescingOperator',
- 'numericSeparator',
- 'objectRestSpread',
- 'optionalCatchBinding',
- 'optionalChaining',
- 'throwExpressions',