Salesforce Lightning Experience のための初めての Lightning Web Component (LWC) 構築ガイド

Salesforce 開発者の視点から、この記事を作成します。


背景と応用シナリオ

Salesforce Classic から Lightning Experience への移行は、単なる UI の刷新ではありません。これは、Salesforce プラットフォーム上でのアプリケーション開発とユーザーエクスペリエンスのあり方を根本的に変えるパラダイムシフトです。Lightning Experience は、コンポーネントベースの柔軟なアーキテクチャを採用しており、標準機能だけでは満たせない複雑なビジネス要件に対応するための強力なカスタマイズ能力を提供します。

このようなカスタマイズの中核をなすのが、Lightning Web Components (LWC) (ライトニングウェブコンポーネント) です。LWC は、HTML、最新の JavaScript (ECMAScript)、CSS といったウェブ標準技術を直接活用して、Salesforce 上で動作する高パフォーマンスで再利用可能な UI コンポーネントを構築するためのプログラミングモデルです。以前の Aura Components (オーラコンポーネント) モデルと比較して、LWC はブラウザでネイティブに実行される部分が多いため、軽量で高速な動作を実現します。

応用シナリオ

LWC の応用範囲は非常に広いです。以下にいくつかの具体的なシナリオを挙げます。

  • カスタムデータ表示: 標準の関連リストでは表現できない、複数のオブジェクトにまたがる情報を集約し、インタラクティブなグラフや表形式で表示するコンポーネント。
  • 複雑な入力フォーム: 複数のステップに分かれたウィザード形式の入力フォームや、入力値に応じて動的に項目が変化する条件付きフォームを作成。
  • 外部システム連携: 外部 API と連携し、Salesforce のデータと外部システムのデータをマッシュアップして表示・操作する画面を構築。
  • プロセスの自動化: 複雑なビジネスプロセスをガイドするカスタムコンポーネントを作成し、ユーザーの作業を簡素化・効率化。

この記事では、Salesforce 開発者として、Lightning Experience のページに配置可能な、取引先データを表示するシンプルな LWC を作成するプロセスを、具体的なコード例を交えながら解説します。

原理説明

LWC の開発を理解するためには、その基本的な構成要素と動作原理を把握することが重要です。LWC は、関連するファイルの集合体である「コンポーネントバンドル」として構成されます。

コンポーネントバンドルの構成要素

主要なファイルは以下の通りです。

  • HTML (template): componentName.html という形式のファイルで、コンポーネントの構造を定義します。HTML 標準のタグに加え、lightning-cardlightning-datatable のような Salesforce が提供する「基本コンポーネント (Base Components)」を使用できます。
  • JavaScript (controller): componentName.js というファイルで、コンポーネントのロジックを記述します。プロパティの定義、イベントの処理、サーバーサイドの Apex (エイペックス) メソッドの呼び出しなど、コンポーネントの動作を制御します。
  • XML (metadata): componentName.js-meta.xml というファイルで、コンポーネントのメタデータを定義します。ここで、コンポーネントをアプリケーションページやレコードページなど、どこに配置可能にするか (ターゲット) や、外部に公開するかどうか (isExposed) を設定します。
  • CSS (styling): componentName.css というファイルで、コンポーネント固有のスタイルを定義します。LWC の CSS はスコープが設定されており、そのコンポーネント内にのみ適用されるため、他のコンポーネントのスタイルに影響を与えません。

データ連携の仕組み: @wire

LWC が Salesforce のデータを扱う上で中心的な役割を果たすのが、@wire デコレータです。@wire は、Apex メソッドや Lightning Data Service からデータをリアクティブに取得するための仕組みです。

「リアクティブ」とは、データの供給源 (例: Apex メソッド) が新しいデータを返すと、@wire で紐付けられたプロパティが自動的に更新され、そのプロパティを使用しているコンポーネントの HTML テンプレートも再レンダリングされることを意味します。これにより、開発者はデータが変更された際の UI 更新ロジックを明示的に記述する必要がなくなり、コードが大幅に簡潔になります。@wire は、データの取得結果を data プロパティと error プロパティを持つオブジェクトとして返します。

