DevContainerを使いVSCodeでPHPStan・ESLint・TypeScriptを統合して静的解析をエラー検知する方法

# 概要
静的解析を行うことで、コード品質の向上とバグの早期発見が可能です。本記事では、DevContainerを活用し、VSCode内でPHPStan、ESLint、TypeScriptの静的解析を統合する方法を解説します。これにより、ローカル環境に依存せず、誰でも同じ検証が可能な開発環境を構築します。チーム全体の生産性向上に役立つ設定手順を詳しく紹介します。

# 目的

### **静的解析とは**

静的解析（Static Analysis）とは、プログラムを実行することなく、ソースコードを解析して潜在的なバグやコーディングミスを発見する技術です。これにより、以下のような問題をコーディングの早い段階で発見・修正できます：

- **構文エラーや型エラー**  
  （例：TypeScriptでの型の不一致、PHPStanでの厳密な型チェック）
- **コーディング規約の違反**  
  （例：ESLintでのJavaScript/TypeScriptのスタイルガイドの違反）
- **潜在的なセキュリティリスク**  
  （例：PHPStanでの未使用変数や不適切なメソッド呼び出し）

静的解析を活用することで、コード品質を向上させ、バグの早期発見・修正により開発効率を高めることができます。

---

### **本記事の目的**

1. **チーム全体で統一された開発環境を構築**  
   - DevContainerを使用して、各メンバーのローカル環境やOSに依存しない、一貫した開発環境を提供します。

2. **静的解析ツールの統合**  
   - PHPStan（PHP）、ESLint（JavaScript/TypeScript）、TypeScriptの解析結果をリアルタイムでVSCodeに表示し、コーディング時点で問題を発見・修正できる環境を整えます。

3. **効率的なチーム開発の実現**  
   - 統一された環境とリアルタイムエラー検知により、チーム内のコード品質を向上させ、レビューや修正にかかる時間を短縮します。

この記事では、これらの目的を達成するための具体的な設定手順と活用方法を解説します。

# 前提条件

この記事を進めるにあたり、以下の条件を満たしていることを確認してください：

1. **VSCodeとDockerがインストールされていること**  
   - DevContainerはDockerを利用して開発環境を構築するため、Dockerのセットアップが必要です。
   - VSCodeのDevContainer拡張機能がインストールされていること。

2. **PHPプロジェクトが構築済みであること**  
   - LaravelなどのPHPプロジェクトが既にセットアップされており、動作確認ができている状態。

3. **Dockerで開発環境を使用していること**（推奨）  
   - Dockerを活用してプロジェクトをセットアップしている場合、DevContainerとの親和性が高く、スムーズに設定が進められます。

