コンテンツにスキップ

静的コード分析とフォーマット⚓︎

静的コード分析とフォーマットには .editorconfig 、 ESLint 、 Stylelint 、および Prettier を使用します。 これらの設定はアプリケーション間で共通することが多いため、ルートプロジェクトに配置して共通化します。 下記の手順を実行後の設定ファイルの配置例を示します。

<root-project-name> ------ ルートプロジェクト
├ .editorconfig
├ eslint.config.ts
├ .prettierrc.js
├ .stylelintrc.js
├ tsconfig.json
└ <workspace-name> ------- ワークスペース/プロジェクト
  └ .prettierrc.js
  └ .stylelintrc.js

.editorconfigの追加⚓︎

.editorconfig を用いることで、 IDE 上で追加されるファイルにフォーマットルールを課すことが可能になります。 ブランクプロジェクトの作成 時に、各ワークスペースの直下に .editorconfig が自動的に作成されているので、ルートプロジェクトに移動してください。

Visual Studio Code の推奨プラグインである EditorConfig for Visual Studio Code を使用すると、以下のような設定が可能です。

  • エンコード
  • 改行コード
  • 文末に空白行を追加
  • インデントのサイズ
  • インデントの形式
  • 行末の空白を削除

開発時に統一する必要がある項目を .editorconfig に定義します。特に開発者によって差が出やすいエンコード、改行コードやインデントのサイズなどを定めておくと良いでしょう。

.editorconfig の設定には、自動的に適用されるものと、違反すると IDE のエディター上に警告として表示されるものがあります。詳細は 公式ドキュメント を参照してください。

.editorconfig の設定例

デフォルトでは上位のフォルダ階層に対して可能なかぎり .editorconfig ファイルを探索し、複数見つかった場合は上位の階層の設定を引き継ぎつつ、 キーが重複したプロパティについては下位の階層の設定でオーバーライドします。 しかし、 root = true が設定された .editorconfig が見つかった時点で探索を停止します。 そのため、意図せず同じリポジトリ内の別の .editorconfig を参照することがないように、ルートプロジェクトの .editorconfig には root = true を設定しておくとよいでしょう。

サンプルアプリケーションの .editorconfig
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
root = true

