みなさん初めまして。晴れる屋 IT チームの森岡です。
先日リリースしたデッキ構築機能、おかげさまで多くの方にご利用いただいています。
本機能の実装にあたってはディレクター兼デザイナーとして、企画や仕様策定などを行いました。

ユーザーが自由にデッキを構築しシェアできる本機能ですが、中でも力を入れたのは「デッキリストの埋め込み機能」です。
note など一部のサービスでは URL を貼るだけで、その他のサービスでも埋め込みコードを発行することで、記事や Web サイトの中にデッキリストを埋め込むことが可能です。
デッキ構築機能は基本的には開発会社に開発を依頼していますが、デッキ埋め込み機能については自ら実装も行いました。
本記事ではデッキ埋め込み機能開発の経緯と技術的な解説を行います。

なぜ開発したのか

古くより MTG プレイヤーは自らのデッキについてインターネット上で発信を続けてきました。
ひと昔前は Diarynote、最近は note で記事を書いている方が多いのではないでしょうか。

その際にデッキリストを掲載する方法はカードを並べて写真を撮ったもの、テキスト、デッキ構築サービスの URL を貼ったものなどさまざまです。
URL の貼り付けは比較的コストが低いものの、総じて手間がかかっています。
また掲載の方法が統一されていないことも読み手の負荷になり得ます。

この問題を解消できるのではないかというのがデッキ埋め込み機能開発の理由であり、ひいてはデッキ構築機能開発のきっかけの 1 つでもあります。

そもそも「埋め込み」とは

皆さんは「埋め込み」と聞いてどのようなものを思い浮かべますか?
なじみ深いところでは Twitter におけるツイートの埋め込みや、Youtube における動画の埋め込みでしょうか。

埋め込むための技術

要するに「あるコンテンツを別のコンテンツの中で動的に引用する」ことなんですが、それを実現する技術には大きく分けて 2 通りあります。

<blockquote class="twitter-tweet">
    <p lang="ja" dir="ltr">
        【キャンペーン】<br>\マジック:ザ・ギャザリングを始めるなら今/<br><br>『春のお友達紹介キャンペーン』開催中🌸<br><br>ご友人と晴れる屋でマジックを始めると<br>合計4000円相当のポイントをプレゼント🎁<br><br>詳細はこちら↓↓<a
            href="https://t.co/5WMZv42F92">https://t.co/5WMZv42F92</a> <a
            href="https://t.co/DibcxezoI5">pic.twitter.com/DibcxezoI5</a></p>— 晴れる屋 (@hareruya_mtg) <a
        href="https://twitter.com/hareruya_mtg/status/1519979808104534016?ref_src=twsrc%5Etfw">April 29, 2022</a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

1 つは Javascript による埋め込みです。
Twitter はこの方法ですね。
DOM と script タグをセットにした埋め込み用コードを貼り付け、script によって埋め込んだコンテンツを描画します。
DOM の内容によっては、元サービスが動いていなくてもある程度内容を担保できます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/6KNZ83k2XHM" title="YouTube video player"
    frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
    allowfullscreen></iframe>

もう 1 つは iframe による埋め込みです。
Youtube はこの方法ですね。埋め込むコンテンツが複雑な場合にはこちらが採用されている傾向がある気がします。

oEmbed

先に示したようなサンプルコードを貼り付けることによって、コンテンツを埋め込むことができます。
一方で URL を貼り付けるだけでコンテンツが埋め込まれるサービスもあります。冒頭で例に挙げた note は埋め込みコードではなく、URL を貼り付けることでコンテンツを埋め込めます。

これを実現するための規格が oEmbed です。
コンテンツを埋め込む先である Consumer と埋め込まれるコンテンツである Provider 間の API の仕様を定義したもので、Consumer としては WordPress や はてなブログ、note などのブログサービス、Provider としては Twitter や Youtube などで広く使われています。
単体で 1 本の記事が書けてしまうのでこの記事では詳しく語りませんが、気になる方は仕様書を読んでみてください。

それぞれ対応しているサービスが異なるため、今回はコード貼り付けと oEmbed の両方に対応することにしました。

実際に使用した技術

デッキ構築機能のインフラ構成図

埋め込みアプリケーション自体は Svelte で作成して S3 上にホスティング。
oEmbed API は API Gateway と Lambda の組み合わせで作成しました。
これらを CloudFront によって配信しています。

埋め込みアプリケーション

埋め込み先のパフォーマンスを損なうことがないよう、極力軽量なフレームワークを使いたいと考えました。
そこで白羽の矢が立ったのが Svelte です。

Svelte はある程度の規模までのアプリであれば他フレームワークの追随を許さない軽量ライブラリです。
Svelte は仮想 DOM を使用せず、ビルド時にバニラ Javascript にコンパイルされます。ランタイムでのライブラリの読み込みがないため、規模の小さなアプリケーションでは軽量になるようです。

Vue と記法が似ていることも個人的には嬉しいポイントです。

Web Components としてのコンパイルも可能で、「埋め込みアプリケーション自体は noindex としたいが、クローラには埋め込み先のコンテンツの一部として認識されたい」という要求から使ってみました。
ただし

  • 全コンポーネントを Web Components としてコンパイルする必要がある
  • Hot Module Replacement が効かなくなる

など、現時点ではあまり開発体験が良くありませんでした。
また Google が indexifembedded に対応したことで、Web Components にするモチベーションがなくなることに。
現状単なるオーバーヘッドになっているはずなので、隙を見て直したいところです。

高速化に関しては Lighthouse とにらめっこしつつ細々とした改善を行い、最終的には(関係のある)全項目で 100 点を記録できました。

「埋め込み先のパフォーマンスを損なうことがない」という点についてはこれである程度達成できたのではないかと思います。

oEmbed API

こちらはアプリケーション自体と比べてアクセスされる頻度が少ないため、素直に API Gateway + Lambda で構成しました。
最近になって Lambda が HTTPS エンドポイントに対応したようなので、今だったら Lambda だけで済みそうですね。

終わりに

まさか晴れる屋で技術記事を書く日が来るとは思いませんでした。

元々個人的な目標として「デザインだけでなく、アプリケーション開発全般をやってみたい」というものがあったため、今回の開発は良い経験になりました。
埋め込み機能はあまり頻繁に手を加えるものではありませんが、デッキ構築機能は今後もどんどん改善を重ねていこうと考えています。

要望などはお問合せフォームの「デッキ構築機能に関するお問い合わせ」にてお待ちしております。