フロントエンドアーキテクチャ構築の実践ガイド

プロジェクト全体の構築

フロントエンド開発ツールチェーン概要

現代のフロントエンド開発では、複雑なプロジェクト要件に対応するための様々なツールが存在します。

主要ツールカテゴリ

  • 静的型チェック: TypeScript, Flow
  • コード品質検査: ESLint
  • パッケージ管理: npm, Yarn
  • トランスパイラ: Babel
  • 開発サーバー: ホットリロード、HMR対応
  • バンドラー: Webpack, Rollup, Parcel
  • タスクランナー: Gulp, npm scripts
  • スキャフォールディング: Vue CLI, Vite, Create React App

ビルドツール比較: Vue CLI vs Vite

Viteは従来のVue CLIに比べて10〜100倍高速な開発サーバーを提供します。

Vue CLIの特徴

  • Webpackベースのビルドシステム
  • 統合的なプロジェクトスキャフォールド
  • プラグインエコシステム
  • GUIインターフェース

Viteの特徴

  • ブラウザのネイティブESモジュールを活用
  • Rollupベースのビルド
  • 高速な開発サーバー
  • シンプルな構成

コード品質管理

ESLintの設定と活用

コードの一貫性を保つためにESLintを活用します。

// ESLint設定例
module.exports = {
  extends: [
    'eslint:recommended',
    '@vue/typescript/recommended'
  ],
  rules: {
    'no-console': 'warn',
    'no-unused-vars': 'error'
  }
};

Prettierとの連携

コードフォーマットを自動化するためにPrettierを導入します。

// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2
}

プロジェクト構造の設計

推奨ディレクトリ構造

src/
├── components/     # 共通コンポーネント
├── views/          # ページコンポーネント
├── store/          # 状態管理
├── router/         # ルーティング
├── hooks/          # カスタムフック
├── utils/          # ユーティリティ関数
└── types/          # TypeScript型定義

Gitワークフロー

Git Flowの基本構造

  • master: 本番環境用ブランチ
  • develop: 開発ベースブランチ
  • feature/*: 機能開発ブランチ
  • release/*: リリース準備ブランチ
  • hotfix/*: 緊急修正ブランチ

UIコンポーネントライブラリ

Ant Design Vueの導入

// main.ts
import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css';

const application = createApp(App);
application.use(Antd);
application.mount('#app');

状態管理の実装

Vuex Storeの基本構造

// store/index.ts
import { createStore } from 'vuex';

interface AppState {
  user: User | null;
  settings: AppSettings;
}

export default createStore<AppState>({
  state: {
    user: null,
    settings: {}
  },
  mutations: {
    setUser(state, userData) {
      state.user = userData;
    }
  },
  actions: {
    async fetchUser({ commit }, userId) {
      const user = await api.getUser(userId);
      commit('setUser', user);
    }
  }
});

ユーティリティライブラリの活用

UUIDの生成

import { v4 as generateId } from 'uuid';

const uniqueId = generateId();
console.log(uniqueId);

Lodashユーティリティ関数

import { pick, mapValues, without } from 'lodash-es';

const sampleData = { id: 1, name: 'Test', value: 100 };
const selectedProps = pick(sampleData, ['id', 'name']);

const transformedData = mapValues(sampleData, (value) => ({
  type: typeof value,
  value
}));

const numbers = [1, 2, 3, 4, 5];
const filteredNumbers = without(numbers, 3, 4);

TypeScriptユーティリティ型

Readonly型の使用

interface UserProfile {
  username: string;
  email: string;
}

const profile: Readonly<UserProfile> = {
  username: 'developer',
  email: 'dev@example.com'
};

PartialとRequiredの活用

interface ConfigOptions {
  timeout?: number;
  retries?: number;
}

// すべてのプロパティを必須にする
const requiredConfig: Required<ConfigOptions> = {
  timeout: 5000,
  retries: 3
};

// すべてのプロパティをオプションにする
const partialConfig: Partial<ConfigOptions> = {};

テスト戦略と実装

Jestテストフレームワーク

基本的なアサーション

describe('基本的なテスト', () => {
  test('数値計算', () => {
    expect(2 + 2).toBe(4);
    expect(5).toBeGreaterThan(3);
  });

  test('オブジェクト比較', () => {
    expect({ name: 'test' }).toEqual({ name: 'test' });
  });
});

非同期処理のテスト

const fetchData = () => Promise.resolve('data');

test('非同期処理', async () => {
  const result = await fetchData();
  expect(result).toBe('data');
});

Vueコンポーネントテスト

コンポーネントのマウントとテスト

import { mount } from '@vue/test-utils';
import ButtonComponent from './Button.vue';

describe('Buttonコンポーネント', () => {
  test('クリックイベントの発火', async () => {
    const wrapper = mount(ButtonComponent, {
      props: { label: 'Click Me' }
    });

    await wrapper.trigger('click');
    expect(wrapper.emitted('click')).toBeTruthy();
  });
});

TDD開発アプローチ

テスト駆動開発のサイクル

  1. テストケースの作成(失敗)
  2. 実装コードの記述(成功)
  3. リファクタリング(改善)

ColorPickerコンポーネントのTDD例

describe('ColorPicker', () => {
  test('カラープレビューの表示', () => {
    const wrapper = mount(ColorPicker, {
      props: { value: '#ff0000' }
    });
    expect(wrapper.find('.color-preview').exists()).toBe(true);
  });

  test('カラー変更イベントの発火', async () => {
    const wrapper = mount(ColorPicker);
    await wrapper.find('.color-option').trigger('click');
    expect(wrapper.emitted('update:value')).toHaveLength(1);
  });
});

テスト環境の設定

Vue Test Utilsの設定

// jest.config.js
module.exports = {
  preset: '@vue/cli-plugin-unit-jest',
  testMatch: [
    '**/__tests__/**/*.[jt]s?(x)',
    '**/?(*.)+(spec|test).[jt]s?(x)'
  ]
};

モックの活用

API呼び出しのモック

jest.mock('axios', () => ({
  get: jest.fn(() => Promise.resolve({
    data: { id: 1, name: 'Mock User' }
  }))
}));

タイマーのモック

jest.useFakeTimers();

test('タイマー処理', () => {
  const callback = jest.fn();
  setTimeout(callback, 1000);

  jest.runAllTimers();
  expect(callback).toHaveBeenCalled();
});

タグ: vue.js TypeScript Jest Vuex Ant Design

6月18日 00:06 投稿