Svelte で Zoom Meeting SDK を触ってみた。

## [前置き]この記事について
この記事は Zoom が協賛する、Qiita Engineer Festa 2022 「Zoom API/SDKを使ってみよう！」の参加記事です。
イベントについての詳細は以下のページをご覧ください。

https://qiita.com/official-events/86d8555146e1b14fef24

## 本題
Qiitaをぺらぺらとみていたときに出てきたこの企画。
なんだか面白そうだなぁと思ったのでせっかくなら英語で調べても出てこなかったSvelteを使った実装方法を書いてみたいと思う。
少し難しい点等もあるのでそこに注意しながら書いていく。

## 先にお詫び
Zoom Meeting SDKは、Client ViewとComponent Viewの二種類があり、用途によって使い分けられる。
ただ、今回はClient Viewで実装した場合エラーが発生し実装が困難なため、Component Viewで実装する。(ライブラリ側だったがSvelte特有の実行タイミングの問題っぽいのでもう少し頑張ればエラーは解消できるかも)

## 完成物
こうなる。
参加者一覧にも表示されるのでしっかりと参加できていることがわかる

![スクリーンショット 2022-06-25 16.27.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643158/7ec1f5f9-3cab-c94a-d22e-777e371d1dbb.png)
(ぬいぐるみかわいい...)

## 参考
今回はほとんど以下のサンプルを参考にした。
他のライブラリ等使われる場合は是非こちらを参考にして欲しい。

https://github.com/zoom/meetingsdk-javascript-sample

## Svelteとは
そもそもSvelteとは。
重要な点を挙げると、

1. UIライブラリではなくコンパイラ。
2. バンドルサイズが小さくとても軽い
3. 個人的にVueやReactよりもJavaScriptが書きやすい。(ネイティブなJavaScriptに近い。)

## Zoom Meeting SDKとは
> MeetingSDKではZoomクライアントで行うミーティング、ウェビナーで利用されるUI/UXをそのままにパッケージした内容となっています。そのため、MeetingSDKでも同じミーティング番号、ウェビナー番号を利用して参加接続できます。
MeetingSDKでは映像音声通話を個別に設計することなくZoomのUI/UXを元に短時間で組み込んでいただけるメリットがあります。
>Zoomの記事より引用 https://qiita.com/yosuke-sawamura/items/de69e73e47335cd61d68

## 作り方
事前に以下の記事を参考にSDK KEY等を取得してください。

https://qiita.com/yosuke-sawamura/items/de69e73e47335cd61d68

### インストール周り
まずSvelteのインストールをします。
```shell
npm init vite my-app -- --template svelte
cd my-app
npm install
npm run dev
```

次にZoom Meeting SDKを使うために今回はzoomが提供しているパッケージを使用します。

```shell
npm install @zoomus/websdk --save
```

