LoginSignup
8
7

More than 1 year has passed since last update.

はじめての Next.js(環境構築)

Last updated at Posted at 2021-02-19

はじめに

Next.jsを使うことになったので、インストールして以下を設定します
今回は最低限な設定で構築したいと思います

  • 静的サイトホスティング用の設定
  • TypeScript
  • ESLint + Prettier
  • CSS
  • Storybook
  • 単体テスト

Next.js をインストール

npx create-next-app@latest --typescript [プロジェクト名] --use-npm

デフォルトが Yarn みたいなので、use-npm オプションを付けている
以下のコマンドで画面が見れたらオッケー

npm run dev

コマンドを設定

デフォルトは以下

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

今回作るアプリは S3 に静的サイトホスティングする
よって、以下に変更

npm i -D serve
package.json
{
  "scripts": {
    "dev": "next dev",
    "export": "next build && next export",
    "serve": "next build && next export && serve ./out"
  }
}

dev は HMR をサポートしているので、普段の開発はこれでやる
export は CI で S3 にデプロイする時用
serve は静的ビルドの結果をローカルでサーバーを立てて確認する用

もし、アプリをサーバー上で動かす場合は"start": "next build && next start"を追加する

ESLint + Prettier を設定

ESLint のルールは Airbnb+TypeScript にする
Lint 系は後でルール変えると修正が大変なので、最初からキッチリ設定しておく

npm i -D eslint eslint-loader eslint-config-airbnb eslint-plugin-react-hooks eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-import @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier eslint-plugin-prettier

プロジェクトルートに.eslintrc.jsを作成

.eslintrc.js
module.exports = {
  env: { browser: true },
  extends: [
    'airbnb',
    'airbnb/hooks',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
    'prettier/@typescript-eslint',
    'prettier/react'
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: { ecmaFeatures: { jsx: true } },
  settings: { react: { version: 'detect' } },
  rules: {
    'prettier/prettier': [
      'error',
      {
        arrowParens: 'avoid',
        semi: false,
        singleQuote: true,
        trailingComma: 'none'
      }
    ]
  }
}

ここは好みだが、自分は常にリンターのエラーを修正しながら開発したいので、eslint-loader を設定する
プロジェクトルートにnext.config.jsを作成し、以下を設定

next.config.js
module.exports = {
  webpack: config => {
    config.module.rules.push({
      test: /\.tsx?$/,
      loader: 'eslint-loader',
      exclude: /node_modules/
    })
    return config
  }
}

ちなみにnext.config.tsはおそらくサポートしていないっぽい
https://github.com/vercel/next.js/issues/5318

CSS 周り

Next には CSS in JS の styled-jsx がビルトインされているので、これを使うのであれば環境設定は不要

使い方は以下のように<style jsx>で囲む

pages/index.tsx
import React from 'react'

const Home: React.FC = () => (
  <>
    <div>Hello Next.js!</div>
    <style jsx>{`
      div {
        color: blue;
      }
    `}</style>
  </>
)

export default Home

stylelint が使えたら良かったが、まだ検証段階だった
https://github.com/giuseppeg/styled-jsx-plugin-stylelint

Storybook

npm i -D @storybook/react

プロジェクトルートに.storybook/main.jsを作成し、以下を設定

.storybook/main.js
const path = require('path')

module.exports = {
  stories: ['../stories/**/*.stories.tsx'],
  webpackFinal: async config => {
    config.resolve.alias['@'] = path.join(__dirname, '../')
    return config
  }
}

stories/pages/index.stories.tsxを作成

stories/pages/index.stories.tsx
import App from '@/pages/index'

export default {
  title: 'pages'
}

export const Home = (): JSX.Element => <App />

以下のコマンドを追加

package.json
{
  "scripts": {
    "sb": "start-storybook -p 9009"
  }
}

npm run sbで動作すれば成功

Storybook が TypeScript をサポートするようになったため、以前のように Storybook 用に webpack.config を用意する必要がなくなった
https://storybook.js.org/docs/react/configure/typescript

また、以下のコマンドで上記を書かなくても、全部セットアップしてくれる(不要なものも色々入るが)
公式の最新の構成にできるので、いったんこちらを実行するのがいいかも

npx storybook init

単体テスト

テストフレームワークは軽く調べた感じ、以下で良さそう
1 年前調べた時と変わってなかった

  • テストランナー
    • Jest
  • テストフレームワーク
    • @testing-library/react
    • @testing-library/react-hooks
npm i -D jest @types/jest ts-jest @testing-library/react

以下のコマンドを追加

package.json
{
  "scripts": {
    "test": "jest --watchAll"
  }
}

プロジェクトルートにjest.config.jsを作成

jest.config.js
module.exports = {
  testMatch: ['<rootDir>/test/unit/specs/**/*.spec.tsx'],
  preset: 'ts-jest',
  moduleNameMapper: { '^@/(.*)$': '<rootDir>/$1' },
  collectCoverage: true,
  collectCoverageFrom: ['<rootDir>/pages/**/*.tsx'],
  coverageDirectory: '<rootDir>/test/unit/coverage',
  coverageReporters: ['html', 'text-summary'],
  verbose: true,
  globals: { 'ts-jest': { tsconfig: { jsx: 'react' } } }
}

tsconfig.jsonjsxオプションがpreserveで ts-jest 使うとエラーになる
https://github.com/kulshekhar/ts-jest/issues/63
なので、jest のglobalsオプションでjsxreactに書き換えている

test/unit/specs/pages/index.spec.tsxを作成
(テスト内容は適当です)

test/unit/specs/pages/index.spec.tsx
import { cleanup, render, RenderResult } from '@testing-library/react'
import React from 'react'
import Home from '@/pages/index'

let wrapper: RenderResult
beforeEach(() => (wrapper = render(<Home />)))
afterEach(cleanup)

test('Get by text', () => {
  expect(wrapper.getByText('Hello Next.js!'))
})

ts-jest やめて、babel-jest にした

ts-jest を使っていると、テスト実行時に以下の警告が出る

Warning: Received `true` for a non-boolean attribute `jsx`.

https://github.com/vercel/styled-jsx#rendering-in-tests
この辺見てもよく分からなかったので、babel-jest を使うことにした

npm i -D babel-jest
npm remove ts-jest

プロジェクトルートに.babelrcを作成

.babelrc
{
  "presets": ["next/babel"]
}

jest.config.jsを以下に変更

jest.config.js
module.exports = {
  testMatch: ['<rootDir>/test/unit/specs/**/*.spec.tsx'],
  transform: { '\\.tsx$': 'babel-jest' },
  moduleNameMapper: { '^@/(.*)$': '<rootDir>/$1' },
  collectCoverage: true,
  collectCoverageFrom: ['<rootDir>/pages/**/*.tsx'],
  coverageDirectory: '<rootDir>/test/unit/coverage',
  coverageReporters: ['html', 'text-summary'],
  verbose: true
}
8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7