[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

end_of_line = lf
max_line_length = 100

Prettier⚓︎

Prettier は ブランクプロジェクトの作成 時にオプションとしてインストールしているため、追加でインストールする必要はありません。 ただし、 mono-repo 構成で使用するための追加の設定をします。

Prettier の設定⚓︎

prettierrc.json という設定ファイルがワークスペースの直下に作成されているため、ルートプロジェクトの直下にコピーします。 ワークスペース側で import するために、 prettierrc.js に拡張子を変更し、 JavaScript 形式に書き換えます。

ルートプロジェクトの .prettierrc.js の設定例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/**
 * @see https://prettier.io/docs/configuration
 * @type {import("prettier").Config}
 */
const config = {
  $schema: 'https://json.schemastore.org/prettierrc',
  semi: false,
  singleQuote: true,
  printWidth: 100,
}

export default config

ワークスペース直下の prettierrc.json についても同様に拡張子を変更し、 JavaScript 形式に書き換えます。

ワークスペースの .prettierrc.js の設定例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import prettierConfigBase from '../.prettierrc.js'
/**
 * @see https://prettier.io/docs/configuration
 * @type {import("prettier").Config}
 */
const config = {
  ...prettierConfigBase,
  // ワークスペースに固有の設定があれば、追加で設定します。
}

export default config

既定の設定を上書きする場合は、設定値を記述します。 全ての設定可能な値は Options - Prettier を参照してください。また、設定方法は Configuration File - Prettier を参照してください。

一部の設定値は、既定で .editorconfig に記述している値が適用されます。したがって、.prettierrc.json では、 .editorconfig では設定できないもののみ設定すると良いでしょう。

ワークスペースの直下にいることを確認し、下記のコマンドを実行します。

npm run format

Prettier が設定ファイルを認識し、フォーマット処理が正常に実行できることを確認してください。

ESLint⚓︎

ESLint および ESLint の実行に必要なパッケージは、 ブランクプロジェクトの作成 時にオプションとしてインストールしているため、追加でインストールする必要はありません。

ESLint の設定⚓︎

設定前の動作確認⚓︎

ESLint の設定は、設定ファイル eslint.config.ts で行います。 このファイルはインストール時にワークスペースの直下に自動的に追加されています。 ワークスペースの直下にいることを確認し、下記のコマンドを実行します。

npm run lint

設定の変更前に、 ESLint が正常に実行できることを確認してください。

設定例の確認⚓︎

コーディング規約 に沿うように設定を追加・変更します。 初期設定からの変更点をハイライトで示します。

サンプルアプリケーションの eslint.config.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { globalIgnores } from 'eslint/config'
import tseslint from 'typescript-eslint'
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
import pluginVue from 'eslint-plugin-vue'
import pluginVitest from '@vitest/eslint-plugin'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import pluginCypress from 'eslint-plugin-cypress/flat'
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
import { configureVueProject } from '@vue/eslint-config-typescript'
import jsdoc from 'eslint-plugin-jsdoc'

configureVueProject({
  // mono-repo 用に、 .vue ファイルを探すルートディレクトリをデフォルト値 `process.cwd()` から変更します。
  rootDir: import.meta.dirname,
})

export default defineConfigWithVueTs(
  // Lint 対象外とするファイルパスを列挙します。
  globalIgnores([
    '**/dist/**',
    '**/dist-ssr/**',
    '**/coverage/**',
    '**/src/generated/**',
    '**/mockServiceWorker.js',
  ]),

  // Vue.js 向けの推奨ルールを適用します。
  // .vue ファイルを Lint の対象とします。
  pluginVue.configs['flat/recommended'],

  // TypeScript + Vue.js 向けの型情報を使用した推奨ルールを適用します。
  // .vue .ts .mts .ts .vue ファイルを Lint の対象とします。
  vueTsConfigs.recommendedTypeChecked,

  // 型情報を使用した Lint を実行するために、 tsconfig ファイルを探すための設定をします。
  {
    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },

  // JavaScript ファイルに対しては、 型情報を使用した Lint は無効化します。
  {
    files: ['**/*.js'],
    extends: [tseslint.configs.disableTypeChecked],
  },

  // プロジェクトやワークスペースに固有のルールを適用します。
  // 必要に応じて対象のファイルやルールを設定します。
  {
    name: 'dressca-frontend/additional-rules',
    files: ['**/*.{ts,mts,tsx,vue}'],
    rules: {
      'no-console': 'warn',
      'no-alert': 'warn',
      '@typescript-eslint/no-floating-promises': [
        'error',
        {
          // 戻り値の Promise を await 不要とみなすメソッドを例外登録します。
          allowForKnownSafeCalls: [
            { from: 'package', name: ['push', 'replace'], package: 'vue-router' },
          ],
        },
      ],
    },
  },

  // Vitest 用のテストスイートに対して、 Vitest 推奨の Lint ルールを適用します。
  {
    ...pluginVitest.configs.recommended,
    files: ['**/src/**/__tests__/**/*'],
  },

  // Cypress 用のテストスイートに対して、Cypress 推奨の Lint ルールを適用します。
  {
    ...pluginCypress.configs.recommended,
    files: [
      '**/cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}',
      '**/cypress/support/**/*.{js,ts,jsx,tsx}',
    ],
  },

  // TypeScript ファイルに対して JSDoc 形式のドキュメンテーションを強制します。
  {
    ...jsdoc.configs['flat/recommended-typescript-error'],
    files: ['**/*.ts'],
  },

  // コードのフォーマットは Prettier で実行するので、 ESLint のフォーマットルールは無効化します。
  skipFormatting,
)

mono-repo 用の設定⚓︎

mono-repo 用に、設定ファイルの配置と設定を変更します。 eslint.config.ts を、ルートプロジェクトの直下に移動してください。 設定後のファイルの配置は下記の通りです。

<root-project-name> ------ ルートプロジェクト
├ eslint.config.ts
├ tsconfig.json
├ <workspace-name> ------- ワークスペース/プロジェクト

eslint.config.ts に、下記の設定を追加してください。

1
2
3
4
5
6
7
8
{
  languageOptions: {
    parserOptions: {
      projectService: true,
      tsconfigRootDir: import.meta.dirname
    },
  },
},

.vue ファイルを探すルートディレクトリを変更するよう下記の設定を追加します。 configureVueProject() の詳細は Advanced Setup を参照してください。

1
2
3
4
import { configureVueProject } from '@vue/eslint-config-typescript'
configureVueProject({
  rootDir: import.meta.dirname,
})

src フォルダーが eslint.config.ts の直下ではなくなるので、ワークスペース配下を検索するようにパスを修正します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  ...pluginVitest.configs.recommended,
  files: ['**/src/**/__tests__/**/*'],
},
{
  ...pluginCypress.configs.recommended,
  files: [
    '**/cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}',
    '**/cypress/support/**/*.{js,ts,jsx,tsx}',
  ],
},

