Closed21

Mear(個人制作物)にESLint, Prettier, Huskyを導入する

ふくえもんふくえもん

ESLint導入

リンターとフォーマッターの学習をしてきたので、自分のプロジェクトにも導入してみる
Next.jsに既存のeslint.jsonがあるけど、eslint.jsに変更(優先順位が高い)
まずはtypescript系ののlintが走るように設定

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", // 型安全性が確保されていない値の返却を検出
  },
};
ふくえもんふくえもん

パッケージ追加時にエラー発生

added 5 packages, changed 5 packages, and audited 425 packages in 4s

128 packages are looking for funding
  run `npm fund` for details

3 vulnerabilities (1 low, 2 moderate)

To address all issues, run:
  npm audit fix --force

Run `npm audit` for details.

脆弱性の報告が出たので、修正

ふくえもんふくえもん

パッケージのアップデート
この記事を参考にする
https://zenn.dev/feb19/articles/907990aaf95b81

ncu
Checking /~~~/~~~/~~~~/Frontend/mear/package.json
[====================] 40/40 100%

 @google/model-viewer       ^3.2.1  →    ^3.3.0
 @hookform/resolvers        ^3.3.1  →    ^3.3.2
 @radix-ui/react-popover    ^1.0.6  →    ^1.0.7
 @radix-ui/react-select     ^1.2.2  →    ^2.0.0
 @reduxjs/toolkit           ^1.9.5  →    ^1.9.7
 @types/node                20.5.9  →    20.8.6
 @types/react              18.2.21  →   18.2.28
 @types/react-dom           18.2.7  →   18.2.13
 autoprefixer              10.4.15  →   10.4.16
 axios                      ^1.5.0  →    ^1.5.1
 eslint                     8.48.0  →    8.51.0
 eslint-config-next        13.4.19  →    13.5.5
 lucide-react             ^0.277.0  →  ^0.287.0
 next                      13.4.19  →    13.5.5
 postcss                    8.4.29  →    8.4.31
 react-day-picker           ^8.8.2  →    ^8.9.0
 react-hook-form           ^7.46.1  →   ^7.47.0
 react-icons               ^4.10.1  →   ^4.11.0
 react-redux                ^8.1.2  →    ^8.1.3
 zod                       ^3.22.2  →   ^3.22.4

Run ncu -u to upgrade package.json
ふくえもんふくえもん

アップデート

 ncu -u
Upgrading /Users/fuku079/Product/Frontend/mear/package.json
[====================] 40/40 100%

 @google/model-viewer       ^3.2.1  →    ^3.3.0
 @hookform/resolvers        ^3.3.1  →    ^3.3.2
 @radix-ui/react-popover    ^1.0.6  →    ^1.0.7
 @radix-ui/react-select     ^1.2.2  →    ^2.0.0
 @reduxjs/toolkit           ^1.9.5  →    ^1.9.7
 @types/node                20.5.9  →    20.8.6
 @types/react              18.2.21  →   18.2.28
 @types/react-dom           18.2.7  →   18.2.13
 autoprefixer              10.4.15  →   10.4.16
 axios                      ^1.5.0  →    ^1.5.1
 eslint                     8.48.0  →    8.51.0
 eslint-config-next        13.4.19  →    13.5.5
 lucide-react             ^0.277.0  →  ^0.287.0
 next                      13.4.19  →    13.5.5
 postcss                    8.4.29  →    8.4.31
 react-day-picker           ^8.8.2  →    ^8.9.0
 react-hook-form           ^7.46.1  →   ^7.47.0
 react-icons               ^4.10.1  →   ^4.11.0
 react-redux                ^8.1.2  →    ^8.1.3
 zod                       ^3.22.2  →   ^3.22.4
ふくえもんふくえもん

npm iしたら修正完了

added 1 package, removed 2 packages, changed 31 packages, and audited 424 packages in 26s

126 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
ふくえもんふくえもん

lintを走らせてみる
大量のerrorが、、

エラー箇所
 npm run lint

