Lightning Message Serviceの使い方(LWC/Aura/VF)

LWC/Aura/VFそれぞれでLightning Message Serviceを使ってみました。
簡単なメッセージのpublish/subscribeの仕方をまとめます。

参考文献はこちら

・[LightningMessageChannel](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningmessagechannel.htm)
・[Create a Message Channel](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/use_message_channel_intro)
・[Message Service](https://developer.salesforce.com/docs/component-library/bundle/lightning-message-service/documentation)
・[Communicating Across the DOM with Lightning Message Service](https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/message_channel_intro.htm)
・[Message Channel](https://developer.salesforce.com/docs/component-library/bundle/lightning:messageChannel/documentation)
・[Lightning Message Service を使用した DOM 間の通信](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/message_channel_intro.htm)

あとは[Trailhead Sample Gallary](https://trailhead.salesforce.com/sample-gallery)のLWC Recipesです。
以下のリポジトリにサンプルコードがあります。

https://github.com/trailheadapps/lwc-recipes

##Message Channelのデプロイ
LMSを使用するには組織にMessageChannelメタデータをデプロイする必要があります。
以下の手順でデプロイしました。

1. プロジェクトの`force-app/main/default`配下に`messageChannels`フォルダを作成
2. `messageChannels`配下にmessageChannelName.messageChannel-meta.xmlファイルを作成
3. ファイルの内容を[メタデータAPIガイド](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningmessagechannel.htm)を参照して設定<br/>
サンプルだと以下のような感じ。lightningMessageFieldにペイロードとして渡す項目を定義します。
4. デプロイして完了

```XML
<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
    <masterLabel>sampleMessageChannel</masterLabel>
    <isExposed>true</isExposed>
    <description>This is a sample Lightning Message Channel.</description>
    <lightningMessageFields>
        <fieldName>recordId</fieldName>
        <description>This is the record Id that changed</description>
    </lightningMessageFields>
    <lightningMessageFields>
        <fieldName>stringData</fieldName>
        <description>string data for publish.</description>
    </lightningMessageFields>
</LightningMessageChannel>
```

##LWCでのLMSの使用
LWCでLMSを使用するには`lightning/messageService`からpublishなどのモジュールをインポートする必要があります。
また、デプロイしたmessageChannelを`'@salesforce/messageChannel/sampleMessageChannel__c'`の形でインポートする必要があります。
messagechannelを指定するときは__cを使用するようです。

```javascript:import
import { publish, subscribe, MessageContext } from "lightning/messageService";
import SAMPLEMESSAGECHANNEL from "@salesforce/messageChannel/sampleMessageChannel__c";
```

###LWCでのpublish
インポートしたpublishモジュールを使用してpublishします。
wireで取得したmessageContextとインポートしたmessageChannel、ペイロードが必要になります。
詳しくは[ガイド](https://developer.salesforce.com/docs/component-library/bundle/lightning-message-service/documentation)に載ってますのでそちらをご参照ください。

以下、publishの例

```Javascript:publish
const payload = { stringData: "Lightning Message from LWC" };
publish(this.messageContext, SAMPLEMESSAGECHANNEL, payload);
```

###LWCでのsubscribe
インポートしたsubscribeモジュールを使用してsubscribeします。
サンプルコードなどでは`connectedCallback()`内でsubscribe関数を使用しているようです。
subscribe関数にはmessageContext、messageChannel、subscribeしたときに実行する関数などが必要になります。

```Javascript:subscribe
  connectedCallback() {
    this.subscription = subscribe(
      this.messageContext,
      SAMPLEMESSAGECHANNEL,
      (message) => this.handleMessage(message)
    );
  }

  handleMessage(message) {
    this.message = message.stringData;
  }
```

##AuraコンポーネントでのLMSの使用
AuraコンポーネントでLMSを使用するには`lightning:messageChannel`をコンポーネントに記載します。
後述しますがこのコンポーネントとonMessageを設定するだけでsubscribeされるようになるのでLWCより使いやすい印象です。

```HTML
  <lightning:messageChannel
    type="sampleMessageChannel__c"
    onMessage="{!c.handleMessage}"
    aura:id="messageChannel"
  />
```

###Auraでのpublish
publishするにはコンポーネント側で記載した`lightning:messageChannel`のpublishメソッドを使用します。
publishメソッドにはpayloadのみ指定すればOKです。
findで探してくる必要があるため`aura:id`の指定が必須となります。

```Javascript:publish
    var payload = { stringData: "Lightning Message from Aura" };
    component.find("messageChannel").publish(payload);
```

###Auraでのsubscribe
subscribeするにはコンポーネント側で`lightning:messageChannel`を記載し、`onMessage`イベントに対してハンドラメソッドを指定します。
ハンドラメソッドにはcomponentとmessageを引数として受け取ることができ、`messsage.getParam('fieldName')`の形でペイロードの中身を取得することができます。

```HTML:subscribe
  <aura:attribute name="message" type="String" />
  <lightning:messageChannel
    type="sampleMessageChannel__c"
    onMessage="{!c.handleMessage}"
    aura:id="messageChannel"
  />
```

```Javascript:subscribe
  handleMessage: function (component, message) {
    component.set("v.message", message.getParam("stringData"));
  }
```

##VFでのLMSの使用
VFページでLMSを使用するにはjavascript内で`$MessageChannel`変数を使用してmessageChannelを取得します。
また、sforce.oneオブジェクトを使用して上記で使用した変数と合わせてpublish/subscribeを行います。
(今回はVFコンポーネントとしてアプリケーションページに配置します)。

```HTML
<script>
    var SAMPLEMESSAGECHANNEL = "{!$MessageChannel.sampleMessageChannel__c}";
</script>
```

###VFでのpublish
Javascript内で`sforce.one.publish`を使用します。
取得したmessageChannelとペイロードを指定します。

```HTML:publish
<script>
    var payload = { stringData: "Lightning Message from VF" };
    sforce.one.publish(SAMPLEMESSAGECHANNEL, payload);
</script>
```

###VFでのsubscribe
subscribeするには`sforce.one.subscribe`を使用します。
取得したmessageChannelとメッセージ受信時のハンドラメソッドを指定する必要があります。

```HTML:subscribe
<script>
    window.onload = function () {
        sforce.one.subscribe(SAMPLEMESSAGECHANNEL, handleMessage);
    }

    function handleMessage(message) {
        document.getElementById("message").innerHTML = "Message: " + message.stringData;
    }
</script>
```


## 最後に
Visualforceとも通信できるのはかなり便利ですね。
使い方をぜひとも覚えておきたいです。