🌙 使用CSS Module避免样式污染
背景:React老项目没有使用【CRA】 (opens new window)创建,使用的自定义的webpack,样式都是采用普通CSS方式,导致很容易造成全局样式污染。
需求:在兼容老页面的基础上,新的页面采用【css module】 (opens new window)方式避免样式污染。
🌙 1.React中引入CSS方式
🌙 1.1 一般方式
APP.tsx
:
import React from 'react';
import './App.scss';
function App() {
return (
<div className="container" />
);
}
export default App;
2
3
4
5
6
7
8
9
10
App.scss
:
.container {
color: red;
text-align: center;
}
2
3
4
🌙 1.2 使用CSS Module
APP.tsx
:
import React from 'react';
// 导入CSS Module定义的CSS对象
import styles from './App.module.scss';
function App() {
return (
{/*使用CSS Module属性*/}
<div className={styles.container} />
);
}
export default App;
2
3
4
5
6
7
8
9
10
11
12
App.module.scss
:
.container {
color: red;
text-align: center;
}
2
3
4
编译后显示:
<div class="container--1g20Q"></div>
上面代码中,我们将样式文件App.module.scss
输入到style
对象,然后当做变量的方式引用style.container
作为class
类名。
🌙 2.CSS Module原理
CSS Module配置极其简单,其原理简单:通过将CSS文件以模块的形式引入(类似于js中的对象),将CSS
中定义的类名当作变量赋值给jsx即可。
当webpack解析时,会将CSS Module的类名计算或拼接一个唯一的hash值,从而避免样式的污染。
🌙 3.配置webpack
webpack.config.js
:
const cssLoaders = [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: [
require('autoprefixer')
]
},
"sass-loader",
];
// CSS Module
const cssModuleLoaders = [
"style-loader",
{
loader: "css-loader",
options: {
modules: {
// class命名规则
/**
* localIdentName格式说明
* path: 路径
* name: css文件名
* local: 类名
* hash: 16位字符串
'[path][name]__[local]--[hash:base64:5]'
.src-styles-main__world-grid--R7u-K
--------------- ---------- -----
path,name local hash
* */
mode: "local",
localIdentName: "[name]__[local]--[hash:base64:5]",
},
},
},
"postcss-loader",
"sass-loader",
];
module.exports = {
entry: './src/index.tsx',
mode: devMode ? 'development' : 'production',
devtool: devMode ? 'cheap-source-map' : 'hidden-source-map',
output: {
// 开发模式不用hash
filename: devMode ? 'js/[name].js' : 'js/[name].[chunkhash:8].js',
path: config.output,
publicPath: config.publicPath
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src')
}
},
module: {
rules: [
// 支持 sass
{
test: /\.module\.(scss|sass)$/, use: cssModuleLoaders,
},
// 普通方式,不使用css module
{
test: /\.scss$/, exclude: /\.module\.(scss|sass)$/, use: cssLoaders,
},
// 支持 css
{
test: /\.css$/, use: cssLoaders,
},
]
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Loaders解析顺序是从后向前,解析顺序:
sass-loader
:解析sass|scss
为css。postcss-loader
:添加浏览器前缀,压缩 CSS等。css-loader
:用于加载css
文件,并且转换成commonjs
对象。style-loader
:将样式通过<style>
标签插入到head中。
注意:{test: /\.scss$/, exclude: /\.module\.(scss|sass)$/, use: cssLoaders}
,(注意顺序,放在后面)由于之前的老页面使用了普通的方式,我们还得保持原来的方式可用,这里进行了剔除。
🌙 3.解决ts报错
配置完上述步骤,如果不出意料的话,会爆出TS2307: Cannot find module './index.module.scss'.
的错误:
在项目中增加css.module.d.ts
声名:
declare module "*.module.css" {
const classes: { [key: string]: string };
export default classes;
}
declare module "*.module.scss" {
const classes: { [key: string]: string };
export default classes;
}
declare module "*.module.sass" {
const classes: { [key: string]: string };
export default classes;
}
declare module "*.module.less" {
const classes: { [key: string]: string };
export default classes;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
🌙 4.CRA使用CSS Module
🌙 5.踩坑记录
由于项目管理不规范,之前新入职的同学,不熟悉项目,随意命名,比如:使用普通的css方式引入时,有一个文件被命名为a.module.scss
,然后在tsx
文件里面使用impoort './a.module.scss'
。
在未使用css module之前是正常的,但是引入css module之后发现style没有加载出来,这时就需要去一一排查了,然后把文件命名为a.scss
即可。
不过,一般这种很少出现吧。