> mear@0.1.0 lint
> next lint


./src/app/_components/Common/BottomNavbar/index.tsx
3:1  Error: `react` import should occur before import of `next/link`  import/order
6:1  Error: `react-icons/bi` import should occur before import of `react-icons/pi`  import/order

./src/app/_components/Common/Navbar/Back/index.tsx
4:1  Error: `react` import should occur before import of `next/link`  import/order

./src/app/_components/Form/DatePicker/index.tsx
7:1  Error: `@/components/ui/button` import should occur before import of `@/libs/tailwind/utils`  import/order
8:1  Error: `@/components/ui/calendar` import should occur before import of `@/libs/tailwind/utils`  import/order
9:1  Error: `@/components/ui/popover` import should occur before import of `@/libs/tailwind/utils`  import/order
14:1  Error: `lucide-react` import should occur before import of `@/libs/tailwind/utils`  import/order

./src/app/_components/Form/InputButtonCombo/index.tsx
3:1  Error: `react` import should occur before import of `@/components/ui/button`  import/order

./src/app/layout.tsx
4:1  Error: `@/libs/font` import should occur before import of `@/store/Provider`  import/order
5:1  Error: `./_components/Common/BottomNavbar` import should occur before type import of `next`  import/order

./src/app/page.tsx
2:1  Error: `@/app/post/_components/Card` import should occur before import of `@/model/PostCard`  import/order
4:1  Error: `next/link` import should occur before import of `@/model/PostCard`  import/order

./src/app/post/[postid]/_components/DetailPost/index.tsx
2:17  Error: 'FC' is defined but never used.  @typescript-eslint/no-unused-vars
3:1  Error: `react-icons/ai` import should occur after import of `next/image`  import/order
4:1  Error: `../../../_components/Card/Header` import should occur after import of `../../../../_components/Common/Navbar/Back`  import/order
8:1  Error: `../../../_components/ModelViewer/DynamicModelViewer` import should occur after import of `../../../../_components/Common/Navbar/Back`  import/order
10:1  Error: `@/model/PostCard` import should occur after import of `@/components/ui/button`  import/order

./src/app/post/_components/Card/index.tsx
9:1  Error: `@/types/Post/types` import should occur before import of `./Header`  import/order

./src/app/post/_components/ModelViewer/index.tsx
9:3  Error: ES2015 module syntax is preferred over namespaces.  @typescript-eslint/no-namespace

./src/app/post/create/_components/CreatePost/index.tsx
5:1  Error: `react-icons/md` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
6:1  Error: `react-icons/ai` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
7:1  Error: `@/components/ui/button` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
8:1  Error: `@/components/ui/textarea` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
9:1  Error: `react-icons/bi` import should occur before import of `../../../../_components/Form/DatePicker`  import/order

./src/app/post/create/page.tsx
2:1  Error: `react-redux` import should occur after import of `next/link`  import/order
3:1  Error: `@/store/features/shopSlice` import should occur after import of `@/app/post/create/_components/CreatePost`  import/order

./src/app/post/page.tsx
2:1  Error: `react` import should occur before import of `@/app/post/[postid]/_components/DetailPost`  import/order

./src/app/profile/_components/Header/index.tsx
2:1  Error: `react` import should occur before import of `next/image`  import/order

./src/app/profile/_components/Post/index.tsx
1:1  Error: `@/types/Post/types` import should occur after import of `react-icons/md`  import/order
2:1  Error: `next/image` import should occur after import of `react`  import/order

./src/app/profile/_components/Profile/index.tsx
3:1  Error: `@/types/Profile/types` import should occur before import of `../Header`  import/order
5:1  Error: `../Post` import should occur before import of `../TabBar`  import/order
6:1  Error: `@/types/Post/types` import should occur before import of `../Header`  import/order

./src/app/profile/page.tsx
4:1  Error: `@/model/Profile` import should occur before import of `../_components/Common/Navbar/Back`  import/order
5:1  Error: `@/model/PostCard` import should occur before import of `../_components/Common/Navbar/Back`  import/order

