57
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

はじめに

この記事には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に対応していなかったりなどと、まだ業務上で使うには少し不安がありそうですが、以上の手順で環境構築まではできました!
新しい機能などを使いながら開発していければ良いなと思います!

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

参考

57
39
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
57
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?