Skip to content

Developer Guide

s12kuma01 edited this page Sep 2, 2025 · 2 revisions

👨‍💻 開発者ガイド

LangPack Studioの開発環境構築、ビルド方法について説明します。

🏗️ 開発環境のセットアップ

必要なツール

Node.js

# Node.js 18以上が必要
node --version  # v18.0.0以上

# nvmを使用する場合
nvm install 18
nvm use 18

Git

git --version  # 任意のバージョン

プロジェクトのクローン

git clone https://github.com/Sumire-Labs/LangPack-Studio.git
cd LangPack-Studio

依存関係のインストール

npm install

開発サーバーの起動

npm run dev

ブラウザで http://localhost:8080 にアクセスして開発版を確認できます。

📁 プロジェクト構造

LangPack-Studio/
├── src/                     # ソースコード
│   ├── components/          # Reactコンポーネント
│   │   ├── redesign/        # 新UI設計のコンポーネント
│   │   │   ├── views/       # 各ビュー(ステップ)のコンポーネント
│   │   │   ├── Header.tsx   # アプリケーションヘッダー
│   │   │   ├── Sidebar.tsx  # サイドバーナビゲーション
│   │   │   └── WelcomeScreen.tsx # ウェルカム画面
│   │   └── [legacy]/        # 旧UIコンポーネント
│   ├── utils/               # ユーティリティ関数
│   │   ├── fileParser.ts    # ファイル解析機能
│   │   ├── resourcePackGenerator.ts # リソースパック生成
│   │   └── translationService.ts # 翻訳サービス
│   ├── types/               # TypeScript型定義
│   ├── AppNew.tsx           # メインアプリケーション(新版)
│   ├── App.tsx              # メインアプリケーション(旧版)
│   └── main.tsx             # エントリーポイント
├── public/                  # 静的ファイル
├── electron/                # Electron関連ファイル
├── dist/                    # ビルド出力
├── wiki-docs/               # Wiki文書
├── package.json             # プロジェクト設定
├── tsconfig.json            # TypeScript設定
├── vite.config.ts           # Vite設定
└── README.md                # プロジェクト説明

🔧 技術スタック

フロントエンド

  • React 18: UIライブラリ
  • TypeScript: 型安全な開発
  • Material-UI v5: UIコンポーネントライブラリ
  • Emotion: CSS-in-JS
  • React Dropzone: ファイルドラッグ&ドロップ

ビルドツール

  • Vite: 高速な開発サーバー・ビルドツール
  • Electron: デスクトップアプリケーション化

翻訳サービス

  • Axios: HTTP クライアント
  • 各種翻訳API: Google, DeepL, Azure, OpenAI, LibreTranslate

ファイル処理

  • JSZip: ZIP ファイル生成
  • File API: ブラウザでのファイル処理

🏗️ ビルドコマンド

開発ビルド

npm run dev          # 開発サーバー起動
npm run build        # 本番用ビルド
npm run preview      # ビルド結果のプレビュー

Electronビルド

npm run electron:dev    # Electron開発版
npm run electron:build  # Electron配布用パッケージ作成

テスト

npm run test        # ユニットテスト実行
npm run test:watch  # テストのウォッチモード
npm run test:coverage # カバレッジレポート生成

リント・フォーマット

npm run lint        # ESLintによるコードチェック
npm run lint:fix    # 自動修正可能なエラーの修正
npm run format      # Prettierによるコード整形

🧪 テスト

テスト構造

src/
├── components/
│   └── __tests__/           # コンポーネントテスト
├── utils/
│   └── __tests__/           # ユーティリティテスト
└── __tests__/               # 統合テスト

テストの書き方

// utils/__tests__/fileParser.test.ts
import { parseJsonFile, parseLangFile } from '../fileParser'

describe('fileParser', () => {
  test('should parse JSON file correctly', () => {
    const content = '{"key": "value"}'
    const result = parseJsonFile(content)
    
    expect(result.entries).toHaveLength(1)
    expect(result.entries[0].key).toBe('key')
    expect(result.entries[0].value).toBe('value')
  })

  test('should handle invalid JSON', () => {
    const content = 'invalid json'
    expect(() => parseJsonFile(content)).toThrow()
  })
})

コンポーネントテスト

// components/__tests__/Header.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import { ThemeProvider, createTheme } from '@mui/material/styles'
import Header from '../redesign/Header'

const renderWithTheme = (component: React.ReactElement) => {
  const theme = createTheme()
  return render(
    <ThemeProvider theme={theme}>
      {component}
    </ThemeProvider>
  )
}

describe('Header', () => {
  test('should toggle dark mode', () => {
    const mockToggle = jest.fn()
    renderWithTheme(
      <Header
        darkMode={false}
        onToggleDarkMode={mockToggle}
        onReset={() => {}}
      />
    )

    const darkModeButton = screen.getByLabelText(//i)
    fireEvent.click(darkModeButton)
    
    expect(mockToggle).toHaveBeenCalledTimes(1)
  })
})

📊 パフォーマンス最適化

バンドルサイズ最適化

# バンドルサイズ分析
npm run analyze

# Tree shakingの確認
npm run build -- --analyze

メモリ最適化

// ✅ useMemoで計算結果をキャッシュ
const expensiveValue = useMemo(() => {
  return heavyCalculation(data)
}, [data])

// ✅ useCallbackで関数をキャッシュ
const handleClick = useCallback(() => {
  // クリック処理
}, [dependency])

レンダリング最適化

// ✅ React.memoで不要な再レンダリングを防ぐ
export const ExpensiveComponent = React.memo<Props>(({ data }) => {
  return <div>{/* レンダリング内容 */}</div>
})