ルートプロジェクトの直下に、 eslint.config.ts 用の tsconfig.json ファイルを作成します。

eslint.config.ts 用の tsconfig.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "extends": "@tsconfig/node22/tsconfig.json",
  "include": ["eslint.config.ts"],
  "compilerOptions": {
    "noEmit": true,
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "types": ["node"]
  }
}

ワークスペースの直下にいることを確認し、再度下記のコマンドを実行します。

npm run lint

ESLint がルートプロジェクトの設定ファイルを自動的に認識し、正常に実行できることを確認してください。

適用ルールの変更⚓︎

Vue ファイルに適用するルールを、 flat/essential から flat/recommended に変更します。

1
pluginVue.configs['flat/recommended'],

TypeScript の型情報を使用するルールを使用するため、 vueTsConfigs.recommendedvueTsConfigs.recommendedTypeChecked に変更します。

1
vueTsConfigs.recommendedTypeChecked,

TypeScript 以外のファイルに対して、型情報を利用したルールの Lint を試みるとエラーが発生します。 そのため、 JavaScript ファイルに対して型情報を使用した Lint ルールを無効化するように、下記の設定を追加します。

1
2
3
4
5
6
import tseslint from 'typescript-eslint'

{
  files: ['**/*.js'],
  extends: [tseslint.configs.disableTypeChecked],
},

プロジェクト固有のルールを追加します。 ESLint は eslint.config.ts の先頭から設定の内容をマージするので、重複する設定は後から配置されたもので上書きされます。 そのため、プロジェクト固有のルールは、推奨ルールの設定よりも後に配置するように気を付けてください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  name: 'app/additional-rules',
  files: ['**/*.{ts,mts,tsx,vue}'],
  rules: {
    'no-console': 'warn',
    'no-alert': 'warn',
    '@typescript-eslint/no-floating-promises': [
      'error',
      {
        // 戻り値の Promise を await 不要とみなすメソッドを例外登録します。
        allowForKnownSafeCalls: [
          { from: 'package', name: ['push', 'replace'], package: 'vue-router' },
        ],
      },
    ],
  },
},

TypeScript ファイルに対して JSDoc 形式のドキュメンテーションを強制します。 ワークスペースの直下にいることを確認し、eslint-plugin-jsdoc をインストールします。

npm install -D eslint-plugin-jsdoc

eslint.config.ts に下記の設定を追加します。

1
2
3
4
5
import jsdoc from 'eslint-plugin-jsdoc'
{
  ...jsdoc.configs['flat/recommended-typescript-error'],
  files: ['**/*.ts'],
},

ESLint の対象外とするファイルを追加します。 サンプルアプリケーションでは、OpenAPI 仕様書からのクライアントコード生成 で自動生成するファイルと、 モックモードの設定 で追加するパッケージに由来するファイルは Lint 処理によって変更したくないので、 対象外にします。

1
2
3
4
5
6
7
globalIgnores([
  '**/dist/**',
  '**/dist-ssr/**',
  '**/coverage/**',
  '**/src/generated/**',
  '**/mockServiceWorker.js',
]),

その他の設定については 公式ドキュメント を参照してください。

ESLint Config Inspector で設定を可視化する

ESLint Config Inspector を使用することで、 ESLint の設定をブラウザー上で可視化できます。 ルールを変更・追加する際には、想定通りの変更が行われているか確認してください。 設定ファイルが存在するフォルダーの直下で下記のコマンドを実行することで、 ESLint Config Inspector を起動できます。