最後に署名のためのサーバーを立てます。
[zoom/meetingsdk-sample-signature-node.js](https://github.com/zoom/meetingsdk-sample-signature-node.js)を使用します。

```shell
git clone https://github.com/zoom/meetingsdk-sample-signature-node.js.git
cd meetingsdk-sample-signature-node.js
npm install
```
そして`.env`ファイルに以下の内容を記述します。
```env
ZOOM_SDK_KEY=SDK_KEY_HERE
ZOOM_SDK_SECRET=SDK_SECRET_HERE
```

サーバーを起動する際は`npm run start`で起動します。
署名用サーバーの準備は以上です。

## svelte書いてくよ
my-appに戻り実際にApp.svelteを編集していきます。

まずコードをご覧ください。
```js
<script>
  import ZoomMtgEmbedded from "@zoomus/websdk/embedded"
  import { onMount } from 'svelte';

  const signatureEndpoint = 'http://localhost:4000';
  const sdkKey = "yourkey"
  const role = 0;
  let meetingNumber;
  let password;
  let userName;
  let registrantToken = ''


  const client = ZoomMtgEmbedded.createClient();

  onMount(() => {
    let meetingSDKElement = document.getElementById('meetingSDKElement');

    client.init({
        zoomAppRoot: meetingSDKElement,
        language: 'jp-JP',
    })
  });

  function startMeeting(signature) {
    client.join({
      sdkKey: sdkKey,
      signature: signature,
      meetingNumber: meetingNumber,
      password: password,
      userName: userName,
      tk: registrantToken
    })
	}

  function getSignature() {
    fetch(signatureEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        meetingNumber: meetingNumber,
        role: role
      })
    }).then((response) => {
      return response.json()
    }).then((data) => {
      console.log(data)
      startMeeting(data.signature)
    }).catch((error) => {
      console.log(error)
    })
  }
</script>

<section>
	<label for="meetingNumber">ミーティングID</label>
	<input 
		type="text"
		id="meetingNumber"
		bind:value={meetingNumber}
	>
	<label for="password">ミーティングパスワード</label>
	<input
		type="text"
		id="password"
		bind:value={password}
	>
	<label for="userName">名前</label>
	<input
		type="text"
		id="userName"
		bind:value={userName}
	>

	<button on:click={getSignature}>
		join
	</button>
  <!-- For Component View -->
  <div id="meetingSDKElement">
    <!-- Zoom Meeting SDK Rendered Here -->
  </div>
</section>
```

### 解説
```js
import ZoomMtgEmbedded from "@zoomus/websdk/embedded"
import { onMount } from 'svelte';
```
パッケージを読み込みます。
今回の最大のポイントは onMountをインポートすること。
後述の`document.getElementById`をするときに必要になります。

```js
const signatureEndpoint = 'http://localhost:4000';
const sdkKey = "yourkey"
const role = 0;
let meetingNumber;
let password;
let userName;
let registrantToken = ''
```
各種変数を設定します。
signatureEndpointに関しては先ほどの署名のサーバーを作った際に何も設定を変更していなければそのままでいけるはずです。が、サーバー起動時にコンソールに表示される表示に従って実装するようにしてください。
また、sdkKeyについては先ほど取得したものを書いてください。今回はローカルでの実装用なのでそのまま書いていますが、公開する際は環境変数からを読み込むようしてください。

```js
const client = ZoomMtgEmbedded.createClient();

onMount(() => {
  let meetingSDKElement = document.getElementById('meetingSDKElement');

  client.init({
      zoomAppRoot: meetingSDKElement,
      language: 'jp-JP',
  })
});
```
接続するためのおまじないを書いていきます。
ここで重要なのが先ほど書いた通り`document.getElementById()`を`onMount`に書くこと。
そうでなければ要素が取得できずエラーになります。

少し飛ばして....
```js
function getSignature() {
  fetch(signatureEndpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      meetingNumber: meetingNumber,
      role: role
    })
  }).then((response) => {
    return response.json()
  }).then((data) => {
    console.log(data)
    startMeeting(data.signature)
  }).catch((error) => {
    console.log(error)
  })
}
```
認証サーバーと接続するところです。
認証サーバーの存在を知らなかったため、認証できないエラーが発生し5分ほど悩みました...


飛ばしたところに戻って...
```js
function startMeeting(signature) {
  client.join({
    sdkKey: sdkKey,
    signature: signature,
    meetingNumber: meetingNumber,
    password: password,
    userName: userName,
    tk: registrantToken
  })
}
```
認証が通ったら実際にZoomへ接続する処理になります。

```html
<section>
	<label for="meetingNumber">ミーティングID</label>
	<input 
		type="text"
		id="meetingNumber"
		bind:value={meetingNumber}
	>
	<label for="password">ミーティングパスワード</label>
	<input
		type="text"
		id="password"
		bind:value={password}
	>
	<label for="userName">名前</label>
	<input
		type="text"
		id="userName"
		bind:value={userName}
	>

	<button on:click={getSignature}>
		join
	</button>
  <div id="meetingSDKElement"></div>
</section>
```
ミーティングIDやミーティングのパスワード、参加時の名前を入力するinput要素を追加します。
また、ボタンをクリックするとgetSignature関数が実行され実際に接続できます。
`meetingSDKElement`は実際にzoomの画面が挿入されるスペースです。
以上で完成です。

my-appのディレクトリで`nom run dev`、meetingsdk-sample-signature-node.jsのディレクトリで`npm run start`を実行すれば実際に使える。

## まとめ
少しsvelteの扱いづらい部分が出たが意外にすんなりと実装できた。
とても簡単にZoomのクライアントを作成できるのでwebサービス内の機能で活躍できそう。