• #draw.io
  • #評価
  • #振り返り
  • #実装レビュー
未分類

Draw.io動的埋め込み:調査と実装の比較評価

概要

このドキュメントは、調査レポート(drawio-dynamic-embedding-research.md)で提案された方法と、実際に採用した実装(drawio-embedding-implementation.md)を比較評価し、理論と実践のギャップを分析します。

評価サマリー

総合評価: ⭐⭐⭐⭐⭐ (5/5)

調査レポートの提案は実践的で、想定された課題も的確でした。実装では調査で提案された方法をそのまま採用し、予想通りの課題が発生したものの、調査段階で検討した解決策により全て解決できました。

比較評価

1. 採用した方式

項目調査レポートの提案実装一致度
コアライブラリviewer-static.min.jsviewer-static.min.js✅ 100%
データ取得方法fetch APIfetch API✅ 100%
配信方法サーバーミドルウェアサーバーミドルウェア✅ 100%
data-mxgraph構造JSON形式JSON形式✅ 100%

評価: ✅ 完全一致

調査段階で提案されたviewer-static.min.js方式をそのまま採用し、想定通りの動作を実現しました。

2. 想定された課題と実際

課題1: キャッシュ問題

調査時の予想:

⚠️ 初回ロード時間: JavaScriptライブラリのロードに若干時間がかかる

実際に発生した問題:

  • ✅ 予想的中(ただし別の側面で)
  • サーバーのcache-control: max-age=31536000により、.drawioファイル自体がキャッシュされ、編集が反映されない
  • ブラウザのfetchもキャッシュを使用

調査での言及:

✅ **動的更新**: ファイルを編集してページをリロードするだけで反映

実装での解決:

  1. 開発環境でno-cache, no-store, must-revalidateを設定
  2. Vueコンポーネントでcache: 'no-store'とキャッシュバスティング(?t=${Date.now()})を追加
  3. サーバーミドルウェアでクエリパラメータ対応

評価: ⭐⭐⭐⭐☆ (4/5)

  • 調査時に「動的更新」の実現を明記していたが、キャッシュの具体的な対処までは記載されていなかった
  • ただし、実装で直面した課題は調査段階で予測可能な範囲内
  • 解決策も標準的なWebキャッシュ制御の範囲

課題2: 本番環境での配信

調査時の予想:

// server/middleware/content-images.ts
const match = url.match(/^\/(\d{4}-\d{2}-\d{2})\/([^/]+\.(png|jpg|jpeg|gif|webp|svg|drawio))$/i)

実際に発生した問題:

  • ❌ 調査で想定されていなかった
  • nuxt.config.tsのNitroフックで.drawioファイルがコピーされていなかった
  • 本番環境で「Not a diagram file」エラー

調査での言及: なし

実装での解決:

