Astro に React と ESLint と Prettier 導入してコードの治安を良くする

に公開

npm create astro@latest で作った Astro のプロジェクトに React と ESLint, Prettier を導入したメモ

環境

  • astro@5.7.5
  • typescript@5.8.3
  • react@19.1.0
  • eslint@9.25.1
  • prettier@3.5.3

🌀 React の導入

https://docs.astro.build/ja/guides/integrations-guide/react/

下記コマンドで React が導入される

$ npm astro add react

astoro.config.mjs に react の設定が追加される

astoro.config.mjs
// @ts-check
import { defineConfig } from 'astro/config';
+ import react from '@astrojs/react';

// https://astro.build/config
export default defineConfig({
  output: 'static',
+ integrations: [react()],
});

tsconfig.json に jsx の設定が追加されてなかったら追加する

tsconfig.json
{
  "extends": "astro/tsconfigs/strict",
  "include": [".astro/types.d.ts", "**/*"],
  ...
  "compilerOptions": {
    ...
+   "jsx": "react-jsx",
+   "jsxImportSource": "react"
  }
}

✨ Prettier を導入する

https://docs.astro.build/ja/editor-setup/#prettier
https://github.com/withastro/prettier-plugin-astro

📦 パッケージのインストール

$ npm i -D prettier prettier-plugin-astro

⚙️ Prettier の設定ファイルを作成

prettier.config.cjs で設定ファイルを作成した

prettier.config.cjs
module.exports = {
  plugins: ['prettier-plugin-astro'],
  overrides: [
    {
      files: '*.astro',
      options: { parser: 'astro' },
    },
    {
      files: ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.json'],
      options: { parser: 'typescript' },
    },
  ],
  // フォーマットの設定
  trailingComma: 'all',
  tabWidth: 2,
  printWidth: 80,
  singleQuote: false,
  arrowParens: 'always',
  bracketSpacing: true,
  bracketSameLine: false,
  semi: true,
  endOfLine: 'lf',
  ...
};

🥔 Tips
Astro で作成した package.json が type: "module" になっているので、npm script から実行しようとする js は ESmodule であることが期待されるので、CommonJS は明示的に .cjs とする必要があった

prettier の対象外にするファイルの設定

Astro の build したファイルなどは Prettier 対象外にしたいので .prettierignore を作成し対象外の設定をした

.astro/
dist/
node_modules/

✅ Prettier を実行する npm script の作成

package.json
{
  "scripts": {
     ...
+   "format": "prettier --write '**/*.{astro,ts,tsx,js,mjs,jsx,md,json}'"
  }
}

npm run format を実行し、.astro のファイルもフォーマットされれば OK


🚨 ESLint の導入

https://ota-meshi.github.io/eslint-plugin-astro/user-guide/
https://qiita.com/cieloazul310/items/e88d1bbb10119788e77e

📦 パッケージのインストール

$ npm i -D eslint eslint-plugin-astro
# TypeScript
$ npm i -D astro-eslint-parser @typescript-eslint/parser typescript-eslint
# React
$ npm i -D eslint-plugin-react eslint-plugin-react-hooks
# Prettier
$ npm i -D eslint-config-prettier

🚧 ESLint の設定ファイルを作成

eslint.config.mjs で設定ファイルを作成

eslint.config.mjs
import astroParser from 'astro-eslint-parser';
import eslintPluginAstro from 'eslint-plugin-astro';
import typescriptEslintParser from '@typescript-eslint/parser';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from 'eslint-config-prettier';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';

const eslintConfig = [
  // 除外ファイルの設定
  {
    ignores: [ ".astro/", "dist/", "node_modules" ],
  },
  ...tseslint.configs.recommended,
  ...eslintPluginAstro.configs['flat/recommended'],
  eslintConfigPrettier,
  // Astro + TypeScript
  {
    files: ['*.astro'],
    languageOptions: {
      parser: astroParser,
      parserOptions: {
        parser: typescriptEslintParser,
        extraFileExtensions: ['.astro'],
      },
    },
  },
  {
    plugins: {
      // React
      react: reactPlugin,
      'react-hooks': reactHooksPlugin,
    },
    rules: {
      // ESLint rules
      / React
      'react/jsx-uses-react': 'off', // React 17以降は import React は不要
      'react/react-in-jsx-scope': 'off', // React 17以降は不要
      'react-hooks/rules-of-hooks': 'error', // Hooksのルールを強制
      'react-hooks/exhaustive-deps': 'warn', // dependencies arrayの警告
    },
  },
];

export default eslintConfig;

✅ ESLint を実行する npm script の作成

package.json
{
  "scripts": {
     ...
+   "lint": "eslint . --ext .js,.mjs,.ts,.tsx",
+   "lint:fix": "eslint . --ext .js,.mjs,.ts,.tsx --fix",
-   "format": "prettier --write '**/*.{astro,ts,tsx,js,mjs,jsx,md,json}'"
+   "format": "prettier --write '**/*.{astro,ts,tsx,js,mjs,jsx,md,json}' && npm run lint:fix"
  }
}

npm run lint, npm run lint:fix で ESLint が実行される
npm run format で Prettier と ESLint が実行されれば OK

🚓 import, unused-imports でインポートをキレイにする

使用してない import の自動削除と、import の順番をフォーマットして治安を良くする

https://github.com/sweepline/eslint-plugin-unused-imports
https://github.com/import-js/eslint-plugin-import
https://chaika.hatenablog.com/entry/2022/01/17/083000

$ npm i -D eslint-plugin-import eslint-plugin-unused-imports

ESLint に rule を追加する

eslint.config.mjs
+ import importPlugin from 'eslint-plugin-import';
+ import unusedImports from 'eslint-plugin-unused-imports';

const eslintConfig = [
  // ...
  {
    plugins: {
+     'unused-imports': unusedImports,
+     import: importPlugin,
      react: reactPlugin,
      'react-hooks': reactHooksPlugin,
    },
    rules: {
      // ...
+     // unused-imports
+     '@typescript-eslint/no-unused-vars': 'off',
+     'unused-imports/no-unused-imports': 'error',
+     'unused-imports/no-unused-vars': [
+       'warn',
+       {
+         vars: 'all',
+         varsIgnorePattern: '^_',
+         args: 'after-used',
+         argsIgnorePattern: '^_',
+       },
+     ],
+     // import order
+     'import/order': [
+       'error',
+       {
+         groups: [
+           'builtin',
+           'external',
+           'internal',
+           ['parent', 'sibling'],
+           'index',
+           'object',
+           'type',
+         ],
+         'newlines-between': 'always',
+         alphabetize: {
+           order: 'asc',
+           caseInsensitive: true,
+         },
+         pathGroups: [
+           // grups の設定
+         ],
+       },
+     ],
    }
  },
  // ...
];

⚡ VSCode (cursor) でファイル保存時にコードフォーマットを実行する

.vscode/settings.json
{
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact",
    "astro"
  ],
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "[astro]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  },
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "always"
  },
  "files.exclude": {
    "**/node_modules": true
  },
}

これで .astro も React の .tsx もファイルの保存時にいい感じにコードがフォーマットされるようになりました 🎉

Discussion