npx @eslint/config-inspector@latest

ESLint の実行⚓︎

ワークスペースの直下にいることを確認し、再度下記のコマンドを実行します。 ESLint が更新後の設定で正常に実行できることを確認してください。

npm run lint

Stylelint⚓︎

CSS ファイルおよび、 Vue ファイルの<template>ブロック、<style>ブロックに記述する CSS に対して静的解析をするため、 StyleLint を導入します。 ブランクプロジェクトの作成 時には追加されないため、手動でインストールする必要があります。

Stylelint のインストール⚓︎

ワークスペースの直下で下記のコマンドを実行してください。

npm install -D stylelint \
  stylelint-config-standard \
  stylelint-config-recommended-vue

Stylelint および、標準の設定や vue ファイルで使用する設定等をインストールします。 サンプルアプリケーションでは以下をインストールしています。

パッケージ名 使用目的
stylelint cssファイルの構文検証
stylelint-config-standard Stylelint の標準設定
stylelint-config-recommended-vue Stylelint の .vue ファイル向け推奨設定

Stylelint の設定⚓︎

ルートプロジェクトの直下に設定ファイル .stylelintrc.js を作成し、設定を記述します。

.stylelintrc.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export default {
  extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
  ignoreFiles: ['dist/**/*'],
  overrides: [
    {
      files: ['**/*.vue'],
      /** Vue ファイルの <style> ブロック内を Lint するための設定です。*/
      customSyntax: 'postcss-html',
    },
  ],
}

各ワークスペースでは、ルートプロジェクトの設定ファイルを継承し、必要に応じて設定を追加します。

.stylelintrc.js
1
2
3
4
5
import stylelintConfigBase from '../.stylelintrc.js'

export default {
  extends: stylelintConfigBase
};
extends

既存の構成を拡張します。

ignoreFiles

分析の対象外とするファイルまたはフォルダーを設定します。

overrides

特定のファイルにのみ別のルールを設定したい場合に使用します。

具体的な設定方法や設定値については 公式ドキュメント を参照してください。

デフォルトのアプリケーションに対する Stylelint の警告

create-vue で作成されるデフォルトのアプリケーションに対して Stylelint を実行すると、下記の警告が出力されて、動作確認が進められない場合があります。

src/assets/base.css
  25:1  ✖  Unexpected duplicate selector ":root", first used at line 2  no-duplicate-selectors

その場合は、 VS Code の拡張機能のサジェストに従って /* stylelint-disable-next-line no-duplicate-selectors */ を追加し、 対象箇所のルール違反を無視するようにして動作確認を続行してください。 ただし、実際のプロジェクトで使用するコードに対しては、ルール違反を無視する設定の利用はできるだけ避けて、警告に従ってコードを修正するようにしてください。

静的コード分析とフォーマットの実行⚓︎

各ワークスペースの package.json には ESLint および Prettier を実行するための scripts がデフォルトで定義されています。 CI での実行と個別の実行を可能にするため、下記のように変更します。

ESLint および Stylelint のオプション引数に --fix を、 Prettier のオプション引数に --write を設定しているため、自動で修正可能なものについては修正が実行されます。 自動で修正できないルール違反については、ターミナル上に結果が表示されます。 一方で、 :ci を付与したタスクではこれらのオプションを使用していないため、自動的に修正可能なルール違反であっても修正は実行されません。

サンプルアプリケーションの package.json
1
2
3
4
5
6
7
8
    "lint": "run-s eslint stylelint format --print-label",
    "lint:ci": "run-p eslint:ci format:ci stylelint:ci --print-label",
    "eslint": "eslint . --fix",
    "eslint:ci": "eslint .",
    "stylelint": "stylelint **/*.{vue,css} --fix",
    "stylelint:ci": "stylelint **/*.{vue,css}",
    "format": "prettier --write .",
    "format:ci": "prettier --check .",

ルートワークスペースの直下にいることを確認し、ワークスペースの設定 - スクリプトの定義 で定義した lint:ci を実行します。

npm run lint:ci:workspace-name

ESLint 、 Stylelint 、 Prettier が実行されることを確認してください。