本文主要是基于webpack+es6+react关于css module脚手架的搭建。可以从css_module_demo下载相关案例,本文拟从4种可能的情形配置启动css_module。
css_module
css module最简单的情形,只需要在css-loader启动css module配置即可。
webpack css-loader
module: {
rules: [{
test: [/\.js$/, /\.jsx$/, /\.es6$/],
include: [
path.resolve(__dirname, 'src'),
],
use: {
loader: "babel-loader"
},
}, {
test: [/\.css/],
exclude: path.resolve(__dirname, 'src/styles/global'),
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[name]__[local]-[hash:base64:5]'
}
}
]
}, {
test: [/\.css/],
include: path.resolve(__dirname, 'src/styles/global'),
use: [
'style-loader',
'css-loader'
]
}]
},
一般项目中,会有normalize.css或者global.css全局css样式,此时若不需要处理,可以配置两种css的管理方式。具体的使用方法,可参照css_module_demo demo1的配置。
css_module + less\scss
若需要配合less、scss编辑器,配置与css-loader类似,在css、less相关配置中设置如下即可.
...
{
test: [/\.css$/, /\.less$/],
exclude: path.resolve(__dirname, 'src/styles/global'),
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[name]__[local]-[hash:base64:5]'
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: (loader) => [
require('postcss-import')({ root: loader.resourcePath }),
require('postcss-cssnext')(),
require('autoprefixer')(),
require('cssnano')()
]
}
},
'less-loader'
]
}, {
test: [/\.css$/, /\.less$/],
include: path.resolve(__dirname, 'src/styles/global'),
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: (loader) => [
require('postcss-import')({ root: loader.resourcePath }),
require('postcss-cssnext')(),
require('autoprefixer')(),
require('cssnano')()
]
}
},
'less-loader'
]
}
...
这样我就可以使用less的功能了,如我们在app.less中
.global {
text-align: left;
font-size: 20px;
composes: box from "../styles/views/layout.less";
.title {
font-size: 22px;
color: red;
}
.title:before {
content: 'before i come'
}
.title:hover {
font-size: 40px;
}
}
但是css module中,不能在子选择器中使用compose,如我们在title中定义composes
.global {
text-align: left;
font-size: 20px;
composes: box from "../styles/views/layout.less";
.title {
font-size: 22px;
composes: heading from "../styles/views/typography.less";
color: red;
}
.title:before {
content: 'before i come'
}
.title:hover {
font-size: 40px;
}
}
会提示类似如下的错误
ERROR in ./node_modules/.0.28.7@css-loader?{"modules":true,"localIdentName":"[name]__[local]-[hash:base64:5]"}!./node_modules/.2.0.8@postcss-loader/lib?{"ident":"postcss"}!./node_modules/.4.0.5@less-loader/dist/cjs.js!./src/components/app.less
Module build failed: Error: composition is only allowed when selector is single :local class name not in ":local(.global) :local(.title)"
css module作者在issues/261中提到“Composition works differently to mixins. It does not mutates rules, just concatenates names.”
css_module + react-css-modules
在每个样式中都是style.*中的形式比较麻烦,可以使用react-css-modules解决这种问题。例如在app.js中
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import CSSModules from 'react-css-modules';
import { Link } from 'react-router-dom';
import styles from './app.less'
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div styleName='global'>
<h1 styleName='title'>css module test case</h1>
<ul role="nav" styleName='nav'>
<li><Link to="/CompositionOverrides">CompositionOverrides</Link></li>
<li><Link to="/GlobalSelectors">GlobalSelectors</Link></li>
<li><Link to="/ScopedAnimations">ScopedAnimations</Link></li>
<li><Link to="/ScopedSelectors">ScopedSelectors</Link></li>
<li><Link to="/StyleVariantA">StyleVariantA</Link></li>
</ul>
{this.props.children}
</div>
);
}
}
export default CSSModules(App, styles)
react-css-modules缺点是是需要运行时的依赖,而且需要在运行时才获取className,性能损耗大。在比较大的项目中,会导致较大的延迟。那么这个问题怎么解决那,可以使用bable-plugins-react-css-modules 把className获取前置到编译阶段。
css_module + bable-plugins-react-css-modules
bable-plugins-react-css-modules与react-css-modules是同一个作者开发的工具,bable-plugins-react-css-modules相对于react-css-modules,在性能方面有了较大的提高。
bable-plugins-react-css-modules有两种配置方式,一是配置在webpack.config.js,二是配置在.babelrc中,本文采取的方式是配置在webpack.config.js中。
...
{
test: [/\.js$/, /\.jsx$/, /\.es6$/],
include: [
path.resolve(__dirname, 'src'),
],
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
plugins: [
[ "react-css-modules", {
context: path.resolve(__dirname, "src"),
"generateScopedName": "[path][name]__[local]--[hash:base64:5]"
}]
]
}
},
}
...
总结
css module具有灵活性、易移植的优点,可以配合less、scss等多种css编译器使用。本文依赖于webpack css-loader,配置了css module、css module + less\scss、css module+react-css-modules、css module + babel-plugin-react-css-modules等四种css_module使用方式。