NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

一步一步做React(二) - CSS Modules

| Comments

基于上次的内容 《一步一步做React(一) - Hello React》,我们继续搭建一个React项目的工程实践 - CSS Modules。

CSS Modules概念

Github文档 - CSS Modules

CSS Modules — Local Scope 局部作用域

CSS Modules里面最基础也是最重要的概念 - 局部作用域。

1
2
3
.backdrop {}
.prompt {}
.pullquote {}

定义在style.css中的样式都存在于一个组件内的局部作用域,不会污染全局的样式。

1
2
3
4
5
6
7
8
9
10
11
12
import styles from "./style.css"

const Component = props => {
  return (
    <div className={styles.backdrop}>
      <div className={styles.prompt}>
      </div>
      <div className={styles.pullquote}>
      </div>
   </div>
  )
}

怎么解释?如何不会污染全局的样式?答案是唯一的命名。现在,我们先来看是怎么配置的。

用webpack处理样式

style-loader | css-loader | sass-loader

给webpack.config.js中的module添加一个新的loaders配置,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
module: {
  loaders: [
    {
      test: /\.jsx?/,
      include: APP_DIR,
      loader: 'babel',
    },
    {
      test: /\.scss$/,
      loaders: ["style", "css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]", "sass"],
    },
  ],
},

webpack的loader是用来预处理由require()或者import加载文件,比如:

1
import styles from "./style.scss"

在上面的webpack配置中,针对*.scss文件,配置了一个loader的管道,顺序是:

sass-loader => css-loader => style-loader

sass-loader顾名思义用来编译SCSS到CSS

css-loader和style-loader用来将样式嵌入到Webpack打包后的JS文件中,从而实现样式的模块化管理。

针对css-loader的配置,你会看到它的格式是如下的:

1
css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]

其实,这是webpack loader传递参数的一种方式(URL方式),css-loader的参数表请进入传送门

localIdentName是用于指定局部className的格式,比如:

1
2
3
[name]__[local]___[hash:base64:5]
ComponentName__LocalName___HashCode
Component__pullquote___SDFe34IIE

如何抽离出独立的css文件?Extract Text Plugin

正如前面所强调的,style-loader和css-loader,将样式嵌入到Webpack打包后的JS文件。

这当然不是最好的方式,我们需要将样式抽离到独立的css文件中,但就是Extract Text Plugin

1
yarn add extract-text-webpack-plugin --dev

完整的webpack.config.js文件如下:

1
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
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const BUILD_DIR = path.resolve(__dirname, 'public');
const APP_DIR = path.resolve(__dirname, 'src');

const extractCSS = new ExtractTextPlugin(`${BUILD_DIR}/styles.css`);

const config = {
  entry: `${APP_DIR}/index.jsx`,
  output: {
    path: BUILD_DIR,
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /\.jsx?/,
        include: APP_DIR,
        loader: 'babel',
      },
      {
        test: /\.scss$/,
        loader: extractCSS.extract(['css?minimize&modules&importLoaders=2&localIdentName=[name]__[local]', 'postcss', 'sass']),
      },
    ],
  },
  resolve: {
    extensions: ['', '.js', '.jsx'],
  },
  plugins: [
    extractCSS,
  ],
};

module.exports = config;

Comments