CSS Modules:babel-plugin-react-css-modules 小記

樣式管理一直是前端工程師的痛點(很煩 (╯‵□′)╯︵┴─┴),因此 CSS 的模組化方法從過去的 OOCSS、SMACSS,到近代的 BEM,還有最近的 CSS Modules 與 CSS in JS,企圖讓程式碼簡潔易懂、可重用,進而有效率地開發和維護。

這裡記錄我的玩具「吃什麼,どっち」使用 CSS Modules 之 babel-plugin-react-css-modules 的實作過程。

前言

一開始我是使用 BEM 來規範程式碼,希望利用規則來做到 CSS 模組化。BEM 的確是很好的 CSS class 命名的設計模式,但命名這件事是由人工來做的,而人的腦袋很殘,一但命名重複就導致模組化失敗,像是被覆寫這種杯具。為了解決這個問題,我又加上一些規則,例如

可是,這依舊是依賴人為操作,規則還愈來愈多 (●▼●;),因此我參考了目前主流市場上的兩種解法

好的,來看本篇的重點-babel-plugin-react-css-modules 吧,下次再看有沒有機會來討論其他解法。

安裝與設定

安裝。

npm install babel-plugin-react-css-modules --save

Webpack 設定檔如下,localIdentName 是指產生名稱的規則,點此看完整檔案。

{
  loader: 'css-loader',
  options: {
    // 省略
    localIdentName: '[path]___[name]__[local]___[hash:base64:5]',
  },
},

.babelrc 設定檔如下,在 plugins 加入 react-css-modules,點此看完整檔案。

"plugins": [
  // 省略
  "react-css-modules"
]

樣式撰寫

樣式撰寫方面,必須以 :global:local 作為產生全域或區域樣式的記號。

若在 class 前加入 :global 會產生全域的樣式。

:global .align-row {
  ...
}

產出結果。

.align-row {
  ...
}

若在 class 前加入 :local 會產生區域的樣式。

:local .slideshow {
  ...
}

產出結果,前面加上 path 和 component name,最後加入的亂亂的 hash。

.style-components-___slideshow__slideshow___2jOdi {
  ...
}

若引用多個樣式檔且含有相同 class name,可用 Named styleName resolution 解決,也就是使用時增加 style object 來辨別。

import foo from 'foo.css';
import bar from 'bar.css';

<div styleName="foo.a"></div>
<div styleName="bar.a"></div>

備註,這裡的程式碼和官方範例檔不同,而不同之處在於官方範例預設是 local 而本文預設是 global。這是由於 css-loader 的 modules 的設定不同所致,當 modules 為 true 時,babel-plugin-react-css-modules 的預設就是 local,即官網範例與說明所呈現的樣子,設定可參考這裡。但本文的 modules 是採用預設的狀態,也就是 false,所以 babel-plugin-react-css-modules 預設就是 global 了。感謝網友托尼的夏天,請見討論串

總結

優點

缺點

疑難雜症

至於研究過程解答了一些過去的疑惑,在這裡提供找到的解法…

若想使用 stylelint 這類的檢查工具…

問:是不是只有在 JS 和 CSS 分開寫的狀況下才能使用 stylelint 這類的檢查工具?CSS in JS 不能用嗎?

答:還是有工具支援的,可使用-stylelint-processor-styled-components

擔心無法使用 CSS 的完整功能…

問:是不是只有在 JS 和 CSS 分開寫的狀況下才能使用 CSS 的完整功能?CSS in JS 不能用嗎?例如:Media Query、Pseudo Class(:hover?)。

答:這裡列出 Styled Components 對於 Media QueryPseudo Class 的解法,現在連巢狀結構都可以用了。


comments powered by Disqus