Duan Hong +

CSS Modules

继昨天的 Webpack Code Splitting,这周第二个任务:CSS MODULES

昨天的博客到凌晨** 03:18 才算完结,今天的 **22:58 分开始,还不知道要写到啥时候

007 幽灵党,开场前奏不错,要不咱也来段儿:


上午8点多醒来的时候,外面一片雾蒙蒙,这几天的空气真的很差,但还是挡不住出去跑步的脚步。这周还没有跑过一公里,这两天一定要做点什么吧~

于是,整理行装,准备出门。哎,可恼人的是,地铁卡和工卡不知道哪去了,难道就这么取消行程吗?不行,这样不行,雾霾怕什么,墨菲定律说了,该发生的总会发生,所以,毅然决然出去跑步,为了这个小插曲,我要刷个半马,以示吾心(谢谢关心爱护我的朋友们,带上口罩跑步真的很不爽,所以,嘿嘿)。

雾霾中的奥森也是不缺人的,朦胧之中自有其优美之处,你可曾发现?天公也不错,把羞涩的太阳也放出来了一小会儿,瞅了瞅奥森还有谁在跑步,哈哈。半马中途,遇到一高中生,聊到了彼此间的同感 “独行者步疾,结伴者行远

Wanna go fast, go alone. Wanna go far, go together.

小伙子现在高三,跑龄5年,从一个小胖子,跑成了一个帅小伙(笑~)。也许当初跑步是为了减肥,但现在已经不是了,它已经变成了一种习惯。作为一个跑者,本身是孤独的,我也感同身受。同样,我们都享受跑步带来的畅快淋漓,满身臭汗,冲个热水澡,带走一切不如意,尽情享受焕然一新的自己。

和他相比,我的跑龄只有5个月,同样也不是为了减肥。我也很少和跑团的小伙伴们一起跑,我的节奏太快,她的配速较慢,为了彼此的跑步体验,还是做一个孤独的跑者比较好吧。当然,有时候也会一起,边跑边聊,畅快且尽兴。

跑步,是一种享受,跑的时候不要去想,给大脑一个放松的时间,带动机体,尽情放纵,在汗水中涅槃,用热水澡冲走疲惫,躺在床上,呆呆看着天花板,渐渐入睡,惬意的人生就这么简单。


享受归享受,天要下雨,娘要嫁人,干货来也。

CSS MODULES的概念,很新潮,但也是自然而然的事。在模块化开发提上议程之后,全局CSS的问题也日益显现出来。

借助于webpack这样的工具,用 style-loader解决了样式和组件一起打包的问题。这样,组件就可以完全JS化,NICE。

// webpack config
module: {
        loaders: [{
            test: /\.jsx?$/,
            loaders: ['react-hot', 'babel'],
            exclude: /node_modules/,
            include: __dirname
        }, {
            test: /\.json$/,
            loader: "json"
        }, {
            test: /\.scss$/,
            exclude: [path.resolve(__dirname, config.base + '/scss')],
            loader: 'style!css?!autoprefixer!sass?sourceMap'
        }, {
            test: /\.(png|jpg|svg)$/,
            loader: 'url?limit=51200'//50k
        }, {
            test: /\.(ttf|eot|svg|woff[1-9]?)$/,
            loader: "file?name=assets/fonts/[name]-[hash:8].[ext]"
        }]
    },
    resolve: {
        root: __dirname,
        extensions: ['', '.js', '.json', '.jsx', '.scss', '.css']
    }

按照上述的配置之后,我们就可以这样写一个组件了

import React from 'react'
import styles from './style'

export default class Footer extends React.Component {
    render() {
      return <footer className='fixed-ft'>
        <ul className='nav-sub'>
            <li className='current'>
                <a href='javascript:void(0)'>
                    <i className='ico-movie'></i>上映
                </a>
            </li>
            <li>
                <a href='javascript:void(0)'>
                    <i className='ico-cinema'></i>影院
                </a>
            </li>
            <li>
                <a href='javascript:void(0)'>
                    <i className='ico-my'></i>我的
                </a>
            </li>
        </ul>
      </footer>
    }
}
// style.scss
.nav {
    position: fixed;
    width: 100%;
    background-color: #fefefe;
    z-index: 1000;
    top: 0;
}
.curent {
    background-image: url()'../../images/active.png')
}