./src/app/shop/search/_components/Search/index.tsx
3:1  Error: `react` import should occur before import of `next/navigation`  import/order

./src/app/shop/search/_components/ShopItem/Container.tsx
3:1  Error: `next/navigation` import should occur before import of `@/store/features/shopSlice`  import/order
4:1  Error: `react` import should occur before import of `@/store/features/shopSlice`  import/order
7:1  Error: `react-redux` import should occur before import of `@/store/features/shopSlice`  import/order

./src/app/shop/search/_components/ShopList/index.tsx
2:1  Error: `react` import should occur before import of `@/store/features/shopSlice`  import/order

./src/app/shop/search/page.tsx
2:1  Error: `@/app/_components/Common/Navbar/Back` import should occur before import of `@/app/shop/search/_components/Search`  import/order

./src/components/ui/auto-form.tsx
13:1  Error: `react-hook-form` import should occur before import of `zod`  import/order
20:1  Error: `@/components/ui/select` import should occur before import of `./form`  import/order
27:1  Error: `@hookform/resolvers/zod` import should occur before import of `zod`  import/order
28:1  Error: `./button` import should occur before import of `./form`  import/order
30:1  Error: `./checkbox` import should occur before import of `./form`  import/order
31:1  Error: `./date-picker` import should occur before import of `./form`  import/order
32:1  Error: `@/libs/tailwind/utils` import should occur before import of `./form`  import/order
35:1  Error: `./accordion` import should occur before import of `./form`  import/order
41:1  Error: `./radio-group` import should occur before import of `./switch`  import/order
42:1  Error: `./separator` import should occur before import of `./switch`  import/order
43:1  Error: `lucide-react` import should occur before import of `zod`  import/order
80:55  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
96:28  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
105:54  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
105:59  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
117:40  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
117:45  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
136:16  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
136:21  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
138:60  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
138:65  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
141:32  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
141:37  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
153:7  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
205:64  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
205:69  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
217:45  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
221:15  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
348:51  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
363:31  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
416:70  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
426:28  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
492:56  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
492:61  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
519:58  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
519:63  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
537:51  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
604:20  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
623:55  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
623:60  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
658:17  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
658:22  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
659:30  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any
659:35  Error: Unexpected any. Specify a different type.  @typescript-eslint/no-explicit-any

./src/components/ui/calendar.tsx
8:1  Error: `@/components/ui/button` import should occur before import of `@/libs/tailwind/utils`  import/order
9:1  Error: `date-fns/locale` import should occur before import of `lucide-react`  import/order
57:25  Error: 'props' is defined but never used.  @typescript-eslint/no-unused-vars
58:26  Error: 'props' is defined but never used.  @typescript-eslint/no-unused-vars

./src/components/ui/date-picker.tsx
7:1  Error: `@/components/ui/button` import should occur before import of `@/libs/tailwind/utils`  import/order
8:1  Error: `@/components/ui/calendar` import should occur before import of `@/libs/tailwind/utils`  import/order
9:1  Error: `@/components/ui/popover` import should occur before import of `@/libs/tailwind/utils`  import/order
14:1  Error: `react` import should occur before import of `date-fns`  import/order

./src/components/ui/form.tsx
14:1  Error: `@/components/ui/label` import should occur before import of `@/libs/tailwind/utils`  import/order

./src/components/ui/radio-group.tsx
26:17  Error: 'children' is defined but never used.  @typescript-eslint/no-unused-vars

./src/store/Provider.tsx
4:1  Error: `react-redux` import should occur before import of `./store`  import/order

info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
(base) fuku079@fukuuranoMacBook-Air mear % npm run npm run lint
npm ERR! Missing script: "npm"
npm ERR! 
npm ERR! To see a list of scripts, run:
npm ERR!   npm run

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/fuku079/.npm/_logs/2023-10-17T03_56_39_103Z-debug-0.log
(base) fuku079@fukuuranoMacBook-Air mear % npm run lint

