Next.jsでEslintとPrettierとRecoilとEmotionの初期環境を作る(備忘録)


## はじめに
以下の環境で構築していきます
- Next.js 13
- TypeScript
- Eslint
- Prettier
- Recoil

## 環境構築 (Eslint,Prettier)

```bash
yarn create next-app --typescript
```
※プロジェクト名は`frontend`にしています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/96c7f709-0424-90e8-e84a-a2e0759b5f8c.png)

```bash
cd frontend
# prettierをインストール
yarn add -D prettier eslint-config-prettier
```

以下ファイルを変更&追加
```:ディレクトリ構造
├── node_modules
├── public
├── src
├── .eslintrc
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── next-env.d.ts
├── next.config.js
├── package.json
├── README.md
├── tsconfig.json
└── yarn.lock
```

```json:.eslintrc.json
{
  "env": {
    "browser": true,
    "node": true,
    "es2022": true
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "project": "./tsconfig.json",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "extends": [
    "eslint:recommended",
    "next/core-web-vitals",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "airbnb",
    "airbnb-typescript",
    "prettier"
  ],
  "plugins": [
    "@typescript-eslint",
    "react"
  ],
  "rules": {
    "react/react-in-jsx-scope": "off",
    "react/function-component-definition": [
      2,
      {
        "namedComponents": "arrow-function",
        "unnamedComponents": "arrow-function"
      }
    ],
    "react/prop-types": "off"
  }
}
```

```json:.prettierrc.json
{
  "endOfLine": "lf",
  "semi": true,
  "singleQuote": true,
  "jsxSingleQuote": false,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 60
}
```

```:.prettierignore
# next.js build output
.next
out
# dotenv environment variables file (build for Zeit Now)
.env
.env.local
# Dependency directories
node_modules
# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# text
*.md
*.txt
*.csv
```

VSCodeのPrettierの拡張機能を追加
※プロジェクトによってはコードの整形が勝手に行われると嫌な時があるので適宜無効にしたりVSCodeの設定ファイルを書き換えることを推奨

https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode

## 環境構築 (Recoil)

※正しいアーキテクチャではない可能性があるので参考までに使用してください。他の方のアーキテクチャも参考にしてみてください。

https://qiita.com/tkmd35/items/b4630e53a907d96e3430

```bash
yarn add recoil
```

```:ディレクトリ構造
src
├── components
      └── TestChild.tsx
├── pages
      ├── _app.tsx
      ├── _document.tsx
      └── index.tsx
├── store
      ├── selectors
            └── カスタムフックに使用
      └── atoms
            └── index.ts
├── styles
└── yarn.lock
```

```tsx:_app.tsx
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import { RecoilRoot } from 'recoil';

export default function App({
  Component,
  pageProps,
}: AppProps) {
  return (
    <RecoilRoot>
      <Component {...pageProps} />
    </RecoilRoot>
  );
}
```

```tsx:index.tsx
import TestChild from '@/components/TestChild';
import { textState } from '@/store/atoms/index';
import styles from '@/styles/Home.module.css';
import { useRecoilState } from 'recoil';

export default function Home() {
  const [text, setText] = useRecoilState(textState);
  return (
    <>
      <main>
        <p>{text}</p>
        <TestChild />
      </main>
    </>
  );
}
```

```ts:atoms/index.ts
import { atom } from 'recoil';

export const textState = atom<string>({
  key: 'textState', // unique ID (with respect to other atoms/selectors)
  default: 'Hello World!', // default value (aka initial value)
});
```

```tsx:TestChild.tsx
import { textState } from '@/store/atoms/index';
import { useRecoilState } from 'recoil';

const TestChild = () => {
  const [text, setText] = useRecoilState(textState);
  return (
    <button onClick={() => setText('にゃっはろー')}>
      click
    </button>
  );
};

export default TestChild;
```

## 環境構築 (Emotion)

```bash
# emotionをインストール
yarn add @emotion/react
```

```diff_json:tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
+   "jsxImportSource": "@emotion/react",
    "incremental": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}
```
https://marketplace.visualstudio.com/items?itemName=styled-components.vscode-styled-components