1. 程式人生 > >[轉] 使用babel-plugin-react-css-modules簡化CSS Modules的使用

[轉] 使用babel-plugin-react-css-modules簡化CSS Modules的使用

麻煩 ash table 項目 引用 con sets name 源碼

在我們的產品中,均使用CSS Modules來作為樣式解決方案,大致的代碼是這樣的:

import React from ‘react‘;
import styles from ‘./table.css‘;

export default class Table extends React.Component {
  render () {
    return <div className={styles.table}>
      <div className={styles.row}>
        <div className={styles.cell}>A0</div>
        <div className={styles.cell}>B0</div>
      </div>
    </div>;
  }
}

但這裏顯然存在一些細節上的麻煩:

  1. 引入樣式時額外增加了一個styles變量
  2. 需要不斷寫styles.xxx,重復代碼

babel-plugin-react-css-modules插件可以一定程度上緩解這些問題,使代碼變為:

import React from ‘react‘;
import ‘./table.css‘;

export default class Table extends React.Component {
  render () {
    return <div styleName=‘table‘>
      <div styleName=‘row‘>
        <div styleName=‘cell‘>A0</div>
        <div styleName=‘cell‘>B0</div>
      </div>
    </div>;
  }
}

難點

  1. 我們的產品使用LESS而非原生的CSS來編寫樣式
  2. 為了生成的類名更漂亮,我們使用CSS Modules用了一個自定義的getLocalIdent實現
  3. 與webpack的整合可能存在一些難點

解決方案

安裝依賴

npm i --save babel-plugin-react-css-modules
npm i --save-dev postcss-less

需要註意的是,babel-plugin-react-css-modules有一個運行時依賴,所以用--save安裝比較好。而postcss-less則用於解析LESS的語法

調整構建配置

因為有一個自定義的生成類名的函數,所以原有的.babelrc

的JSON格式已經不夠了(無法表達函數),因此我們要把.babelrc的配置移到babel-loaderoptions裏去

在完成移動後,再向其中添加babel-plugin-react-css-modules這一插件,在這個過程中將生成類名的函數抽象出來:

const generateScopedName = (name, filename) => {
    const hash = hasha(filename + name, {algorithm: ‘md5‘});
    const basename = path.basename(filename, ‘.less‘);
    return `${dashCase(basename)}-${name}-${hash.slice(0, 5)}`;
};

exports.babel = {
    loader: ‘babel-loader‘,
    options: {
        cacheDirectory: true,
        presets: [
            // ...預置集
        ],
        plugins: [
            // ...其它插件
            [
                ‘react-css-modules‘,
                {
                    context: path.join(__dirname, ‘..‘),
                    exclude: ‘node_modules‘,
                    filetypes: {
                        ‘.less‘: {
                            syntax: ‘postcss-less‘
                        }
                    },
                    generateScopedName: generateScopedName
                }
            ]
        ]
    }
};

以上文件為webpack/loaders.js,相關的配置基本不用修改,原樣使用就行。如果這些代碼的位置不同,將其中的context配置修改一下,對應至項目根目錄就行。

然後調整一下CSS Modules相關的loader的配置,復用generateScopedName函數:

exports.cssModules = {
    loader: ‘css-loader‘,
    options: {
        sourceMap: development,
        modules: true,
        importLoaders: true,
        camelCase: ‘dashes‘,
        getLocalIdent({resourcePath}, localIdentName, localName) {
            return generateScopedName(localName, resourcePath);
        }
    }
};

修改一些源碼

需要特別註意:所有從.js中引用.less的代碼,都不可以依賴webpack的resolve.modules配置,只能寫相對路徑了。即原來寫import ‘common/less/global.less‘要改成import ‘./common/less/global.less‘

隨後按著喜好將已經用了className的地方慢慢改成styleName就行。

[轉] 使用babel-plugin-react-css-modules簡化CSS Modules的使用