> mear@0.1.0 lint
> next lint --dir src/app


./src/app/_components/Common/BottomNavbar/index.tsx
3:1  Error: `react` import should occur before import of `next/link`  import/order
6:1  Error: `react-icons/bi` import should occur before import of `react-icons/pi`  import/order

./src/app/_components/Common/Navbar/Back/index.tsx
4:1  Error: `react` import should occur before import of `next/link`  import/order

./src/app/_components/Form/DatePicker/index.tsx
7:1  Error: `@/components/ui/button` import should occur before import of `@/libs/tailwind/utils`  import/order
8:1  Error: `@/components/ui/calendar` import should occur before import of `@/libs/tailwind/utils`  import/order
9:1  Error: `@/components/ui/popover` import should occur before import of `@/libs/tailwind/utils`  import/order
14:1  Error: `lucide-react` import should occur before import of `@/libs/tailwind/utils`  import/order

./src/app/_components/Form/InputButtonCombo/index.tsx
3:1  Error: `react` import should occur before import of `@/components/ui/button`  import/order

./src/app/layout.tsx
4:1  Error: `@/libs/font` import should occur before import of `@/store/Provider`  import/order
5:1  Error: `./_components/Common/BottomNavbar` import should occur before type import of `next`  import/order

./src/app/page.tsx
2:1  Error: `@/app/post/_components/Card` import should occur before import of `@/model/PostCard`  import/order
4:1  Error: `next/link` import should occur before import of `@/model/PostCard`  import/order

./src/app/post/[postid]/_components/DetailPost/index.tsx
2:17  Error: 'FC' is defined but never used.  @typescript-eslint/no-unused-vars
3:1  Error: `react-icons/ai` import should occur after import of `next/image`  import/order
4:1  Error: `../../../_components/Card/Header` import should occur after import of `../../../../_components/Common/Navbar/Back`  import/order
8:1  Error: `../../../_components/ModelViewer/DynamicModelViewer` import should occur after import of `../../../../_components/Common/Navbar/Back`  import/order
10:1  Error: `@/model/PostCard` import should occur after import of `@/components/ui/button`  import/order

./src/app/post/_components/Card/index.tsx
9:1  Error: `@/types/Post/types` import should occur before import of `./Header`  import/order

./src/app/post/_components/ModelViewer/index.tsx
9:3  Error: ES2015 module syntax is preferred over namespaces.  @typescript-eslint/no-namespace

./src/app/post/create/_components/CreatePost/index.tsx
5:1  Error: `react-icons/md` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
6:1  Error: `react-icons/ai` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
7:1  Error: `@/components/ui/button` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
8:1  Error: `@/components/ui/textarea` import should occur before import of `../../../../_components/Form/DatePicker`  import/order
9:1  Error: `react-icons/bi` import should occur before import of `../../../../_components/Form/DatePicker`  import/order

./src/app/post/create/page.tsx
2:1  Error: `react-redux` import should occur after import of `next/link`  import/order
3:1  Error: `@/store/features/shopSlice` import should occur after import of `@/app/post/create/_components/CreatePost`  import/order

./src/app/post/page.tsx
2:1  Error: `react` import should occur before import of `@/app/post/[postid]/_components/DetailPost`  import/order

./src/app/profile/_components/Header/index.tsx
2:1  Error: `react` import should occur before import of `next/image`  import/order

./src/app/profile/_components/Post/index.tsx
1:1  Error: `@/types/Post/types` import should occur after import of `react-icons/md`  import/order
2:1  Error: `next/image` import should occur after import of `react`  import/order

./src/app/profile/_components/Profile/index.tsx
3:1  Error: `@/types/Profile/types` import should occur before import of `../Header`  import/order
5:1  Error: `../Post` import should occur before import of `../TabBar`  import/order
6:1  Error: `@/types/Post/types` import should occur before import of `../Header`  import/order

