概要
- scoped sass (ファイル内限定で適用されるスタイル) を使いたいでござる
- でも
npm run eject
はしたくないでござる cra-sass
を導入するとかんたんにできるでござる
参考文献
実行環境
create-react-app
で作った react project- 既存プロジェクトなのでversionわからん すまん
- TypeScript
サンプルコード (変更前)
node-sass
を入れてふつーにscssを使うとこうなる。
Sample.tsx
Sample.tsx
import*asReactfrom"react";import"./Sample.scss";exportconstSample:React.FC=()=>{return(<divclassName="outer">
OUTER
<divclassName="inner">INNER</div><ul>{["red","blue","green"].map((each,index)=>(<liclassName={each}key={index}>{each.toUpperCase()}</li>))}</ul></div>);};exportdefaultSample;
Sample.scss
Sample.scss
.outer{&,*{display:flex;flex-direction:column;padding:8px;border-left:1pxsolidgray;}font-size:1.2rem;.inner{font-weight:bold;}ul{li{&.red{color:red;}&.green{color:green;}&.blue{color:blue;}}}}
ビルド結果(html)
<divclass="outer">
OUTER
<divclass="inner">INNER</div><ul><liclass="red">RED</li><liclass="blue">BLUE</li><liclass="green">GREEN</li></ul></div>
実行結果
この実装の問題点
Sample.scss に記述したスタイルのscopeはグローバルである。
すなわち、Sample.tsx と同時にロードされるコンポーネントに、
同じclassName(例えば.outer)が割りあたっていると、互いに影響を受け合いバグの原因となる
解決策
閉じたscopeを扱うことのできるsass loaderを導入する
導入手順
cra-sass を導入
npm install --save-dev cra-sass
cra-sass を実行
$(npm bin)/cra-sass
するとなんかいっぱいインストールしてプロジェクトが魔改造される
package.json
@ devDependencies
+ "cra-sass": "0.0.5",
@ dependencies
+ "node-sass-chokidar": "^1.4.0",
+ "npm-add-script": "^1.1.0",
+ "npm-run-all": "^4.1.5",
@ scripts
- "start": "react-scripts start",
- "build": "react-scripts --max-old-space-size=2048 build",
+ "start": "npm-run-all -p watch-css start-js",
+ "build": "npm run build-css && react-scripts build",
"test": "react-scripts test",
- "eject": "react-scripts eject"
+ "eject": "react-scripts eject",
+ "build-css": "node-sass-chokidar src/ -o src/",
+ "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
+ "start-js": "react-scripts start"
--max-old-space-size=2048
とか無くなってぶっ壊れてんじゃん!
ってことで無駄にぶっこわされたとこは直しておく
package.json
- "build": "react-scripts --max-old-space-size=2048 build",
+ "build": "npm run build-css && react-scripts --max-old-space-size=2048 build",
サンプルコード(リファクタ後)
Sample.scss
Sample.module.scss
に改名する
Sample.tsx
- scssのimport
- classNameの割当てのしかた
だけを変更
Sample.tsx
import*asReactfrom"react";importstylesfrom"./Sample.module.scss";exportconstSample:React.FC=()=>{return(<divclassName={styles.outer}>
OUTER
<divclassName={styles.inner}>INNER</div><ul>{["red","blue","green"].map((each,index)=>(<liclassName={styles[each]}key={index}>{each.toUpperCase()}</li>))}</ul></div>);};exportdefaultSample;
ビルド結果
<divclass="Sample_outer__144wv">
OUTER
<divclass="Sample_inner__EiBfI">INNER</div><ul><liclass="Sample_red__1ktYQ">RED</li><liclass="Sample_blue__32ZOZ">BLUE</li><liclass="Sample_green__2OrZU">GREEN</li></ul></div>
css部分の抜粋
.Sample_outer__144wv{font-size:1.2rem;}.Sample_outer__144wv,.Sample_outer__144wv*{display:flex;flex-direction:column;padding:8px;border-left:1pxsolidgray;}.Sample_outer__144wv.Sample_inner__EiBfI{font-weight:bold;}.Sample_outer__144wvulli.Sample_red__1ktYQ{color:red;}.Sample_outer__144wvulli.Sample_green__2OrZU{color:green;}.Sample_outer__144wvulli.Sample_blue__32ZOZ{color:blue;}
その他やったこと
scriptsが壊されてないかチェックしよう
start, build, test が、 cra-sass によって破壊されている恐れがある
特にdefaultから変更している場合注意しよう
.cssが.scssと同階層に出力されるようになってうっおとしい
- node-sass-chokidar のしわざくさい
- でもoutputしなくするオプションとかなさげ
- めんどいから、別階層に吐かせて、ignoreすることにした
package.json
- "build-css": "node-sass-chokidar src/ -o src/",
+ "build-css": "node-sass-chokidar src/ -o built-css/",
- "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
+ "watch-css": "npm run build-css && node-sass-chokidar src/ -o built-css/ --watch --recursive",
.gitignore
+/built-css
node-sass
をすでに使っていた場合、不要になる
npm r node-sass
おしまい
これで快適な React x Scoped SASS 生活が始まる