今回のサンプルでは、この @wire デコレータを使って Apex クラスのメソッドを呼び出し、取得した取引先リストを画面に表示します。

示例代码

ここでは、年間売上が上位 10 件の取引先を取得し、リスト表示する LWC を作成します。まず、サーバーサイドでデータを取得する Apex クラスを作成し、次に LWC コンポーネントバンドルを作成します。

1. Apex コントローラ (AccountController.cls)

最初に、Salesforce のデータベースから取引先データを取得するための Apex クラスを作成します。LWC から呼び出されるメソッドには @AuraEnabled(cacheable=true) アノテーションを付与する必要があります。cacheable=true を指定することで、メソッドはデータを参照するだけで DML 操作を行わないことを示し、クライアントサイドで結果をキャッシュできるようになります。これによりパフォーマンスが向上します。

// AccountController.cls
public with sharing class AccountController {
    /**
     * @description 年間売上 (AnnualRevenue) の降順で上位 10 件の取引先を取得します。
     *              LWC から呼び出すために @AuraEnabled(cacheable=true) アノテーションが必要です。
     * @return 取引先のリスト
     */
    @AuraEnabled(cacheable=true)
    public static List<Account> getTopAccounts() {
        // SOQL クエリを実行して、指定した項目を持つ取引先を取得します。
        // WITH SECURITY_ENFORCED を使用して、項目レベルおよびオブジェクトレベルのセキュリティを適用します。
        return [
            SELECT Id, Name, AnnualRevenue, Industry
            FROM Account
            WITH SECURITY_ENFORCED
            ORDER BY AnnualRevenue DESC NULLS LAST
            LIMIT 10
        ];
    }
}

2. LWC コンポーネントバンドル (topAccounts)

次に、取得したデータを表示するための LWC を作成します。VS Code と Salesforce Extension Pack を使用して LWC バンドルを作成するのが一般的です。

topAccounts.html

コンポーネントの UI 構造を定義します。lightning-card でコンポーネント全体を囲み、タイトルを設定します。template:if:true ディレクティブを使用して、データ (accounts.data) が存在する場合にのみリストを表示し、エラー (accounts.error) が発生した場合はエラーメッセージを表示します。

<!-- topAccounts.html -->
<template>
    <!-- lightning-card は、コンテンツを囲むためのコンテナです -->
    <lightning-card title="Top 10 Accounts by Annual Revenue" icon-name="standard:account">
        <div class="slds-m-around_medium">
            <!-- @wire の結果が data プロパティにセットされていれば、このブロックが表示される -->
            <template if:true={accounts.data}>
                <!-- for:each ディレクティブでリストをループ処理 -->
                <template for:each={accounts.data} for:item="account">
                    <!-- 各取引先の名前と年間売上を表示 -->
                    <p key={account.Id} class="slds-p-bottom_small">
                        <b>{account.Name}</b> - Annual Revenue: {account.AnnualRevenue}
                    </p>
                </template>
            </template>

            <!-- @wire の結果が error プロパティにセットされていれば、このブロックが表示される -->
            <template if:true={accounts.error}>
                <p>Error loading accounts. Please contact your administrator.</p>
            </template>
        </div>
    </lightning-card>
</template>
topAccounts.js

コンポーネントのロジックを記述します。lwc モジュールから LightningElementwire をインポートし、作成した Apex メソッド (getTopAccounts) もインポートします。@wire デコレータを使用して Apex メソッドを呼び出し、その結果を accounts プロパティに格納します。

// topAccounts.js
import { LightningElement, wire } from 'lwc';
// Apex クラスの getTopAccounts メソッドをインポート
import getTopAccounts from '@salesforce/apex/AccountController.getTopAccounts';

export default class TopAccounts extends LightningElement {
    /**
     * @wire デコレータを使用して Apex メソッドを呼び出します。
     * getTopAccounts メソッドがデータを返すと、その結果が accounts プロパティに
     * { data, error } という形式のオブジェクトとして格納されます。
     * このプロセスはリアクティブであり、データが変更されると自動的に更新されます。
     */
    @wire(getTopAccounts)
    accounts;
}
topAccounts.js-meta.xml