即使有图片也无所谓,只要在设置的大小范围内,仍旧可以以Base64的格式存储在JS里,这样的组件才是我们最最期待的。

然并卵,即使这样,仍旧有全局CSS的问题,那如何隔绝外部样式的干扰或者冲突呢? 那,去看看Facebook和Instagram的网页,有什么发现没?

**广告时间: inst@duan112358, facebook@duan112358, twitter@duan112358 **

上述做法是不是很酷?现在,CSS MODULES就给予了我们这种实现方案,借助于webpack,那用起来就更方便了

第一步,webpack设置

// loader config
{
    test: /\.scss$/,
    exclude: [path.resolve(__dirname, config.base + '/scss/shared')],
    loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:8]!autoprefixer!sass')
}

// plugin config add
new ExtractTextPlugin('css/[name]-[contenthash:8].css', { allChunks: true })
// for why set allChunks:true, i will tell later.

第二步,在JS里使用导出后的样式。css-modules/webpack-demo里很详细了,无需我在此赘言。

import React from 'react'
import ReactCssModules from 'react-css-modules'
import styles from '../../scss/style'

@ReactCssModules(styles, {allowMultiple:true, errorWhenNotFound: false})
export default class Footer extends React.Component {
    render() {
      return <footer styleName='fixed-ft' class='nav navbar'>
        <ul styleName='nav-sub'>
            <li styleName='current'>
                <a href='javascript:void(0)'>
                    <i styleName='ico-movie'></i>上映
                </a>
            </li>
            <li>
                <a href='javascript:void(0)'>
                    <i styleName='ico-cinema'></i>影院
                </a>
            </li>
            <li>
                <a href='javascript:void(0)'>
                    <i styleName='ico-my'></i>我的
                </a>
            </li>
        </ul>
      </footer>
    }
}

不过推荐采用这总做法,styleName指代该组件特有样式,className指代全局样式,两者可以同时使用。

那说下,为什么要指定** {allChunks: true} ** ?

上篇博文webpack code spliting提到异步模块的问题以及解决方案。这里的allChunks就是为解决异步Chunks里的样式而设置的。我们知道,webpack不会主动分析异步Chunks里的依赖,其中的依赖也只是会打包到该Chunk中去,样式也是一样。那,如果不采用** {allChunks: true} **,结果如何呢?

CSS的处理是正常的,但为什么没有将CSS映射到DOM中去呢?

import styles from './ScopedSelectors.css';

import React, { Component } from 'react';

export default class ScopedSelectors extends Component {

  render() {
    return (
      <div className={ styles.root }>
        <p className={ styles.text }>Scoped Selectors</p>
      </div>
    );
  }

};

打印输出这里的styles,发现是个空值,真是个奇怪的问题,那启用{ allChunks: true }为什就会有值了呢?这也忒奇怪了

那CSS MODULES的实现究竟是怎么一回事呢?

正常情况下是导出了一个原样式和处理后样式的一个MAP映射,这也是可以想象得到的,那如果不去处理异步模块里的CSS引用,那没有任何样式MAP的输出也是理所当然的事了。

可设置了{allChunks: true}之后为什么就可以了呢?这就是 extract-text-webpack-plugin 的魔法所在吧,等我细细研究一番这和各位探讨下

那如果使用在异步模块里使用CSS MODULES的话,就只好把样式全都提取出来,放到一个css里去了, 的缺是异步模块的一大痛点,拆出来的模块,又何必要再合回去呢?😂😂

所以,上次代码拆分的DEMO暂且没有采用CSS MIDODULES的方案,至少在该问题解决之前。

如果你有更好的方案,欢迎留言~

update@Mon Nov 23 09:02:10 CST 2015

客官,你来晚了,上述DEMO已被移除,还请见谅。

上述问题已经找到原因,如果你已COPY过DEMO,更新css-loader即可。

如不介意,慢品此作

post@Sun Nov 15 01:25:19 CST 2015

Wanna say something ?

Blog

Friends