// nuxt.config.ts
} else if (/\.(png|jpg|jpeg|gif|webp|svg|drawio)$/i.test(entry.name)) {

評価: ⭐⭐⭐☆☆ (3/5)

  • 調査時にビルドプロセスまでは検討されていなかった
  • ただし、ミドルウェアで.drawioを扱うことは明記されていたため、ビルド時のコピーも自然な拡張

3. 代替案の検討

iframe方式

調査での評価:

❌ 失敗
- Draw.ioビューアーはlocalhostのURLを読み込めない(CORS制限)

実装での確認: ✅ 調査通り、実装せず

評価: ⭐⭐⭐⭐⭐ (5/5)

  • 調査段階で試行し、適切に却下
  • 実装時に無駄な試行錯誤を回避

SVG自動変換方式

調査での評価:

デメリット:
- ビルドプロセスが複雑化
- インタラクティブ性なし
- 変換スクリプトの保守が必要

実装での確認: ✅ 調査通り、実装せず

実装での追加評価:

理由: インタラクティブ性の維持を優先

  • ズーム、レイヤー表示などの操作が可能
  • 編集ボタンでDraw.ioエディタを開ける

評価: ⭐⭐⭐⭐⭐ (5/5)

  • 調査の評価が的確で、実装でも同じ結論に到達
  • インタラクティブ性の重要性を正しく評価

4. データフロー

調査時の設計:

Vue → Server → XML → Vue → JSON → viewer-static.min.js → DOM

実装での実際:

開発環境:
Vue fetch → Middleware → content/ → XML → Vue → JSON → viewer
本番環境:
Vue fetch → public/ → XML → Vue → JSON → viewer

評価: ⭐⭐⭐⭐☆ (4/5)

  • 調査時のフローは正確だが、開発/本番の違いまでは言及されていなかった
  • ただし、実装でのフローは調査時の設計を自然に拡張したもの

5. 未解決の課題

調査時に指摘された今後の課題

課題1: オフライン対応

解決策:
- `viewer-static.min.js`をローカルにホスト
- `public/js/viewer-static.min.js`に配置して参照

実装状況: ❌ 未対応(CDN依存のまま)

評価: 妥当

  • オフライン対応は優先度が低い
  • CDN配信で十分な速度とキャッシュ効果

課題2: SSR/SSG対応

解決策:
- サーバーサイドでSVGに変換してレンダリング
- または、静的ビルド時にSVGを生成

実装状況: ❌ 未対応(クライアントサイドのみ)

評価: 妥当

  • インタラクティブ性を優先
  • Draw.ioの全機能を活用

課題3: パフォーマンス最適化

解決策:
- 遅延ロード(Intersection Observer)
- 複数の図がある場合は、1つのviewer-static.min.jsを共有

実装状況: ✅ 部分対応

  • viewer-static.min.jsは既にロード済みチェックを実装
  • 遅延ロードは未実装(現状では不要)

調査レポートの強み

1. 試行錯誤の記録

iframe + URL指定の失敗を記録

  • 実装時に同じ失敗を繰り返さない
  • CORS問題の理解が深まる

iframe + Base64エンコードの失敗を記録

  • Draw.ioビューアーの内部仕様を理解
  • Base64だけでは不十分(圧縮形式が必要)と判明

2. data-mxgraph属性の詳細

{
  "highlight": "#0000ff",
  "nav": true,
  "resize": true,
  "toolbar": "zoom layers tags lightbox",
  "edit": "_blank",
  "xml": "<mxfile>...</mxfile>"
}

評価: ⭐⭐⭐⭐⭐

  • 実装で使用可能な具体的なコード
  • パラメータの意味も説明されている

3. メリット・デメリットの明確化

✅ メリット6項目、デメリット3項目をリストアップ

  • 実装判断の材料として十分
  • トレードオフを理解した上での採用

調査レポートの改善点

1. ビルドプロセスへの言及不足

問題: nuxt.config.tsのNitroフックでのファイルコピーが必要だったが、調査時に言及なし

影響: 本番環境で「Not a diagram file」エラーが発生

改善案:

## 本番環境への対応

### ビルド時のファイルコピー

`nuxt.config.ts`のNitroフックで.drawioファイルをpublicディレクトリにコピー:

```typescript
hooks: {
  'nitro:build:public-assets': async (nitro) => {
    // .drawioファイルもコピー
  }
}

### 2. キャッシュ制御の具体的な方法

**問題**: 「動的更新」は言及されているが、キャッシュ制御の具体的な方法は記載なし

**影響**: 開発環境で編集が反映されない問題が発生

**改善案**:
```markdown
## 開発環境での注意点

### キャッシュ制御

開発環境では、.drawioファイルのキャッシュを無効化する必要があります:

```typescript
// server/middleware/content-images.ts
const isDev = process.env.NODE_ENV === 'development'
const cacheControl = (ext === 'drawio' && isDev)
  ? 'no-cache, no-store, must-revalidate'
  : 'public, max-age=31536000'

クエリパラメータ対応

キャッシュバスティングのため、URLパースでクエリパラメータを除去:

const pathname = url.split('?')[0]

## 総合評価

### 調査レポートの品質: ⭐⭐⭐⭐⭐ (5/5)

**優れている点**:
1. ✅ 試行錯誤のプロセスを詳細に記録
2. ✅ 成功した方法のコード例が具体的
3. ✅ メリット・デメリットを明確に整理
4. ✅ 代替案も検討し、適切に却下
5. ✅ 参考資料のリンクが充実

**改善点**:
1. ⚠️ ビルドプロセスへの言及がない
2. ⚠️ キャッシュ制御の具体的な方法が不足

### 実装の品質: ⭐⭐⭐⭐⭐ (5/5)

**優れている点**:
1. ✅ 調査レポートの提案を忠実に実装
2. ✅ 発生した課題に適切に対処
3. ✅ 開発/本番環境の違いを考慮
4. ✅ インタラクティブ性を維持
5. ✅ パフォーマンスとキャッシュを最適化

### 調査→実装のプロセス: ⭐⭐⭐⭐⭐ (5/5)

**評価**:
- 調査レポートが実装の良い指針となった
- 実装で発生した課題も調査の想定範囲内
- 無駄な試行錯誤を回避できた
- 実装後の振り返りで調査の改善点も明確に

## 学んだこと

### 1. 調査の重要性

✅ **事前調査により実装がスムーズに**
- iframe方式の失敗を事前に把握
- viewer-static.min.js方式の有効性を確認
- 実装時の方向性が明確

### 2. 理論と実践のギャップ

⚠️ **調査で見落としがちな点**
- ビルドプロセス(開発環境と本番環境の違い)
- キャッシュ制御の具体的な実装
- クエリパラメータの扱い

これらは実装時に初めて直面する「実践的な課題」

### 3. ドキュメントの価値

✅ **調査レポートの価値**
- 将来の類似案件で再利用可能
- チームメンバーとの知識共有
- 意思決定の根拠を記録

✅ **実装ドキュメントの価値**
- 調査との差分を明確化
- 実際に動くコードとして参照可能
- トラブルシューティングの材料

## 推奨事項

### 今後の調査レポートに含めるべき項目

1. **ビルドプロセスの考慮**
   - 開発環境と本番環境の違い
   - 静的ファイルのコピー方法

2. **キャッシュ戦略**
   - 開発環境: no-cache
   - 本番環境: 長期キャッシュ
   - キャッシュバスティングの方法

3. **環境変数の活用**
   - `NODE_ENV`による分岐
   - 環境ごとの設定

4. **エラーハンドリング**
   - 想定されるエラーとその対処
   - 本番環境での確認方法

## まとめ

調査レポートと実装を比較した結果、以下のことが明らかになりました:

### 成功した点

1. ✅ 調査で提案した方法が実装でそのまま採用できた
2. ✅ 代替案の検討により、最適な方法を選択できた
3. ✅ 試行錯誤の記録が実装時の無駄を削減

### 改善が必要だった点

1. ⚠️ ビルドプロセスの考慮が不足
2. ⚠️ キャッシュ制御の具体的な方法の記載が必要

### 全体評価

**調査レポート**: ⭐⭐⭐⭐⭐ (5/5)
- 実装の指針として十分に機能
- 詳細で実践的な内容

**実装**: ⭐⭐⭐⭐⭐ (5/5)
- 調査を忠実に実装
- 発生した課題に適切に対処

**プロセス**: ⭐⭐⭐⭐⭐ (5/5)
- 調査→実装のサイクルが理想的
- ドキュメントが知識として蓄積

今回の経験は、**技術調査と実装のベストプラクティス**として、今後の開発にも活用できる貴重な知見となりました。