create-react-appをベースにeslint(airbnb)とprettierを導入 の続編。css周りも改良したくなり、sass(scss)を使えるようにした。(ついでにcss-modulesも試した)
更にstylelintを利用して*.css
, *.scss
ファイルのフォーマットチェックを行い、prettierと連携させて自動整形出来るようにした。
0. 前提条件など
検証環境:
- Linux(Ubuntu20.04LTS)
- node 14.16.0
- npm6.14.11
prettierが予め入っている状態にしたいので、前回の最終形からスタートする。
1. css周り改善
- sass: https://sass-lang.com/
- cssの完全上位互換なので、既存の
*.css
ファイルを*.scss
にそのまま置き換えるだけで移行出来る
- cssの完全上位互換なので、既存の
- css-modules: https://github.com/css-modules/css-modules
- あくまで擬似的にだがcssをモジュール化することができ、ファイル分割の際にファイル間でのidやクラス名のバッティングによる意図しない挙動を減らすことが出来そう
- create-react-appでは標準でサポートされており、別に設定作業は必要無いがついでで試してみる
1-1. sass導入
node-sassをインストールすればOK
npm i node-sass
なお、やや古くから使っている環境で↑をやろうとする(最新版のnode-sassを入れようとする)と、バージョン不整合でエラーが起こることがある。そうした場合、
https://stackoverflow.com/questions/64625050/error-node-sass-version-5-0-0-is-incompatible-with-4-0-0 などを参考に少し古いバージョンのnode-sassを入れることで対処出来る。
create-react-appの場合、node-sassをインストールしておけばそのまますぐにsassを使い始めることができ、例えばsrc/
以下にある
index.css
およびApp.css
をそれぞれindex.scss
, App.scss
にリネームし、
index.js
およびApp.js
におけるimport文を修正(import 'index.css'
→ import 'index.scss'
といった感じ)で移行出来る。
(勿論cssも以前通りに使い続けることが出来る)
1-2. css-modules
sassと併用できる。
試しに簡単なファイルを追加して試してみる。
# before
$ tree src
src
├── App.js
├── App.scss
├── App.test.js
├── index.js
├── index.scss
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
# after
$ tree src
src
├── App.js # 編集
├── App.scss
├── App.test.js
├── dummy.module.scss # 追加
├── index.js
├── index.scss
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
App.js
でdummy.module.scss
をimportしてみる。
$color: #e30;
$dummy-test-color: #d0d;
.test {
color: $color;
}
.dummy-text {
color: $dummy-test-color;
}
ごくシンプルな例だが、sassの機能を使うために一応変数を使ってみている。
import logo from './logo.svg';
import './App.scss';
import styles from './dummy.module.scss'; // 追加
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
{/* 追加始まり */}
<div className={`test-class ${styles.test}`}>
hello css-modules with sass
</div>
<div className={styles['dummy-text']}>
dummy-text
</div>
{/* 追加終わり */}
</header>
</div>
);
}
export default App;
create-react-appで自動生成されるお馴染みのコードを少し編集して、dummy.module.scss
からインポートしたスタイルをあてがっている。
css-modulesを使う場合の注意点(面倒な点)として、クラス名がハイフン-
を含んでいたりすると単純なドット.
でクラスを呼び出せないので、上記の例ではstyles['dummy-text']
のようにしている。また、一つのclassName
内に複数のクラスを割り当てることもあるが、そのような場合は{}
とバッククウォートで囲ってあげるなどの必要がある。(上の例でtest-class
は別に何の意味もないが、複数クラスを書く場合の例として書いている。)
上記のようにしてnpm run start
などとすると、↓のようにdummy.module.scss
から読み込んだスタイルをあてがったテキストを表示出来ていることが分かる:
2. prettier, stylelintの設定
prettierはcssやscssにも使えるようなので設定してみる。
https://wemo.tech/3307 の後半部分を大幅に参考にさせて頂いているが、自分用の整理として一応書いておく。
npmで必要なパッケージをインストール
npm i -D stylelint-prettier stylelint-config-prettier stylelint-scss
# 必要に応じて設定をインストール(今回はstandard)
npm i -D stylelint-config-standard
なおstylelint-config-standard
に関して、本当はstylelint-config-airbnb
を入れようとしていた(eslint設定がairbnbだったため)が、バージョンが0.0.0
だったり、最後のアップデートが3年前だったりしたので今回は見送った。
次に、 https://stylelint.io/user-guide/configure を参考にstylelintの設定ファイルを作成する必要がある。
yaml, jsonなどの選択肢もあるが、今回は.stylelintrc.js
を作成する。
module.exports = {
plugins: ['stylelint-scss'],
extends: [
'stylelint-config-standard',
'stylelint-prettier/recommended',
],
rules: {
'at-rule-no-unknown': null,
'scss/at-rule-no-unknown': true,
}
};
- sassを使うので、
plugins
にstylelint-scss
を入れている - stylelintとprettierの連携については、 https://github.com/prettier/stylelint-prettier の通りに行う
- sassを使う際に不要なエラーが出ないように
rules
以下を設定している- (参考)
これでstylelintをlinterとして使えるようになっている。
(他にも必要であればstylelint-orderなど、適宜追加していったりする)
また、前回はnpm run format
で*.js
, *.jsx
がprettierで整形されるようにしていた。
package.json
のscript
部分を編集して、
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"format": "prettier --write ./src/**/*.{js,jsx,css,scss}"
},
のようにすることで、*.css
, *.scss
ファイルも一緒にprettierでフォーマット出来るようになる。
3. まとめ
前回記事と合わせると、プロジェクトのルートディレクトリ直下のファイルなどは
$ tree -a -L 1
.
├── .env.development
├── .env.production
├── .eslintrc.js
├── .git
├── .gitignore
├── .prettierrc.js
├── .stylelintrc.js # 追加
├── README.md
├── node_modules
├── package-lock.json # 変更(但し自動で変更されるので意識しない)
├── package.json # 変更
├── public
└── src # 必要に応じて変更(cssをscssに置き換える、css-modulesに則ったファイルを追加するなど)
といった感じ。
ここで、最終的なpackage.json
があるとnpm i
などで一気に必要なライブラリをインストール出来るなど後で便利なので、自分用に置いておく:
{
"name": "test-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.8.3",
"node-sass": "^5.0.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"format": "prettier --write ./src/**/*.{js,jsx,css,scss}"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"eslint": "^7.22.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"prettier": "^2.2.1",
"stylelint": "^13.12.0",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^21.0.0",
"stylelint-prettier": "^1.2.0",
"stylelint-scss": "^3.19.0"
}
}
参考
- https://www.i-ryo.com/entry/2020/12/11/065700
- https://dev.classmethod.jp/slide/scss-tutorial/
- https://kenjimorita.jp/react-css-modules-multiple/
- https://qiita.com/Ryo__M/items/01a1621768bc3882d5dd
- https://wemo.tech/3307
- http://cluex-developers.hateblo.jp/entry/2019/01/10/171237
- https://qiita.com/bijutubu_no_e-su/items/b1a105ea7c3defa880a8
- https://qiita.com/miwashutaro0611/items/437db965a819018f86d5
- https://github.com/kristerkari/stylelint-scss/issues/196