CodeSandbox上にReact + TailwindCSS + twin.macro環境を作る

# 目的
気軽にちょっと実装してみたい！っていうときに毎回ローカル環境でReactアプリを作るのは面倒なので、クラウド環境上に実験場的な環境が欲しいなと思って作りました。気軽に何か試すときにCSSをファイル分けて書くのも面倒なので、tailwindcssを使うことにしました。tailwindcssだけだとちょっと複雑なレイアウトとかしたいときにカバーできるか不安だったので、twin.macroも導入してemotionでインラインcssも書けるようにしました。

# CodeSandboxとは
クラウド上にいろんな環境を作れる便利なWebサイトです。テンプレートを選ぶだけでアプリの作成をやってくれて、Reactアプリはもちろん、Next.jsやVue.js、Node.jsとかも選べます。Reactに関してはビルドシステムをcreate-react-appではなくviteにしたい、とかtypescript導入したい、っていうのもテンプレートを選ぶだけで実現できます。

# 環境
CodeSandbox上で以下の環境を構築します。

React(Vite + Typescript)
TailwindCSS
twin.macro

# 手順
### 1. CodeSandbox上でReactテンプレートからアプリを作成する

CodeSandboxのダッシュボード画面で「New Sandbox」をクリックします。
![スクリーンショット 2023-07-03 011557.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/9368a850-fc52-9fe1-b357-200fd5d39309.png)

React(Vite + TS)を選択します。もし表示されない場合は右上の検索窓からReactで検索してみてください。
![スクリーンショット 2023-07-03 012101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/a1f12657-2e12-8194-d393-a2a90f54c112.png)

ちょっと待つとReactアプリが作成されてサーバーが自動的に立ち上がった状態になります。
![スクリーンショット 2023-07-03 012243.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/c4a032d3-ce3c-1c89-5d31-5a13ec1e38da.png)

これでReactテンプレートからのアプリ作成は完了です。

### 2. TailwindCSSをインストールする
TailwindCSS公式ドキュメントを参考にしてTailwindCSSをインストールしていきます。
https://tailwindcss.com/docs/guides/vite

まずはターミナルを立ち上げます。以下の画面で右上の三転リーダーをクリックして「New Terminal」を選択します。
![スクリーンショット 2023-07-03 012539.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/a4e29477-c517-1bc3-a083-777dd4cd2651.png)

ターミナル上で以下のコマンドを実行します。TailwindCSS公式ドキュメントではnpmを使っていますが、CodeSandbox上でReactアプリ作成した場合はデフォルトでyarnが使われているので、yarnを使ったコマンドに読み替えて実行します。
`> yarn add --dev tailwindcss postcss autoprefixer`
![スクリーンショット 2023-07-03 013001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/8879eacd-0b22-3014-8de2-1842fc8c7f15.png)

完了したら次のコマンドを実行します。
`npx tailwindcss init -p`

tailwind.config.jsを以下のように書き換えます。
```tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

index.cssを以下のように書き換えます。書き換えた後、Unknown at rule @tailwindcss(unknownAtRules)という警告が出ると思いますが、特に問題ないので無視で大丈夫です。
```index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

これでTailwindCSSのインストールは完了ですApp.tsxを適当に書き換えてTailwindCSSが適用されているか確認しましょう。
```App.tsx
function App() {
  return (
    <div
      className="w-48 h-48 bg-black"
    />
  );
}

export default App;
```

書き換え終わったらRestartでサーバーを立ち上げなおして、画面上に黒い四角が表示されればOKです。
![スクリーンショット 2023-07-03 013639.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/8c3c90f4-ee5a-9225-523c-52fa695401cd.png)

![スクリーンショット 2023-07-03 013817.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/5a05e0d2-12ce-0979-a716-7af278813ce3.png)

これでTailwindCSSの導入が完了しました。次はtwin.macroを入れていきます。

### 3. twin.macroをインストールする
以下の記事を参考にさせていただきました。
https://osu-log.com/archives/975#toc2

まずはtwin.macroをインストールします。
```bash
yarn add @emotion/react @emotion/styled
yarn add --dev twin.macro @emotion/babel-plugin-jsx-pragmatic babel-plugin-macros tailwindcss -D
```

次にsrcフォルダ内にGlobalStyles.tsxを作成し、中身を記述していきます。
```src/GlobalStyles.tsx
import React from 'react'
import { css, Global } from '@emotion/react'
import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro'

const customStyles = css({
  body: {
    WebkitTapHighlightColor: theme`colors.purple.500`,
    ...tw`antialiased`,
    // グローバルスタイルをカスタマイズしたいなら、ここに追記していく
  },
})

const GlobalStyles = () => (
  <>
    <BaseStyles />
    <Global styles={customStyles} />
  </>
)

export default GlobalStyles
```

次にsrc/main.tsxから作成したGlobalStyles.tsxを読み込みます。
```src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import GlobalStyles from './GlobalStyles' // この文を追記
import App from './App'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <GlobalStyles /> // この文を追記
    <App />
  </React.StrictMode>
)
```

vite.config.jsを編集してviteにtwin.macroのプラグインを追加します。
```vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: [
          'babel-plugin-macros',
          [
            '@emotion/babel-plugin-jsx-pragmatic',
            {
              export: 'jsx',
              import: '__cssprop',
              module: '@emotion/react',
            },
          ],
          [
            '@babel/plugin-transform-react-jsx',
            { pragma: '__cssprop' },
            'twin.macro',
          ],
        ],
      },
    }),
  ],
  esbuild: {
    logOverride: { 'this-is-undefined-in-esm': 'silent' }
  },
});
```

最後にTypescriptの設定をします。src/types/twin.d.tsファイルを作成して以下の内容を記述します。
```src/types/twin.d.ts
import 'twin.macro'
import { css as cssImport } from '@emotion/react'
import { CSSInterpolation } from '@emotion/serialize'
import styledImport from '@emotion/styled'

declare module 'twin.macro' {
  // The styled and css imports
  const styled: typeof styledImport
  const css: typeof cssImport
}

declare module 'react' {
  // The css prop
  interface HTMLAttributes<T> extends DOMAttributes<T> {
    css?: CSSInterpolation
    tw?: string
  }
  // The inline svg css prop
  interface SVGProps<T> extends SVGProps<SVGSVGElement> {
    css?: CSSInterpolation
    tw?: string
  }
}
```

tsconfig.jsonに次のように追記します。
```tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "jsxImportSource": "@emotion/react"　<< この一行を追記
  },
  "include": ["src"],
  "references": [
    {
      "path": "./tsconfig.node.json"
    }
  ]
}

```

これでtwin.macroの設定は完了です。最後にtwin.macroがちゃんと適用されているか確認します。
```App.tsx
import tw, { css } from "twin.macro";
import "./App.css";

function App() {
  return (
    <div
      tw="w-48 h-48 bg-black"
      css={css`
        box-shadow: 10px 5px 5px red;
      `}
    ></div>
  );
}

export default App;
```

これで以下のように黒い四角に赤い影がついていれば、環境構築は完了になります。
![スクリーンショット 2023-07-03 015606.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139120/56e9c954-361b-3a24-8fc4-c8a040a4ba0c.png)

ちょっと試したいことや作ってみたいものがあるときに使い倒してReactともっと仲良くなれると良いなと思っています。手順実践された方お疲れさまでした。