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;

一步一步做React(一) - Hello React

| Comments

什么都不说,先照着做

安装合适的node版本和包管理工具Yarn

1
2
3
4
5
node -version v6.9.4(用nvm)

brew update(如果是mac的)

brew install yarn

https://yarnpkg.com/en/docs/install

安装webpack

1
yarn add --dev webpack

安装babel

1
yarn add --dev babel-core babel-loader babel-preset-es2015 babel-preset-react

安装React

1
yarn add react react-dom

创建和编辑.babelrc

1
2
touch .babelrc   
vim .babelrc  
1
2
3
{
  "presets" : ["es2015", "react"]
}

创建和编辑webpack.config.js

1
2
touch webpack.config.js
vim 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
var webpack = require('webpack');
var path = require('path');

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

var config = {
  entry: APP_DIR + '/index.jsx',
  output: {
      path: BUILD_DIR,
      filename: 'bundle.js'
  },
  module: {
      loaders: [
          {
              test: /\.jsx?/,
              include: APP_DIR,
              loader: 'babel'
          }
      ]
  }
};

module.exports = config;

创建和编辑src/index.jsx

1
2
3
4
mkdir src
cd src
touch index.jsx
vim index.jsx
1
2
3
4
5
6
7
8
9
10
import React from 'react';
import {render} from 'react-dom';

class App extends React.Component {
  render () {
      return <p> Hello React!</p>;
  }
}

render(<App/>, document.getElementById('app'));

在html中引用

1
2
3
cd src
touch index.html
vim index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!doctype html>

<html lang="zh">
<head>
    <!-- The first thing in any HTML file should be the charset -->
    <meta charset="utf-8">
    <!-- Make the page mobile compatible -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="mobile-web-app-capable" content="yes">
    <title>17High</title>
</head>
<body>
<div id="app"/>
<!-- Display a message if JS has been disabled on the browser. -->
<noscript>If you're seeing this message, that means <strong>JavaScript has been disabled on your browser</strong>, please <strong>enable JS</strong> to make this app work.</noscript>

<script src="../public/bundle.js" type="text/javascript"></script>
</body>
</html>

运行webpack命令,生成打包文件bundle.js

1
2
./node_modules/.bin/webpack -d
./node_modules/.bin/webpack -d --watch //监听文件变化

打开index.html看效果