はじめに
この記事には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.js
をsrc/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を設定しています。
/*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,
},
],
},
}
/* 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
},
}
{
"compilerOptions": {
...
"baseUrl": "./",
"paths": {
"src/*": ["src/*"]
},
...
}
必要に応じて編集しながら設定してください。
package.json
のscripts
にyarn lint
で実行できるように追記しておきましょう。
{
...
"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
{
...
"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
必要な設定を記述します。
/* 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',
},
},
}
{
"extends": "../tsconfig.json",
"compilerOptions": {
"jsx": "react"
}
}
import Enzyme from 'enzyme'
import Adapter from '@wojtekmaj/enzyme-adapter-react-17'
Enzyme.configure({ adapter: new Adapter() })
最後にpackage.json
のscripts
にyarn jest
で実行できるように追記しておきましょう。
{
...
"scripts": {
...
"jest": "jest"
},
...
}
これで、Jestの導入は完了です。
試しにコンポーネントを作って試してみます。
import React from 'react'
type Props = {
name: string
}
export const Hello: React.FC<Props> = (props) => {
const { name } = props
return <div>Hello {name}!</div>
}
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に対応していなかったりなどと、まだ業務上で使うには少し不安がありそうですが、以上の手順で環境構築まではできました!
新しい機能などを使いながら開発していければ良いなと思います!
試行錯誤しながら進めていましたので、こっちの方がいいよみたいなアドバイスがあれば是非コメントで教えてください!