🦁

next.js環境構築

2023/03/09に公開

自分用メモ
create-next-appを使えば楽なんだけどたまには手動でしとかないと忘れるので

インストール

cd ../
mkdir client && cd $_
yarn init -y
yarn add next react react-dom
yarn add -D typescript @types/{node,react,react-dom}

TypeScript設定

基本的には標準のものを使う

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",
    "incremental": true,
    "paths": {
      "@/*": [
        "./src/*"
      ]
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
}

export default nextConfig
src/pages/index.tsx
import { NextPage } from 'next'

interface IndexPageProps {}

const IndexPage: NextPage<IndexPageProps> = () => {
  return (
    <div>
      <div>Hello</div>
    </div>
  )
}
export default IndexPage
package.json
+  "type": "module",
+  "scripts": {
+    "dev": "next dev"
+  },

yarn devで動作すればOK

ESLint + Prettier

yarn add -D eslint eslint-config-{next,prettier} prettier

設定

.eslint.json
{
  "extends": [
    "next/core-web-vitals",
    "plugin:import/recommended",
    "plugin:import/warnings",
    "prettier"
  ],
  "rules": {
    "import/order": [
      "error",
      {
        "alphabetize": {
          "order": "asc"
        }
      }
    ]
  }
}
.prettierrc
{
  "trailingComma": "all",
  "tabWidth": 2,
  "semi": false,
  "singleQuote": true,
  "jsxSingleQuote": true,
  "printWidth": 120
}

StyledComponents

yarn add styled-components
yarn add -d @types/styled-components
next.config.js
+   compiler: {
+       styledComponents: true,
+   },
}

export default nextConfig
src/pages/index.tsx
import { NextPage } from 'next'
+ import styled from 'styled-components'

interface IndexPageProps {}

+ const StyledText = styled.p`
+   & {
+     color: red;
+   }
+ `

const IndexPage: NextPage<IndexPageProps> = () => {
  return (
    <div>
-       <div>Hello</div>
+       <StyledText>Hello</StyledText>
    </div>
  )
}
export default IndexPage

これだけだとProp 'className' did not match. Server: 〜なエラーが出てしまうので、公式に載っているとおりgetInitialPropsの対応を追加する

src/pages/_document.tsx
import Document, { DocumentContext } from 'next/document'
import { ServerStyleSheet } from 'styled-components'

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        })

      const initialProps = await Document.getInitialProps(ctx)
      return {
        ...initialProps,
        styles: [initialProps.styles, sheet.getStyleElement()],
      }
    } finally {
      sheet.seal()
    }
  }
}

ついでにReset CSSも追加しとく

yarn add styled-reset
src/pages/_app.tsx
import { AppProps } from 'next/app'
import { createGlobalStyle } from 'styled-components'
import reset from 'styled-reset'

const GlobalStyle = createGlobalStyle`
  & {
    ${reset}

    * {
      box-sizing: border-box;
    }
  }
`

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <GlobalStyle />
      <Component {...pageProps} />
    </>
  )
}

export default MyApp

Discussion