第八回:マイクロフロントエンドのデプロイメント
「各アプリのデプロイのタイミングをどう合わせればいい?」
「一部の機能だけ先にリリースしたい...」
「デプロイに失敗したときの影響を小さくしたい...」
マイクロフロントエンドの大きな魅力の一つが、独立したデプロイです。今回は、安全で効率的なデプロイ方法を見ていきましょう。
従来のデプロイとの違い
従来のモノリスなアプリケーション
1つのアプリ
└── 1回のデプロイで全ての機能をリリース
マイクロフロントエンドの場合
複数のアプリ
├── 商品一覧アプリ(個別にデプロイ可能)
├── カートアプリ(個別にデプロイ可能)
└── 注文アプリ(個別にデプロイ可能)
デプロイの基本戦略
1. 独立デプロイ
各アプリを独立してデプロイできる構成を作ります
# GitHub Actions例(商品一覧アプリ用)
name: Deploy Product App
on:
push:
paths:
- 'apps/product/**' # 商品一覧アプリの変更時のみ実行
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
working-directory: ./apps/product
run: npm run build
- name: Deploy
run: |
# AWS S3にデプロイする例
aws s3 sync dist/ s3://my-bucket/product-app/
2. バージョン管理
各アプリのバージョンを管理する仕組みを作ります
// manifest.json
{
"apps": {
"product": {
"version": "1.2.0",
"url": "https://cdn.example.com/product/1.2.0/",
"integrity": "sha384-..."
},
"cart": {
"version": "1.1.0",
"url": "https://cdn.example.com/cart/1.1.0/",
"integrity": "sha384-..."
}
}
}
// コンテナアプリでの読み込み
async function loadApp(name) {
const manifest = await fetch('/manifest.json').then(r => r.json());
const app = manifest.apps[name];
const script = document.createElement('script');
script.src = app.url;
script.integrity = app.integrity;
document.head.appendChild(script);
}
3. 段階的なロールアウト
新機能を徐々にリリースする仕組みを実装
// フィーチャーフラグの実装
const features = {
// ユーザーの10%に新UIを表示
newProductUI: {
enabled: true,
rolloutPercentage: 10
},
// 特定の条件のユーザーに新機能を表示
newCheckout: {
enabled: true,
condition: (user) => user.isPremium
}
};
// 使用例
function ProductList() {
if (isFeatureEnabled('newProductUI')) {
return <NewProductUI />;
}
return <OldProductUI />;
}
デプロイの自動化
1. CI/CDパイプラインの構築
# 共通の設定(.github/workflows/deploy.yml)
name: Deploy
on:
push:
branches: [main]
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
apps: ${{ steps.set-matrix.outputs.apps }}
steps:
- uses: actions/checkout@v2
- id: set-matrix
run: |
# 変更があったアプリを検出
CHANGED_APPS=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep '^apps/' | cut -d/ -f2 | uniq)
echo "::set-output name=apps::$CHANGED_APPS"
deploy:
needs: detect-changes
strategy:
matrix:
app: ${{ fromJson(needs.detect-changes.outputs.apps) }}
steps:
- name: Deploy ${{ matrix.app }}
run: |
# アプリごとのデプロイ処理
2. ロールバック戦略
// バージョン履歴の管理
const versionHistory = {
"product": [
{ version: "1.2.0", date: "2024-01-03", stable: true },
{ version: "1.1.0", date: "2024-01-01", stable: true }
]
};
// ロールバック用の関数
async function rollback(appName) {
const versions = versionHistory[appName];
const lastStableVersion = versions.find(v => v.stable);
if (lastStableVersion) {
await deployVersion(appName, lastStableVersion.version);
notifyTeam(`${appName} rolled back to ${lastStableVersion.version}`);
}
}
トラブルシューティング
1. デプロイ失敗時の対応
// ヘルスチェックの実装
async function checkAppHealth(appName, version) {
try {
// アプリの主要機能をチェック
const response = await fetch(`/${appName}/health`);
const metrics = await response.json();
// 問題があれば自動ロールバック
if (metrics.errorRate > 0.1) { // エラー率10%超
await rollback(appName);
return false;
}
return true;
} catch (error) {
console.error(`Health check failed: ${appName}`, error);
return false;
}
}
2. パフォーマンスモニタリング
// パフォーマンス監視の実装
function monitorPerformance(appName) {
// ロード時間の計測
const loadTime = performance.now();
// Core Web Vitalsの計測
new PerformanceObserver((list) => {
const metrics = list.getEntries();
metrics.forEach(metric => {
sendToAnalytics({
app: appName,
metricName: metric.name,
value: metric.value
});
});
}).observe({ entryTypes: ['web-vitals'] });
}
まとめ
マイクロフロントエンドのデプロイでは
独立したデプロイを可能に
バージョン管理を適切に
段階的なロールアウトを検討
自動化とモニタリングを実装
が重要です。
次回は、マイクロフロントエンドの監視と運用について、より詳しく見ていきます。