概要
- scoped sass (ファイル内限定で適用されるスタイル) を使いたいでござる
- でもnpm run ejectはしたくないでござる
- 
cra-sassを導入するとかんたんにできるでござる
参考文献
実行環境
- 
create-react-appで作った react project- 既存プロジェクトなのでversionわからん すまん
 
- TypeScript
サンプルコード (変更前)
node-sass を入れてふつーにscssを使うとこうなる。
Sample.tsx
Sample.tsx
import * as React from "react";
import "./Sample.scss";
export const Sample: React.FC = () => {
  return (
    <div className="outer">
      OUTER
      <div className="inner">INNER</div>
      <ul>
        {["red", "blue", "green"].map((each, index) => (
          <li className={each} key={index}>
            {each.toUpperCase()}
          </li>
        ))}
      </ul>
    </div>
  );
};
export default Sample;
Sample.scss
Sample.scss
.outer {
  &,
  * {
    display: flex;
    flex-direction: column;
    padding: 8px;
    border-left: 1px solid gray;
  }
  font-size: 1.2rem;
  .inner {
    font-weight: bold;
  }
  ul {
    li {
      &.red {
        color: red;
      }
      &.green {
        color: green;
      }
      &.blue {
        color: blue;
      }
    }
  }
}
ビルド結果(html)
<div class="outer">
  OUTER
  <div class="inner">INNER</div>
  <ul>
    <li class="red">RED</li>
    <li class="blue">BLUE</li>
    <li class="green">GREEN</li>
  </ul>
</div>
実行結果
 
この実装の問題点
Sample.scss に記述したスタイルのscopeはグローバルである。
すなわち、Sample.tsx と同時にロードされるコンポーネントに、
同じclassName(例えば.outer)が割りあたっていると、互いに影響を受け合いバグの原因となる
解決策
閉じたscopeを扱うことのできるsass loaderを導入する
導入手順
cra-sass を実行
npx 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 * as React from "react";
import styles from "./Sample.module.scss";
export const Sample: React.FC = () => {
  return (
    <div className={styles.outer}>
      OUTER
      <div className={styles.inner}>INNER</div>
      <ul>
        {["red", "blue", "green"].map((each, index) => (
          <li className={styles[each]} key={index}>
            {each.toUpperCase()}
          </li>
        ))}
      </ul>
    </div>
  );
};
export default Sample;
ビルド結果
<div class="Sample_outer__144wv">
  OUTER
  <div class="Sample_inner__EiBfI">INNER</div>
  <ul>
    <li class="Sample_red__1ktYQ">RED</li>
    <li class="Sample_blue__32ZOZ">BLUE</li>
    <li class="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: 1px solid gray; }
  .Sample_outer__144wv .Sample_inner__EiBfI {
    font-weight: bold; }
  .Sample_outer__144wv ul li.Sample_red__1ktYQ {
    color: red; }
  .Sample_outer__144wv ul li.Sample_green__2OrZU {
    color: green; }
  .Sample_outer__144wv ul li.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/",
-    "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
+    "build-css": "node-sass-chokidar src/ -o built-css/",
+    "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 生活が始まる
