Support deep merging chart configs (e.g. with functions)

shoelace-style/webawesome

が関数を含む Chart.js 設定を安全にマージできるようになり、DataCloneError が解消されました。これにより、ユーザーは既存の Chart.js API をそのまま利用しつつ、Web Awesome コンポーネント側での設定処理を簡潔に保てます。

背景

このセクションでは、関数付き Chart.js 設定が引き起こすエラーとその影響を概観します。 Chart.js の tooltip.callbacks.label などのコールバック関数を含む設定オブジェクトを <wa-chart> に渡すと、内部で structuredClone が呼び出され DataCloneError がスローされました。エラーメッセージは “Failed to execute 'structuredClone' on 'Window'” と示され、コンポーネントの描画が中断されます。

再現手順は単純で、関数を含む設定オブジェクトを new Chart(...) に渡すだけです。 当該設定は公式ドキュメントでも例示されており、実務での利用頻度が高いため、エラーは実装上の重大な障壁となっていました。Issue #2444 で報告されたこのバグは、Web Awesome の主要コンポーネントの信頼性に直結していました。

結果として、関数を回避するためにカスタムプラグインを導入するという回避策が提示されましたが、実装負荷が大きく不自然でした。 そこで根本的な解決策として、設定オブジェクトのクローン処理を見直すことが決定されました。

技術的な変更

本セクションでは、clone.ts に導入された deepClone と、コンポーネント側でのマージロジック変更を詳述します。 packages/webawesome/src/utilities/clone.ts に新規追加された deepClone は、プリミティブ・関数・クラスインスタンス・DOM ノードなどを参照渡しし、プレーンオブジェクトと配列のみを再帰的にコピーします。これにより、関数を含む構造体でも structuredClone のように例外を投げません。

export function deepClone<T>(value: T, seen = new WeakMap<object, unknown>()): T {
  if (value === null || typeof value !== 'object') {
    return value; // primitives and functions are returned as‑is
  }
  if (seen.has(value as object)) {
    return seen.get(value as object) as T; // circular reference guard
  }
  if (Array.isArray(value)) {
    const result: unknown[] = [];
    seen.set(value as object, result);
    for (const item of value) {
      result.push(deepClone(item, seen));
    }
    return result as T;
  }
  if (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
    const result: Record<string, unknown> = {};
    seen.set(value as object, result);
    for (const key of Object.keys(value as Record<string, unknown>)) {
      result[key] = deepClone((value as Record<string, unknown>)[key], seen);
    }
    return result as T;
  }
  return value;
}

deepClone が導入されたことにより、<wa-chart> の内部で設定オブジェクトをマージする際に安全なコピーが取得できるようになりました。 具体的には、applyDefaultConfig で受け取ったユーザー設定とデフォルト設定を deepClone 後に再帰的にマージし、関数はそのまま保持されます。結果として、Chart.js のコールバック関数が正しく動作し、エラーが発生しなくなります。

設計上の選択肢としては、structuredClone の代替として既存のロジックを置き換えるか、外部ライブラリを導入するかが考えられました。 本実装は軽量で依存性を増やさず、Circular reference にも対応している点が評価され、採用が決定されました。

設計判断

このセクションでは、カスタムクローン実装を選んだ背景とトレードオフを整理します。 structuredClone は標準 API で安全性は高いものの、関数や DOM ノードといった非シリアライズ可能な値を受け付けず、Chart.js 設定のようなユースケースでは不適切です。代替案としては、lodash.cloneDeep のような汎用ライブラリを使用する方法がありますが、バンドルサイズ増大や余計なプロトタイプ除去のリスクがあります。

deepClone は「プレーンオブジェクトと配列だけをクローンし、その他は参照で渡す」シンプルな方針を取っています。 これにより、関数やクラスインスタンスが意図せずコピーされて失われることが防げ、かつ実装が数十行に収まります。Circular reference のハンドリングも WeakMap により安全に処理しています。

結果として、Web Awesome のコンポーネントは既存の API 互換性を保ちつつ、関数付き設定をサポートできるようになりました。 今後、同様の構造体を扱う他コンポーネントでも deepClone を再利用でき、コードベース全体の保守性が向上します。

まとめ

本 PR で導入された deepClone により、<wa-chart> が関数を含む Chart.js 設定を安全にマージでき、DataCloneError が解消されました。 変更は内部ユーティリティの追加のみで、外部 API への影響はなく、既存プロジェクトへの導入障壁はほぼゼロです。今後は同様のパターンでカスタム設定を扱うコンポーネントでも同様の利便性が提供されることが期待されます。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
b130f4db

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景(Context)、技術的な変更(Technical Detail)、まとめ(Conclusion)がすべて揃っており、3部構成が明確です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

PRリンクは「PR #2534」の形式で、期待される「[#2534]」形式と異なります。また、Issue #2444 がテキストで記載されているだけでリンク化されていません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

内容はエンジニア向けに適切で、初心者向けの過度な説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論→各論→結論の流れが保たれ、段落はトピックセンテンスで始まり、一段落一トピック、長さも適切です。

Diff内容との照合 ⚠ WARNING

コードブロックとDiff内容の一致

記事のコードブロックは実装本体はDiffと一致していますが、コメントヘッダー、`export default deepClone`、補助関数 `isPlainObject` が抜けており、Diff全体を完全に再現していません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

deepClone、structuredClone、DataCloneError、Chart.js などの用語は正しく使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明は PR の目的(DataCloneError の解消)と一致し、因果関係も論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記述された事実はすべて PR のタイトル、説明、および Diff で裏付けられています。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #2534 と Issue番号 #2444 が正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR タイトルと完全に一致しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

バージョンや LTS、リリース日程等の外部知識は一切記載されていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PR の記述と整合しています。