./src/app/profile/page.tsx
4:1  Error: `@/model/Profile` import should occur before import of `../_components/Common/Navbar/Back`  import/order
5:1  Error: `@/model/PostCard` import should occur before import of `../_components/Common/Navbar/Back`  import/order

./src/app/shop/search/_components/Search/index.tsx
3:1  Error: `react` import should occur before import of `next/navigation`  import/order

./src/app/shop/search/_components/ShopItem/Container.tsx
3:1  Error: `next/navigation` import should occur before import of `@/store/features/shopSlice`  import/order
4:1  Error: `react` import should occur before import of `@/store/features/shopSlice`  import/order
7:1  Error: `react-redux` import should occur before import of `@/store/features/shopSlice`  import/order

./src/app/shop/search/_components/ShopList/index.tsx
2:1  Error: `react` import should occur before import of `@/store/features/shopSlice`  import/order

./src/app/shop/search/page.tsx
2:1  Error: `@/app/_components/Common/Navbar/Back` import should occur before import of `@/app/shop/search/_components/Search`  import/order

info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules

:::

ふくえもんふくえもん

src直下のcomponents/uiディレクトリには、shadcnからimportしたコンポーネントが配置されている
このコンポーネントはそのままにしておきたいので、lintが走る箇所を萎める

  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint --dir src/app",
    "lint:fix": "next lint --fix --dir"
  },
ふくえもんふくえもん

fixで修正した後

npm run lint

> mear@0.1.0 lint
> next lint --dir src/app


./src/app/layout.tsx
5:1  Error: `@/libs/font` import should occur before import of `@/store/Provider`  import/order

./src/app/post/[postid]/_components/DetailPost/index.tsx
2:17  Error: 'FC' is defined but never used.  @typescript-eslint/no-unused-vars

./src/app/post/_components/ModelViewer/index.tsx
9:3  Error: ES2015 module syntax is preferred over namespaces.  @typescript-eslint/no-namespace
ふくえもんふくえもん

Modelviewerのファイルとshadcnuiでimportしたコンポーネントは、lintの対象外にしておく

node_modules
.next
out
public
.prettierrc.js
.eslintrc.js
tailwind.config.js
next.config.js
postcss.config.js
src/components/
src/app/post/_components/ModelViewer
ふくえもんふくえもん

Prettier導入

インストール

$ npm i -D prettier eslint-config-prettier
ふくえもんふくえもん

Prettierの設定

{
  "printWidth": 120, // 120文字以上で改行
  "jsxBracketSameLine": false, // jsxの閉じタグを新しい行に
  "tabWidth": 2, // インデントのスペース
  "trailingComma": "none", // 配列やオブジェクトの最後の要素にカンマはつけない
  "semi": false, // 分の終わりにセミコロンを追加しない
  "singleQuote": true // 文字列はシングルクォートで囲む
}
ふくえもんふくえもん

VScodeで保存時にLintやFormatが走るように設定

.vscodeディレクトリを作成し、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"]
  }
ふくえもんふくえもん

husky導入 初

初めてhusky入れてみる
コミット時にリンターやフォーマッターのチェックが走るようになる?ぐらいの解釈です

ふくえもんふくえもん

huskyのprecommitファイルを作成する

npx husky add .husky/pre-commit "npx lint-staged"

中身

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

これでpre-commit(git commit実行時)にnpx lint-stagedを実行されるようになる

ふくえもんふくえもん

.lintstagedrc.jsを作成
lintを行うスクリプトが、next.jsだとnext lint --fix で、実行したいファイルがステージングされたファイル(commitしたいファイル)なので、そうなるようにlint-stagedの設定を行う

const path = require('path')

const buildEslintCommand = (filenames) =>
  `next lint --fix --file ${filenames.map((f) => path.relative(process.cwd(), f)).join(' --file ')}`

module.exports = {
  '*.{js,jsx,ts,tsx}': [buildEslintCommand]
}
ふくえもんふくえもん

commit時にlintが走るか検証

試しに、import順をルールに逆らってそのままcommitしてみる

このスクラップは2023/10/20にクローズされました