本文主要是基于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使用方式。