4. **シリーズ記事の前提を満たしていること**（推奨）  
   - 以下のシリーズ記事を参考にし、PHPプロジェクトや環境構築が済んでいること：
     - [Laravel + Vue3 チーム開発を効率化！統一環境構築と品質向上の完全ガイド](https://qiita.com/ukei2021/items/4b2f047c72dd17c571c7)
     - [DockerでPHP 8.4/Nginx + Node 22 + MySQL環境を構築する方法](https://qiita.com/ukei2021/items/49eb61e4db221346dfe0)
     - [Laravel 11 + Inertia.js + Vue 3 + TypeScriptでモダンなフルスタック環境を構築](https://qiita.com/ukei2021/items/ca36f47975e5fc5ff16e)
     - [Laravel 11 + Vue 3プロジェクトにSassとBootstrap 5を導入する方法](https://qiita.com/ukei2021/items/2a0916ffc9c6ef900cb4)
     - [Laravelでテストコード込みのサービス・リポジトリパターンを実装する方法](https://qiita.com/ukei2021/items/53d3776f580cfd3a074b)



---

これらの前提条件を満たしていれば、この記事の手順をスムーズに進めることができます！




# 具体的な手順
この記事では、以下の静的解析ツールをVSCodeに導入し、DevContainerを活用してリアルタイムでエラーを検知する環境を構築します：

- PHPStan
- ESLint
- TypeScript

## 背景

通常、これらのツールはPHPやNode.jsを必要としますが、ローカル環境にインストールするには以下のような課題があります：

1. **OSごとの手順の違い**  
   MacとWindowsでのセットアップ手順が異なり、全員の環境を統一するのが困難です。

2. **VSCode拡張機能のインストール管理**  
   必要な拡張機能を手動で共有・インストールするのは手間がかかります。

これらの課題を解決し、チームに統一した開発環境を提供するために、**DevContainer**を使用します。


## DevContainerの導入

### DevContainerとは

DevContainerは、開発環境をコンテナ化する仕組みで、以下のような特徴を持っています：

- **VSCodeとの連携**: Dockerを活用し、統一された環境をVSCodeで簡単に利用可能。
- **環境定義の共有**: 必要なツールや設定をプロジェクト内の設定ファイル（例: `devcontainer.json`）に記述することで、チーム全体に共有できます。


### DevContainer設定ファイルの作成

プロジェクトルートに `.devcontainer` フォルダを作成し、以下の2つのファイルを配置します：
```
src
  ├─ .devcontainer
  │    ├─ devcontainer.json
  │    └─ Dockerfile
  ├─ app
  ├─ bootstrap

```

#### **`.devcontainer/devcontainer.json`**
```devcontainer.json
{
    "name": "StaticScan",
    "build": {
        "dockerfile": "Dockerfile"
    },
    "overrideCommand": true,
    "customizations": {
        "vscode": {
            "extensions": [
                "esbenp.prettier-vscode",
                "bmewburn.vscode-intelephense-client",
                "vue.volar",
                "sanderronde.phpstan-vscode",
                "dbaeumer.vscode-eslint",
                "onecentlin.laravel-blade",
                "ms-ceintl.vscode-language-pack-ja",
                "oderwat.indent-rainbow"
            ]
        }
    }
}
```
##### 設定項目の説明
- name
  - 開発環境の名前を指定します。
  - 任意の名前を設定可能で、今回は「StaticScan」にしました（静的解析を行う環境であるため）。
- build
  - 使用するDockerfileを指定します。
  - "dockerfile": "Dockerfile"とすることで、.devcontainerディレクトリ内のDockerfileが利用されます。
- overrideCommand
  - デフォルトのイメージコマンドを無効にします。
  - trueに設定すると、カスタムコマンドが有効になります。例えば、開発環境を特定の設定で立ち上げたい場合に有用です。
- customizations
  - VSCodeのカスタマイズを定義します。
  - 特に、vscode.extensionsでは拡張機能を列挙することで、環境構築時に自動でインストールされます。
- 拡張機能の指定方法
  - 拡張機能の識別子（例: dbaeumer.vscode-eslint）を記載します。
  - 各拡張機能の識別子はVSCodeの拡張機能画面で確認できます（以下はESLintの例）。

#### **`.devcontainer/Dockerfile`**
```Dockerfile
FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
    curl \
    software-properties-common \
    lsb-release \
    gnupg \
    unzip \
    git \
    && apt-get clean

# Node.js 22 のインストール
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
    apt-get install -y nodejs && \
    npm install -g npm@latest

# ondrej/php PPA の追加
RUN add-apt-repository ppa:ondrej/php && \
    apt-get update

# PHP 8.4 のインストール
RUN apt-get install -y \
    php8.4-cli \
    php8.4-mbstring \
    php8.4-xml \
    php8.4-curl \
    php8.4-zip \
    && apt-get clean


WORKDIR /workspace
```

### DevContainerの起動
1. VSCode左下の「><」アイコンをクリックします。
2. 「コンテナで再度開く」を選択します。
3. 成功すると、左下のアイコンがDevContainerに切り替わります。
![スクリーンショット 2025-01-04 22.38.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032988/b897251b-e331-1d82-3ede-3ff5b0f62eb0.png)

##### DevContainerの動作
左下のアイコンがDevContainerになっていれば、正しく起動しています。
![スクリーンショット 2025-01-04 22.59.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032988/41658c84-00cb-b272-8961-1730ae9ab7b3.png)

## 静的解析ツールの導入
### ESLint/TypeScriptの設定
#### パッケージのインストール
開発コンテナのターミナルで以下のコマンドを実行します：
```
$ npm install --save-dev eslint globals @eslint/js @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue
```


#### **`eslint.config.js`**

```eslint.config.js
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";


/** @type {import('eslint').Linter.Config[]} */
export default [
  {files: ["**/*.{js,mjs,cjs,ts,vue}"]},
  {languageOptions: { globals: globals.browser }},
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  ...pluginVue.configs["flat/essential"],
  {files: ["**/*.vue"], languageOptions: {parserOptions: {parser: tseslint.parser}}},
];
```
#### **`tsconfig.json`**
```tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "jsx": "preserve",
    "types": ["vite/client"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["resources/js/*"]
    }
  },
  "include": [
    "resources/**/*.ts",
    "resources/**/*.d.ts",
    "resources/**/*.tsx",
    "resources/**/*.vue"
  ],
  "exclude": ["node_modules"]
}
```

#### **`.vscode/settings.json`**
```settings.json
{
    "typescript.validate.enable": true,
    "javascript.validate.enable": false,
}
```

### PHPStanの設定

#### LaravelプロジェクトにLarastanをインストール
```
$ composer require --dev nunomaduro/larastan
```
#### **`phpstan.neon`**

```phpstan.neon
includes:
    - ./vendor/nunomaduro/larastan/extension.neon

parameters:
    paths:
        - app
        - database
        - tests
    level: 8

```

#### **`.vscode/settings.json`**
```settings.json
{
    "typescript.validate.enable": true,
    "javascript.validate.enable": false,
    "phpstan.binPath": "/workspaces/src/vendor/bin/phpstan",
    "phpstan.configFile": "/workspaces/src/phpstan.neon",
    "php.executablePath": "/usr/local/bin/php",
    "intelephense.environment.phpVersion": "8.4.0"
}
```


# 確認
### ESLint/TypeScript
ソースコードを編集中に、リアルタイムでエラーがVSCodeの問題タブに表示されます。
![スクリーンショット 2025-01-04 23.21.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032988/17a934b4-11fb-fd2a-d7b4-d5341af6c256.png)

PHPStan
保存後に、PHPStanのエラーがリアルタイムで表示されることを確認してください。
![スクリーンショット 2025-01-04 23.28.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032988/69ee6e67-5976-8d09-6fed-78c6768cc0bd.png)



## まとめ

この記事では、**DevContainerを活用したVSCodeでの静的解析環境の構築方法**を解説しました。以下のポイントを押さえることができました：

### **DevContainerの活用**
- Dockerを活用して、チーム全体で統一された開発環境を簡単に構築・共有。
- ローカル環境やOSの違いに依存せず、一貫性のある環境を提供。

### **静的解析ツールの導入**
- **PHPStan**: Laravelプロジェクトに対応したLarastanを活用し、厳密な型チェックを実現。
- **ESLintとTypeScript**: JavaScriptやTypeScriptのエラーをリアルタイムで検知し、コード品質を向上。

### **VSCodeとの統合**
- DevContainer設定により、VSCodeの拡張機能を自動インストール。
- 開発コンテナ内でリアルタイムエラー検知を可能にし、効率的なコーディングをサポート。

---

#### **静的解析を導入したのちに感じたこと**

静的解析を導入することで、開発中にリアルタイムでエラーを検知できるようになり、コード品質の向上が期待できます。しかし、実際のチーム開発では、以下のような課題が生じる可能性があります：

1. **エラーの見逃しや無視**  
   問題タブに表示されたエラーを見落としたり、意図的に無視するケースが発生することがあります。

2. **ルール遵守の監視が必要**  
   静的解析ツールのエラーを誰かが確認し、指摘しなければならず、結果的にレビューの負担が増える可能性があります。

そこで思いついたのが、**Gitのコミット時に静的解析を実行し、エラーがあればコミットできないようにする仕組み**です。この方法であれば、ルール違反が確実に検出され、チーム全体で統一したコード品質を保つことが可能になります。

---

## 次の記事の紹介

次回の記事では、この課題を解決するための方法として、**Gitコミット時に静的解析をフックで自動実行する手法**を解説します。

### **次の記事はこちら**  
[Gitコミット時に自動チェック！HuskyでESLint・PHPStan・ユニットテストを効率化する方法](https://qiita.com/ukei2021/items/592b50cbe04aaeae575f)

この記事では、以下のポイントを解説予定です：

- **Huskyの導入**  
  Gitフックを簡単に管理するためのツール、Huskyのセットアップ方法。

- **静的解析の自動実行**  
  コミット時にESLint、PHPStanを実行し、不備がある場合にコミットを防止。

- **チーム開発での活用**  
  一貫したコード品質基準をチーム全体に適用する方法。

引き続き良かったら読んでください！

### 関連記事
- [Laravel + Vue3 チーム開発を効率化！統一環境構築と品質向上の完全ガイド](https://qiita.com/ukei2021/items/4b2f047c72dd17c571c7)
- [DockerでPHP 8.4/Nginx + Node 22 + MySQL環境を構築する方法](https://qiita.com/ukei2021/items/49eb61e4db221346dfe0)
- [Laravel 11 + Inertia.js + Vue 3 + TypeScriptでモダンなフルスタック環境を構築](https://qiita.com/ukei2021/items/ca36f47975e5fc5ff16e)
- [Laravel 11 + Vue 3プロジェクトにSassとBootstrap 5を導入する方法](https://qiita.com/ukei2021/items/2a0916ffc9c6ef900cb4)
- [Laravelでテストコード込みのサービス・リポジトリパターンを実装する方法](https://qiita.com/ukei2021/items/53d3776f580cfd3a074b)
- [Gitコミット時に自動チェック！HuskyでESLint・PHPStan・ユニットテストを効率化する方法](https://qiita.com/ukei2021/items/592b50cbe04aaeae575f)