create-react-app + typescript + css modules

# はじめに

`create-react-app`　+ `typescript`で作ったプロジェクトを`eject`しないで`css-modules`を組み込む方法について説明します。

- typescriptでcss-modulesの型定義の解決
- create-react-appで作ったプロジェクトにcss-modulesを組みこむ

# プロジェクトの準備

`create-react-app`でtypescriptのプロジェクトを作る。

```
create-react-app my-app --scripts-version=react-scripts-ts
cd my-app
```

# css-modulesの組み込み

- [react-app-rewired](https://github.com/timarney/react-app-rewired) と [react-app-rewire-css-modules-simple](https://github.com/jackyr/react-app-rewire-css-modules-simple) を組み込む

## パッケージの追加

    ```
    yarn add -D react-app-rewired react-app-rewire-css-modules-simple
    ```
## packsge.jsonの編集
[Custom scripts versions](https://github.com/timarney/react-app-rewired#2-custom-scripts-versions)を参考に`package.json`を編集し、`react-app-rewired`を組み込む

```json:package.json
{
  "scripts": {
    "start": "react-app-rewired start --scripts-version react-scripts-ts",
    "build": "react-app-rewired build --scripts-version react-scripts-ts",
    "test": "react-app-rewired test --scripts-version react-scripts-ts --env=jsdom",
    "eject": "react-scripts eject"
  }
}
```
## config-overrides.jsの追加

react-app-rewire-css-modules-simpleの[example](https://github.com/jackyr/react-app-rewire-css-modules-simple#example)を参考にファイルを追加し、css-modulesが組み込まれる。

```
+-- your-project
|   +-- config-overrides.js
|   +-- node_modules
|   +-- package.json
|   +-- public
|   +-- README.md
|   +-- src
```

```js:config-overrides.js
/* config-overrides.js */

const rewireCssModules = require("react-app-rewire-css-modules-simple");

module.exports = function override(config, env) {
  
  config = rewireCssModules(config, env);
  
  // with loaderOptions
  config = rewireCssModules.withLoaderOptions({
    localIdentName: '[local]___[hash:base64:5]',
  })(config, env);

  return config;
};
```
- そのまま、コピペでOK
- 普通に `yarn start` で css-modules が利用できる

# cssの型定義の解決
- [typed-css-modules](https://github.com/Quramy/typed-css-modules)を利用して型定義を生成

## パッケージの追加

```
yarn add typed-css-modules -D
```

## cssの型定義の生成

```
yarn tcm -w -p src/**/*.module.css
```
- `*.module.css` というファイルを`watch`して変更があった場合は、`*.module.css.d.ts` が生成される

# 実際にコードを書いてみる
[create react app](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-a-css-modules-stylesheet)のサンプルを試してみる

## 通常のbuttonを追加してみる
```css:App.css
    :
.error {
  color: red;
}

```

```tsx:Button.tsx
import * as React from "react";
export class Button extends React.Component {
  public render(){
    return <>
      <button className="error">error button</button>
    </>
  }
}
```
```tsx:App.tsx
import { Button } from "./Button"; // コンポーネントのimport
      :
  public render() {
    return (
      <div className="App">
               :
        <Button /> // Buttonの追加
      </div>
    )
  }
```
- これで通常のボタン(文字が赤)が表示される

## css modulesを使ったボタンの追加

```css:Button.module.css
.error {
  background-color: red;
}
```

- このファイルを保存すると、`Button.module.css.d.ts`が生成される

```tsx:Button.tsx
import * as React from "react";
import * as styles from "./Button.module.css"; // d.tsファイルが生成されているので、typescriptでも型情報が解決される
export class Button extends React.Component {
  public render(){
    return <>
      <button className="error">error button</button>
      <button className={styles.error}>error button</button>　
                     {//css modulesの利用}
    </>
  }
}
```

- これでcss modulesのボタン(背景が赤)が表示される

## 注意事項
- cssのクラス名を`aaa-bbb`のように`-`が含まれている場合は、型定義が生成されず、以下のように記載する必要があります。

```tsx
<button className={styles["aaa-bbb"]} >error button</button>
```
# まとめ

create-react-appで作ったtypescriptの環境でもcss-modulesが使えるようになり、VSCodeなどのエディターでも支援が受けられ、とても便利になります。


# 参考にした記事
https://qiita.com/Quramy/items/a5d8967cdbd1b8575130