このコンポーネントを Lightning Experience のどこで利用可能にするかを定義します。isExposedtrue に設定し、targets タグ内で配置したいページ種別 (ホームページ、レコードページなど) を指定します。

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <!-- このコンポーネントを App Builder で利用可能にする -->
    <isExposed>true</isExposed>
    <!-- 配置可能なページ種別を定義 -->
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

注意事項

LWC を開発・運用する際には、いくつかの重要な点に注意する必要があります。

権限とセキュリティ

・Apex クラスのアクセス権: LWC から呼び出される Apex クラスには、コンポーネントを使用するユーザーのプロファイルまたは権限セットからアクセス権が付与されている必要があります。
・オブジェクトと項目のアクセス権 (FLS): Apex クラス内で with sharing キーワードを使用することで、組織の共有設定が適用されます。さらに、SOQL (Salesforce Object Query Language) クエリに WITH SECURITY_ENFORCED 句を追加することで、実行ユーザーの項目レベルセキュリティ (FLS) とオブジェクト権限が自動的に適用されます。これを怠ると、ユーザーが本来アクセスできないはずのデータをコンポーネントが表示してしまう脆弱性につながる可能性があります。

API 制限

・ガバナ制限: LWC のバックエンドで動作する Apex コードは、Salesforce のガバナ制限に従います。1 トランザクションあたりの SOQL クエリ発行回数 (100 回)、DML ステートメント実行回数 (150 回)、CPU 時間 (10,000 ミリ秒) などの制限に注意が必要です。特に、ループ内で SOQL や DML を実行しないように設計することが重要です。

エラー処理

@wire サービスは、成功時には data プロパティに、失敗時には error プロパティに値を設定します。サンプルコードのように、HTML テンプレート内で accounts.error の存在をチェックし、エラーが発生した際にはユーザーフレンドリーなメッセージを表示することが推奨されます。コンソールにエラーオブジェクトを出力してデバッグすることも有効ですが、本番環境ではユーザーに技術的な詳細を見せるべきではありません。

まとめとベストプラクティス

Lightning Web Components (LWC) は、Lightning Experience のカスタマイズにおいて、現代的で強力なフレームワークです。ウェブ標準に準拠しているため学習コストが比較的低く、優れたパフォーマンスと再利用性を提供します。今回作成した取引先リスト表示コンポーネントは、LWC の基本的なデータ取得と表示のパターンを示す良い出発点です。

以下に、LWC 開発におけるベストプラクティスをいくつか挙げます。

  1. コンポーネントの粒度を小さく保つ: 1 つのコンポーネントに多くの機能を詰め込むのではなく、特定の役割を持つ小さなコンポーネントを複数作成し、それらを組み合わせることで、再利用性とメンテナンス性が向上します。
  2. 基本コンポーネントを最大限に活用する: Salesforce が提供する lightning-button, lightning-input, lightning-datatable などの基本コンポーネントを積極的に利用することで、開発時間を短縮し、Salesforce のデザインシステム (SLDS) に準拠した UI を簡単に構築できます。
  3. Apex でのビジネスロジック集約: LWC の JavaScript は主に UI の制御とユーザーインタラクションの処理に集中させ、複雑なデータ処理やビジネスロジックは Apex 側に集約します。これにより、コードの関心事が明確に分離されます。
  4. セキュリティを常に意識する: 前述の通り、Apex での WITH SECURITY_ENFORCED の使用や、CRUD/FLS の適切なチェックは必須です。クライアントサイドでの入力値検証も怠らないようにしましょう。
  5. Salesforce DX を活用する: Salesforce DX (Salesforce Developer Experience) は、ソースコード駆動開発、バージョン管理、継続的インテグレーション (CI) をサポートする最新の開発手法です。LWC 開発には、VS Code と Salesforce Extension Pack を中心とした Salesforce DX のツールチェーンを利用することが強く推奨されます。

LWC をマスターすることで、Salesforce 開発者としての価値を大きく高め、ユーザーの期待を超える高度なソリューションを Lightning Experience 上で実現できるようになります。

コメント