Next.js(13.5)でTailwindCSS・Sassの導入。ESLint・Stylelint・Prettierのセットアップ
本日のお題
Next.js(AppRouter)・TailwindCSS・Sassの欲張りセットで、 ESLint,StyleLint Prettierを導入
1. Next.jsセットアップ
まずはここから
npx create-next-app@latest
✔ What is your project named? … component-library
✔ Would you like to use TypeScript? …Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the default import alias (@/*)? … No
Creating a new Next.js app in /Users/fuku079/Product/Blog/component-library.
2. リンター導入:ESLintの設定
(ESLintについて詳しく知りたい方は以下の記事を参照)
初期状態では以下の構成になっている
.eslintrc.json
{
"extends": "next/core-web-vitals"
}
下記のようなものも含まれているらしい
eslint-plugin-react,eslint-plugin-react-hooks,eslint-plugin-next
Core-web-vitals:パフォーマンス測定のための指標
Googleが提唱しているUXに関する指標のようなもの
公式でも解説されている
設定ファイルの優先度
eslintの設定ファイルは拡張子によって、優先順位が変わる
1.eslintrc.js
2.eslintrc.cjs
3.eslintrc.yaml
4.eslintrc.yml
5.eslintrc.json
6 package.json
💡数字が小さい方が優先
今回はeslintrc.jsを使用
TypeScriptのESLintの有効化
例:型が使われていないためエラーが出てるコンポーネント
import { FC } from "react";
type SampleProps = {
name: string;
};
export const Sample: FC = ({ user }) => { //プロパティ 'user' は型 '{}' に存在しません。
return <div>{user.name}</div>;
};
このコンポーネントがある状態で、ESLintを走らせてみると…
% npm run lint
> component-library@0.1.0 lint
> next lint
✔ No ESLint warnings or errors
(base) fuku079@fukuuranoMacBook-Air compo
なんと、通っちゃいました…
これではいけないので、TypeScript用のルールを追加します
pluginとparserをインストール
npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser
.eslintrc.jsに設定を追加
module.exports = {
root: true,
extends: ["plugin:@typescript-eslint/recommended", "next/core-web-vitals"],
plugins: [],
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json",
},
rules: {
"@typescript-eslint/no-unused-vars": "error", //宣言されてるけど使用されてない変数をエラーに
"@typescript-eslint/no-explicit-any": "warn", // any型の場合に警告を出す
"@typescript-eslint/no-unsafe-call": "error", // 型安全性が確保されてない関数を呼び出した場合にエラーに
"@typescript-eslint/no-unsafe-member-access": "error", //オブジェクトのメンバーへの型安全性が確保されていないアクセスを検出
"@typescript-eslint/no-unsafe-return": "error", // 型安全性が確保されていない値の返却を検出
},
};
(tips:下の二つはわかりづらいので、後ほど深掘っていく…)
設定し終えたら、もう一度Linterを走らせてみる
% npm run lint
> component-library@0.1.0 lint
> next lint
./src/app/Sample.tsx
3:6 Error: 'SampleProps' is defined but never used. @typescript-eslint/no-unused-vars
6:16 Error: Unsafe member access .name on an `any` value. @typescript-eslint/no-unsafe-member-access
ちゃんとエラーが出た!
修正後のコード
import { FC } from "react";
type SampleProps = {
user: {
name: string;
};
};
export const Sample: FC<SampleProps> = ({ user }) => {
return <div>{user.name}</div>;
};
tips:オブジェクトのメンバーと戻り値の型安全性を検知
@typescript-eslint/no-unsafe-member-access
型定義で定義してるメンバー(変数)以外のものを使用している場合に、エラーが出る
type User = {
name: string;
};
export const Sample2 = () => {
const user: User = {
name: "John",
age: 25, //型 '{ name: string; age: number; }' を型 'User' に割り当てることはできません。オブジェクト リテラルは既知のプロパティのみ指定できます。'age' は型 'User' に存在しません。ts(2322)
};
return <div>{user.age}</div>;
};
@typescript-eslint/no-unsafe-return
型定義で定義してるメンバー(変数)以外のものを使用している場合に、エラーが出る
type User = {
name: string;
};
export function getUser(): User {
const user: any = {
name: "John",
age: 25,
};
return user; // User型にはageプロパティが存在しない
}
export const Sample3 = () => {
const user = getUser();
return <div>{user.age}</div>;
};
さっきのルール追加によって、これらの型安全性に関する問題をLinterでも検知できるようにする
% npm run lint
> component-library@0.1.0 lint
> next lint
./src/app/Sample.tsx
30:3 Error: Unsafe return of an `any` typed value. @typescript-eslint/no-unsafe-return
検知!!
import周りの設定 (✨神✨)
eslint-plugin-unused-imports
:未使用のimport文を削除するplugin
開発中に、「このコンポーネントやライブラリ使おう…….やっぱこっち使おう」という風にどんどんいろんなものをimportすることがあります。
けど、結局使わなくなったimport文を後から剥がしていくのって結構大変...(面倒)
そんな時に役立つpluguin
$ npm i -D eslint-plugin-unused-imports
eslintrc.jsに追加
plugins: ["unused-imports"],
import/order
:import文の順番を自動で並び替えしてくれるruleを追加
先ほど同様、import文がごちゃごちゃになってきたら整理するのが面倒
だけどこれがあれば、自動的に並び替えてくれてスッキリ!
eslintrc.jsのrulesに追加
rules: {
"import/order": [
"error",
{
// インポートを以下のカテゴリに分類
groups: [
"builtin", // Node.jsの組み込みモジュール
"external", // node_modulesからのインポート
"internal", // 同じパッケージ内の他のモジュールからのインポート
"parent", // 現在のディレクトリの親ディレクトリからのインポート
"sibling", // 同じディレクトリ内の他のモジュールからのインポート
"index", // 現在のディレクトリのインデックスファイルからのインポート
"object", // オブジェクトのインポート
"type", // TypeScriptの型のインポート
],
// 特定のインポートパターンをカスタムグループに分類
pathGroups: [
{
pattern: "{react,react-dom/**,react-router-dom}", // このパターンに一致するインポート
group: "builtin", // 上記のインポートをbuiltinグループとして扱う。
position: "before", // そのグループの前に配置
},
],
// pathGroupsの設定から特定のインポートタイプを除外します。
pathGroupsExcludedImportTypes: ["builtin"], // builtinタイプのインポートを除外。
// インポート文のアルファベット順にソート
alphabetize: {
order: "asc", //
},
},
],
}
並び替えに関しては、自分の好みでカスタマイズしていこう
(以下の記事を参考に)
.eslintignoreで管理対象から省くファイルを定義
node_modules
.next
out
public
.prettierrc.js
.eslintrc.js
tailwind.config.js
next.config.js
postcss.config.js
3. フォーマッター:Prettierの導入
インデントやセミコロンなどのルールを指定できる
開発チームによって変わってくるので、どういうルールなのかを理解できるようになっておきます
まずはインストール
$ npm i -D prettier eslint-config-prettier
.prettierrcというファイルを作成し、この中にルールを記述する
{
"printWidth": 120, // 120文字以上で改行
"jsxBracketSameLine": false, // jsxの閉じタグを新しい行に
"tabWidth": 2, // インデントのスペース
"trailingComma": "none", // 配列やオブジェクトの最後の要素にカンマはつけない
"semi": false, // 分の終わりにセミコロンを追加しない
"singleQuote": true // 文字列はシングルクォートで囲む
}
.eslintrc.jsにprettierを追加
extends: ['plugin:@typescript-eslint/recommended', 'next/core-web-vitals', 'prettier'],
.prettierignoreで管理対象から省くファイルを定義
node_modules
.next
dist
out
public/
*.md
4. Sass + Stylelintの導入
Q:TailwindCSSを導入したのになんでSassを入れるんだ?
A:個人開発でTailwindCSS使ってたけど、css.moduleも導入したいと思ったため
あまりCSSを学んでない状態でTailwindCSSを始めちゃったので、素のCSSの知識が乏しいです。
Sassの勉強もしつつ、自分の開発中のプロジェクトでも少しずつ取り入れていきたいという考えです
Sassのインストール
npm i --save-dev sass
Next.jsのSassの設定
Next.jsの場合は、バンドルの方で設定する必要がなく、next.config.jsに以下の設定を追加するだけで設定できる
/** @type {import('next').NextConfig} */
const path = require('path')
module.exports = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')]
}
}
めっちゃ簡単
Stylelintの導入
npm i -D stylelint stylelint-config-standard-scss stylelint-config-recess-order stylelint-config-recommended-scss
.stylelintrc.jsを作成し、設定を追加
module.exports = {
extends: ['stylelint-config-recess-order', 'stylelint-config-recommended-scss'],
rules: {
// ::before, ::afterのコロンを2つにする
'selector-pseudo-element-colon-notation': 'double',
// クラス名でアンパサンド(&)は禁止(&:hoverなどはOK)
'scss/selector-no-union-class-name': true,
// シングルクォーテーションに統一
'string-quotes': 'single'
},
ignoreFiles: ['**/node_modules/**']
}
これによって、cssプロパティの並び順を自動で整理してくれたり、コードを整形してくれる
CSSプロパティの書き順
アルファベット順:名前の通り
視覚順:人銀が見たものを認識する順番に沿って記載
(以下の記事でわかりやすくまとめてくださっています)
pacage.jsonにコマンドを追加
pacage.jsonのscriptに以下の内容を雨域
"scripts: {
//..省略
// Next.jsのESLintを使って、'src'ディレクトリ内のファイルをリントする
"lint": "next lint --dir src",
// Next.jsのESLintを使って、プロジェクト内のファイルのリントエラーを自動修正する
"lint:fix": "next lint --fix",
// Prettierを使って、指定されたファイルタイプのファイルを自動フォーマットする
// .gitignoreにリストされているファイルは無視される
"format": "prettier --write './**/*.{js,jsx,ts,tsx,json}'",
// Stylelintを使って、指定されたファイルタイプのスタイルファイルをリントする
"lint:style": "stylelint '**/*.{css,scss,sass}'",
// Stylelintを使って、指定されたファイルタイプのスタイルファイルのリントエラーを自動修正する
"lint:style:fix": "stylelint --fix '**/*.{css,scss,sass}'"
}
適当に書いたSCSSファイルをformatしてみる
.text {
color: blue;
font-size: 1em;
text-align: center;
flex: 1;
display: flex;
align-items: center;
}
上記のようななSCSSファイルにStylelintを走らせてみる
% npm run lint:style
> component-library@0.1.0 lint:style
> stylelint '**/*.{css,scss,sass}'
Deprecation warnings:
- The "string-quotes" rule is deprecated.
src/app/Sample.module.scss
3:3 ✖ Expected "font-size" to come before "color" order/properties-order
5:3 ✖ Expected "flex" to come before "text-align" order/properties-order
6:3 ✖ Expected "display" to come before "flex" order/properties-order
src/app/globals.css //tailwindcssの設定も引っかかってる
1:1 ✖ Unexpected unknown at-rule "@tailwind" scss/at-rule-no-unknown
2:1 ✖ Unexpected unknown at-rule "@tailwind" scss/at-rule-no-unknown
3:1 ✖ Unexpected unknown at-rule "@tailwind" scss/at-rule-no-unknown
6 problems (6 errors, 0 warnings)
ちゃんとエラーになってる
fixで自動修正
.text {
display: flex;
flex: 1;
align-items: center;
font-size: 1.5em;
color: palevioletred;
text-align: center;
}
整形された!!
VSCodeで保存時に自動整形するようにする
ルートディレクトリに.vscodeディレクトリを作成し、settings.jsonを追加
mkdir .vscode
.vscodeディレクトリ内にsettings.jsonファイルを追加
settings.json
{
// ESLintの機能を有効にする
"eslint.enable": true,
// Stylelintの機能を有効にする
"stylelint.enable": true,
// ファイルを保存する際に、自動的にフォーマットを行う
"editor.formatOnSave": true,
// 保存時に実行されるコードアクションを指定
"editor.codeActionsOnSave": {
// 保存時にESLintによる自動修正を行う
"source.fixAll.eslint": true,
// 保存時に不足しているインポートを自動的に追加する
"source.addMissingImports": true
},
// SCSSのバリデーションを無効にする(VSCodeのデフォルトのSCSSバリデーションを避けるため)
"scss.validate": false,
// SCSSファイルに特有の設定
"[scss]": {
// SCSSファイルを保存する際に自動フォーマットを行わない
"editor.formatOnSave": false,
// SCSSファイルを保存する際にStylelintによる自動修正を行う
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": true
}
},
// Stylelintでバリデーションを行うファイルタイプを指定(この場合、SCSSファイルのみ)
"stylelint.validate": ["scss"]
}
これで保存時に自動整形ができるようになる
TailwindCSSのためのESLint設定
TailwindCSSを使ってる時に、classNameを結構適当に書いて、ぐちゃぐちゃになるケースがある
CSSやSass同様に、自動で整形してくれたり、間違ったclassを定義しているのを検知してくれるpluginが存在する
$ npm i -D eslint-plugin-tailwindcss
.eslintrc.jsのextendsに以下を追記
extends: [
"plugin:tailwindcss/recommended",
]
試しにめちゃくちゃなスタイルを当ててみる
export const Sample: FC<SampleProps> = ({ user }) => {
return (
<div className="justify-center flex text-lg p-8 ">
<div>{user.age}</div>
</div>
)
}
これを保存すると…
export const Sample: FC<SampleProps> = ({ user }) => {
return (
<div className="flex justify-center p-8 text-lg">
<div>{user.age}</div>
</div>
)
}
順番を並び替えてくれる!!
おわりに
今回できるようになったことのまとめです
ESLint
- TypeScriptの型チェック
- import文の自動削除や並べ替え
どこのファイルの何行目なのかを教えてくれたり、自動整形してくれるので、快適になる
Prettier
- コードの自動整形
Stylelint
- cssの自動整形
自動整形によって、チームで統一したコードを保つことができるし、Styleに関してもプロパティの並び順を規則に則り並び替えてくれるので、自分流というのがなくせてすごいいいものだと感じました。
StorybookやJestなどのツールの導入もこれからやっていきたいと思います
参考
Discussion