Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
20
Help us understand the problem. What is going on with this article?
@282Haniwa

Next.js 10にTypeScriptとESLint, PrettierとJestを導入する

はじめに

この記事にはNext.js 10にTypeScript, ESLint, Prettier, Jestを導入するまでの手順を書いていきます。
個人的な好みの設定も記述していますので、適宜設定を追加したり、抜いたりしながら進めてください!

最終的に出来上がるソースコードはこちらにあります。
https://github.com/282Haniwa/next-example

プロジェクトの作成

まず、next-create-appを使ってプロジェクトを作成します。

$ npx create-next-app your-project
# or
$ yarn create next-app your-project

この時点で、私はソースコードをsrcディレクトリで管理したいので修正します。
srcディレクトリでソースコードを管理したい場合、コンフィグファイルやpublicディレクトリはsrc配下に移動しないように注意しましよう。

.
├── .next
├── node_modules
├── README.md
├── package.json
├── public
├── src
│   ├── pages
│   └── styles
└── yarn.lock

最後にyarn devをすると、localhost:3000でアクセスできることが確認できると思います。

参考 : https://nextjs.org/docs/advanced-features/src-directory

TypeScriptの導入

プロジェクトが作成できたら、src/pages/index.jssrc/pages/index.tsxに変更するか、空のtsconfig.jsonを作成してyarn devを実行してください。

yarn devを実行するとメッセージとともにTypeScriptを導入するためのコマンドが表示されるので、その通りに実行しましょう。

$ yarn add --dev typescript @types/react @types/node

パッケージを追加できれば、yarn devと実行することでNext.jsでTypeScriptを利用するのに必要なファイルが自動で生成されます。
必要に応じてtsconfig.jsonなどを編集してください。

とりあえず、tsconfig.jsonのstrictはtrueにしておきましょう。

{
    ...
    "strict": true,
    ...
}

これでTypeScriptの導入は完了です。

ESLint, Prettierの導入

ESLintとPrettierを導入していきます。
ESLint関係のパッケージとPrettier関係のパッケージをそれぞれ追加します。

$ yarn add --dev \
    eslint \
    @typescript-eslint/parser \
    @typescript-eslint/eslint-plugin \
    eslint-plugin-react \
    eslint-plugin-react-hooks \
    eslint-plugin-jsx-a11y \
    eslint-plugin-import\
    eslint-import-resolver-typescript
yarn add --dev prettier eslint-plugin-prettier eslint-config-prettier

最低限eslint, @typescript-eslint/parser, @typescript-eslint/eslint-plugin,
eslint-plugin-reactがあればNext.jsでESLintを利用することはできますが、個人的にこのようなプラグインの構成にしています。
適宜好みに合わせてカスタマイズしてください。

このプラグインの構成での.eslintrc.jsの構成は以下のファイルのようになります。

また、ESLint, Prettierの導入と同時に、srcから始まる絶対パスでimportできるようにaliasを設定しています。

.eslintrc.js
/*eslint-env node*/
module.exports = {
  root: true,
  env: {
    browser: true,
    es2020: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:jsx-a11y/recommended',
    'plugin:import/errors',
    'plugin:import/warnings',
    'plugin:prettier/recommended',
    'prettier/@typescript-eslint',
    'prettier/react',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 2020,
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint', 'react', 'import'],
  settings: {
    'import/resolver': {
      node: {
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
      },
      typescript: {
        config: 'tsconfig.json',
        alwaysTryTypes: true,
      },
    },
  },
  rules: {
    '@typescript-eslint/ban-types': [
      'error',
      {
        types: {
          '{}': false,
        },
      },
    ],
    'react/prop-types': ['off'],
    'react/react-in-jsx-scope': 'off',
    'react/jsx-filename-extension': ['error', { extensions: ['.jsx', '.tsx'] }],
    'import/order': ['error'],
    'prettier/prettier': [
      'error',
      {
        trailingComma: 'all',
        endOfLine: 'lf',
        semi: false,
        singleQuote: true,
        printWidth: 80,
        tabWidth: 2,
      },
    ],
  },
}

next.config.js
/* eslint-env node */
/* eslint-disable @typescript-eslint/no-var-requires */

const path = require('path')

module.exports = {
  webpack(config) {
    config.resolve.alias = {
      ...config.resolve.alias,
      src: path.join(__dirname, 'src/'),
    }
    return config
  },
}

tsconfig.json
{
  "compilerOptions": {
    ...
    "baseUrl": "./",
    "paths": {
      "src/*": ["src/*"]
    },
    ...
}

必要に応じて編集しながら設定してください。

package.jsonscriptsyarn lintで実行できるように追記しておきましょう。

package.json
{
  ...
  "scripts": {
    ...
    "lint": "eslint --ext .js,.jsx,.ts,.tsx .",
    "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx --fix ."
  },
  ...
}

huskyの導入

ついでにcommit時にlintが走るようにhuskyも入れておきましょう。

$ yarn add --dev husky lint-staged
package.json
{
  ...
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix"
    ]
  }
  ...
}

