experience-lds-best-practices-apply について
Lightning Web Component のデータ操作を Lightning Data Service のベストプラクティスに沿って確認・実装するスキルです。UI API、キャッシュ整合性、スキーマ参照を中心に、チェックリストと修正手順を提供します。
主な機能
- 01LDS データ層の準拠状況を確認
- 02CRUD には LDS/UI API を優先
- 03ハードコード名をスキーマインポートに置換
- 04変更後にキャッシュデータを更新
- 05Apex と LDS の選択をガイド
活用シーン
- 01独自フォームや Apex 利用のレビュー
- 02標準・カスタムオブジェクトの CRUD 実装
- 03レコード変更後の古い表示を修正
- 04項目やオブジェクトのスキーマをインポート
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill experience-lds-best-practices-applyインストール後、Claude Code で/experience-lds-best-practices-applyを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/adapter-apis.mdlds-data-consistency.mdlds-expert.mdlds-referential-integrity.mdwire-adapter-types.md詳細
LDS のベストプラクティスの適用
Lightning Web Component に Lightning Data Service のガイドラインを適用します。3 つの柱は、データの一貫性、参照整合性、UI API と Apex の使い分けです。ここでは UI API の経路に焦点を当てます。GraphQL と上流のデータ要件分析は別途扱います。
使用する場面
- コンポーネントのデータレイヤーが LDS に準拠しているかをレビューする場合(独自実装のフォーム、文字列ベースのフィールド名、同期されていない Apex と LDS、Apex の過剰な使用)。
- 標準オブジェクトまたはカスタムオブジェクトに対する CRUD を実装する場合。
getRecord、getRecords、createRecord、updateRecord、deleteRecord、基本レコードフォームコンポーネント、Apex のどれを使用するか判断する場合。- レコードの変更後に発生する古いデータの不具合を修正する場合。
- ハードコードされたフィールド名やオブジェクト名を置き換えるために、スキーマインポート(
@salesforce/schema/...)を追加する場合。
次の場合は、このスキルを使用しないでください。
- GraphQL のクエリ/ミューテーションの生成 — 現時点では別途扱います。
- 上流のデータ要件の把握 — 現時点では別途扱います。
- SLDS クラスやデザイントークンの作業(
design-systems-slds-applyを使用してください)。 - アクセシビリティ、セキュリティ、RTL のレビュー — これらは個別のツールを使って別々に実施します。
前提条件
- コンポーネントのパス。
- コンポーネントのデータ操作(読み取り/書き込み/両方)と、Apex がすでに関係しているかどうかの把握。
@salesforce/schemaインポートに必要な組織のスキーマへのアクセス(Setup → Object Manager →<Object>→ Details → API Name、または、読み取りに GraphQL を使用する場合は、対象の組織から取得した SDL)。
ナレッジベース
- references/lds-expert.md — LDS に関する信頼できる知識(パターン、アダプター、キャッシュ、ミューテーションフロー)。
- references/lds-data-consistency.md — キャッシュの無効化、
refreshApex、notifyRecordUpdateAvailable、wire の結果の伝播。 - references/lds-referential-integrity.md —
@salesforce/schemaインポート、フィールド定数、オブジェクト名の解決、リファクタリング時の伝播。
アダプターごとの API リファレンス — references/adapter-apis.md には、各 UI API アダプターの構文/パラメーター/戻り値/使用方法が、ファミリー(uiRecordApis、uiListsApis、uiRelatedListApis、uiObjectInfoApis)ごとに記載されています。各アダプターは # `<name>` ブロックです。バッククォートで囲まれた名前(例:# `getRecord`)を grep すると、該当項目に移動できます。アダプターを wire する前にこれを読み、記憶を頼りに言い換えないでください。
型カタログ — references/wire-adapter-types.md には、アダプターが返すすべての型(Record、ObjectInfo、FieldValue など)がカテゴリごとにまとめられ、従来の MCP ツールと同じフォーマッターで表示されています。## <TypeName> を grep すると、特定の項目に移動できます。
コードを編集する前に、該当するリファレンスを読んでください。
基本原則
- 標準オブジェクトとカスタムオブジェクトの CRUD には、LDS/UI API を優先してください。Apex は、ビジネスロジックや一括操作が LDS の機能を超える場合にのみ使用してください。
- ミューテーションの後は必ず、
refreshApex(wiredResult)またはnotifyRecordUpdateAvailable([{ recordId }])を使って、表示されるデータを最新に保ってください。 - オブジェクトとフィールドの参照は、文字列リテラルではなく
@salesforce/schemaからインポートしてください。これにより、メタデータの名前変更からコンポーネントを保護できます。 - 単一レコードの UI には、基本レコードフォームコンポーネント(
lightning-record-form、lightning-record-edit-form、lightning-record-view-form)を優先してください。これらには、検証、SLDS スタイリング、アクセシビリティ、フィールドレベルセキュリティが組み込まれています。
レビューチェックリスト
各項目に はい/いいえ で回答してください。はいが 1 つでもあれば、リファクタリングが必要です。
1. 基本コンポーネントを使わずにフォームを独自実装している
lightning-record-form、lightning-record-edit-form、lightning-record-view-formで十分な単一レコードの CRUD に、コンポーネントがカスタムフォームを実装していますか?- 基本レコードフォームコンポーネントが標準で提供する検証ロジックを重複して実装していますか?
- 基本コンポーネントに組み込まれたスタイルを活用せず、標準の SLDS スタイルを手動で再現していますか?
2. 参照をインポートしていない
- オブジェクトまたは項目の API 名が、ハードコードされた文字列として参照されていますか?
- テンプレートで、スキーマのインポートなしに、
record.data.fields.Name.valueのような式を使って項目値に直接アクセスしていますか? - Salesforce の項目を扱っているにもかかわらず、JS ファイルに
@salesforce/schemaのインポートがありませんか?
3. Apex と LDS の併用時に同期していない
- コンポーネントが LDS 経由で読み取り、Apex 経由で同じレコードを変更しているにもかかわらず、その後にキャッシュを更新していませんか?
- Apex 経由で取得する一方、更新後に同期せず、表示には LDS キャッシュを使用していますか?
- 明示的な更新戦略がないまま、複数のデータソースが同じオブジェクトにアクセスしていますか?
4. Apex の過剰使用
getRecord、updateRecord、または基本的なレコードフォームで処理できる単一レコードの取得または更新だけを目的に、コンポーネントが Apex を呼び出していますか?- 標準の LDS ワイヤーアダプターで取得できる項目を含む単純な SOQL クエリの実行に、Apex を使用していますか?
- コード内に LDS/UIAPI の呼び出しが見当たらない一方で、基本的な CRUD 処理用のカスタム Apex メソッドが存在しますか?
ワークフロー
ステップ 1 — データレイヤーを一覧にする
コンポーネント内のすべてのデータ操作を列挙します。
- ワイヤーアダプター(
@wire(getRecord, …)、@wire(getRecords, …)、@wire(someApexMethod, …))。 - 命令型呼び出し(
updateRecord、createRecord、deleteRecord、Apex の命令型呼び出し)。 - 読み取りと書き込み、対象のオブジェクト、項目、および書き込み後の更新処理がワイヤー経由かどうか。
ステップ 2 — 4 つのセクションのチェックリストを実施する
§1〜§4 を順に確認します。各セクションがレビュー対象のコンポーネントに該当するかを判断し、その結果をレポートに記録します。以下の形式を使用してください。各セクションは、## LDS Best Practices の下に問題(違反)として記載するか、## Sections checked (no issue) の下に準拠項目として記載するかのいずれかで、必ず一度だけ記載します。最後に、件数を記した ## Summary 行と、1 段落の説明を記載します。
レポート形式:
## LDS Best Practices
- §<N> <section title> — <file>:<lines>
Issue: <what is wrong, specifically citing the pattern in the code>
Fix: <the corrective change, naming the exact import / API to use>
Applied: <yes | no>
## Sections checked (no issue)
- §<N> <section title> — <file>:<lines>
Status: Compliant (no action).
Evidence: <what in the code makes this section compliant — cite lines, imports, and the base component or schema token being used>
## Summary
- <X> issue(s) found; <Y> fixed; <Z> deferred.
- <one-paragraph narrative of the review — what the component does, why the flagged issues matter, and why the compliant sections are compliant.>
このレポートの作成ルール:
- §1〜§4 はすべて、2 つのブロックのいずれか一方に必ず一度だけ記載します。準拠しているセクションも省略せず、
## Sections checked (no issue)の下に根拠とともに記録してください。 ## LDS Best Practicesの下には、実際の違反のみを記載します。違反がない場合は、最初の行に "No best-practice issues found." と記載し、その後、すべてのセクションを準拠ブロックに移します。- レビュー対象のコンポーネントについて、具体的なファイルパスと行範囲を示してください。一般的な参照を使用しないでください。
- §1〜§4 以外のセクションを追加しないでください。後続の a11y/RTL/セキュリティレビューは別のワークフローとして実施され、それぞれ専用のレポートがあります。
ステップ 3 — 参照整合性に関する修正を適用する
ハードコードされた API 名すべてに対して:
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
オブジェクトまたは項目を参照するすべての箇所で、これらの定数を使用してください。ワイヤー設定、@wire の項目配列、getFieldValue(record, NAME_FIELD) の呼び出し、基本コンポーネントの object-api-name/fields 属性が対象です。
詳細なルール:references/lds-referential-integrity.md。
ステップ 4 — データ整合性に関する修正を適用する
- LDS の命令型の変更(
updateRecord、createRecord、deleteRecord)の後に、更新処理を実行します。import { updateRecord, getRecord } from 'lightning/uiRecordApi'; import { refreshApex } from '@salesforce/apex'; async handleSave() { await updateRecord({ fields: { Id: this.recordId, Name: this.name } }); await refreshApex(this.wiredRecord); } - キャッシュに保持されているレコードを Apex で変更した後は、次を優先します。
import { notifyRecordUpdateAvailable } from 'lightning/uiRecordApi'; await notifyRecordUpdateAvailable([{ recordId: this.recordId }]); - ワイヤーの結果への参照を保持します(
this.wiredRecord = result; return result.data;)。これにより、refreshApexでその結果を更新できます。 - 基本フォームコンポーネントは自動で更新されるため、手動での更新は不要です。
詳細なルール:references/lds-data-consistency.md。
ステップ 5 — 該当する場合は Apex を UIAPI に置き換える
- 単一レコードの読み取り →
getRecord(fieldsとスキーマのインポートを使用)。 - 単一レコードの更新 →
updateRecordまたはlightning-record-edit-form。 - 単一レコードの作成 →
createRecordまたはmode="edit"を指定したlightning-record-form。 - 関連レコードの読み取り →
getRelatedListRecords。 - 選択リストの値 →
getPicklistValues。 - オブジェクトのメタデータ →
getObjectInfo/getObjectInfos。
アダプターの形式が不明な場合は、references/adapter-apis.md でバッククォート付きのアダプター名(例:# `getRecord`)を検索してください。正確なパラメーター、戻り値、使用方法が記載されています。@salesforce/schema/<Object>.<Field> のパスについては、設定 → オブジェクトマネージャー → <Object> → 詳細 → API 名で、正確な API 名を確認してください。見慣れない戻り値の型については、references/wire-adapter-types.md で型名を検索してください。
ステップ 6 — 検証
- コンポーネントファイルにハードコードされた API 名が残っていないこと。
- すべての書き込み処理に対応する更新処理があること(または基本フォームコンポーネントを使用していること)。
- Apex と UIAPI の両方を介して同じレコードを重複して読み取っていないこと。
- 既存の Jest テストが成功すること。更新処理ごとに
refreshApexが正確に 1 回呼び出されることを確認する更新フローのテストを追加してください。
相互参照
- 関連スキル:
experience-lwc-generate— レビューの結果、コンポーネントを修正するのではなく再生成する必要がある場合。design-systems-slds-apply— LDS レビューで明らかになった SLDS クラス/デザイントークンの整理に使用します。
- 隣接する作業(現時点では範囲外):
- GraphQL クエリ/ミューテーションの作成、上流のデータ要件分析、セキュリティ/RTL/アクセシビリティのレビューは、それぞれ専用のツールを使う別個のワークフローとして実施します。
例
基本コンポーネントを優先
<template>
<lightning-record-form
record-id={recordId}
object-api-name="Account"
fields={fields}
mode="edit"
onsuccess={handleSuccess}>
</lightning-record-form>
</template>
import { LightningElement, api } from 'lwc';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
export default class AccountEditor extends LightningElement {
@api recordId;
fields = [NAME_FIELD, INDUSTRY_FIELD];
handleSuccess() {
this.dispatchEvent(new CustomEvent('saved'));
}
}
更新処理後に更新
import { LightningElement, api, wire } from 'lwc';
import { getRecord, updateRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '@salesforce/apex';
import ACCOUNT_NAME from '@salesforce/schema/Account.Name';
export default class RenameAccount extends LightningElement {
@api recordId;
wiredRecord;
@wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME] })
wired(result) {
this.wiredRecord = result;
}
async handleRename(event) {
await updateRecord({ fields: { Id: this.recordId, Name: event.detail } });
await refreshApex(this.wiredRecord);
}
}
検証
@salesforce/schema/のインポートを検索し、コンポーネントが参照するすべてのフィールド/オブジェクトが網羅されていることを確認します。- API 名に見える文字列リテラル(
'Account'、'Name'など)を検索し、wire 設定やフィールド配列に含まれていないことを確認します。 - すべての更新呼び出しを対応する更新呼び出しまで追跡します(
refreshApex、notifyRecordUpdateAvailable、または内部で処理する基本フォームのいずれか)。 - Apex の使用が UIAPI では要件を満たせない場合(一括処理、複雑な結合、カスタムロジック)に限られていることを確認します。