これで、ESLint, Prettierの導入は完了です。

Jestの導入

Next.jsのプロジェクトにJestを導入していきます。
まず、必要なパッケージを追加します。

$ yarn add --dev  \
    jest  \
    ts-jest \
    react-test-renderer \
    enzyme \
    enzyme-to-json \
    @wojtekmaj/enzyme-adapter-react-17 \
    @types/jest \
    @types/react-test-renderer \
    @types/enzyme

EnzymeはまだReact 17に対応していないので、代わりに@wojtekmaj/enzyme-adapter-react-17を使います。
EnzymeはまだReact 17に対応したときに置き換えれば良いはずです。

参考: https://github.com/enzymejs/enzyme/issues/2429

必要な設定を記述します。

jest.config.js
/* eslint-env node */

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: [
    '**/__tests__/**/*.+(ts|tsx|js)',
    '**/?(*.)+(spec|test).+(ts|tsx|js)',
  ],
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
  moduleNameMapper: {
    '^src/(.*)$': '<rootDir>/src/$1',
  },
  testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  snapshotSerializers: ['enzyme-to-json/serializer'],
  setupFilesAfterEnv: ['<rootDir>/test/setupTests.ts'],
  // https://github.com/zeit/next.js/issues/8663#issue-490553899
  globals: {
    // we must specify a custom tsconfig for tests because we need the typescript transform
    // to transform jsx into js rather than leaving it jsx such as the next build requires. you
    // can see this setting in tsconfig.jest.json -> "jsx": "react"
    'ts-jest': {
      tsconfig: '<rootDir>/test/tsconfig.jest.json',
    },
  },
}

test/tsconfig.jest.json
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "jsx": "react"
  }
}

test/setupTests.ts
import Enzyme from 'enzyme'
import Adapter from '@wojtekmaj/enzyme-adapter-react-17'

Enzyme.configure({ adapter: new Adapter() })

最後にpackage.jsonscriptsyarn jestで実行できるように追記しておきましょう。

package.json
{
  ...
  "scripts": {
    ...
    "jest": "jest"
  },
  ...
}

これで、Jestの導入は完了です。
試しにコンポーネントを作って試してみます。

src/compontns/Hello/Hello.tsx
import React from 'react'

type Props = {
  name: string
}

export const Hello: React.FC<Props> = (props) => {
  const { name } = props
  return <div>Hello {name}!</div>
}

src/compontns/Hello/Hello.test.tsx
import React from 'react'
import { shallow } from 'enzyme'
import { Hello } from 'src/components/Hello'

test('Hello test', () => {
  const hello = shallow(<Hello name="World" />)

  // Interaction demo
  expect(hello.text()).toEqual('Hello World!')
  hello.setProps({ name: 'Jest' })
  expect(hello.text()).toEqual('Hello Jest!')

  // Snapshot demo
  expect(hello).toMatchSnapshot()
})

yarn jestを実行すれば、テストが走っていることが確認できます。

まとめ

以上でNext.js 10にTypeScriptとESLint, PrettierとJestを入れた環境の構築が完了になります!

最新のバージョン(2020/12/21時点)で環境構築する上でEnzymeがまだReact 17に対応していなかったりなどと、まだ業務上で使うには少し不安がありそうですが、以上の手順で環境構築まではできました!
新しい機能などを使いながら開発していければ良いなと思います!

試行錯誤しながら進めていましたので、こっちの方がいいよみたいなアドバイスがあれば是非コメントで教えてください!

参考

20
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。Twitterで情報配信中https://twitter.com/yumemiinc

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
20
Help us understand the problem. What is going on with this article?