【Gatsby】iframelyを使うためにやったこと

01-05-2021

以前投稿していたブログでよく使っていたiframelyをGatsbyでも使おうとしたが、同じ要領では表示されなかった

今回はGatsbyでiframelyを使うために調べたこと、やったことについてまとめる

iframelyとは?

iframelyは一言でいうと、SNSやブログなどの共有時に使うHTMLの埋め込みコードを簡単に取得するためのサービス

このサービスを使うことで便利になるのは以下の点

  • HTMLの埋め込みコードを取得するのが簡単になる
  • 埋め込みコード未対応のサイトでも取得できるケースが多い
  • サービスに登録すると、文字色は背景色がカスタムできる(ただし、カスタマイズされた埋め込みコードは1000リクエスト/月まで)

iframelyが提供する基本機能で十分な場合は、基本的に無料で利用ができる

iframely UI

サイトにて、上記の画像のようにURLを入力してREFRESHをクリックすると、埋め込みコードとプレビューが表示される

問題だったこと

あとは、ブログに埋め込みコードを配置することで外部コンテンツへのリンクが使えるはずだが、実際はプレビューが表示されなかった

公式ドキュメントの説明によるとReactのように仮想DOMを使う場合、素の状態ではembed機能が使えない

React has its own virtual DOM and doesn’t execute (eval) any inline scripts that go with HTML elements you add.

正確には、HTML要素と一緒に書かれたインラインスクリプトをReactが危険なHTMLと判断して、実行をしないとのこと

Even when you use dangerouslySetInnerHTML. Even if that “dangerous” HTML is actually trusted to be safe. React considers that you expose yourself to the risks of out-of-sync virtual DOM.

解決策

注意事項

本記事はgatsby-starter-blogから生成していることを前提にしている
また、記事ではReactの関数コンポーネントでの実装を想定している

やることはシンプルで、iframelyで提供しているグローバルCDNを headタグ に配置することで、解決できる
ただ、Reactで headタグmetaタグ を操作するためのライブラリを使う必要がある
これに関してはgatsby-starter-blogですでに使われているreact-helmetを使うことで実現できる

では、公式ドキュメントCDNスクリプト配置の例が載っているgistを参考に以下のように実装する

まず、今回の実装で使うファイルは以下の通り

src
├── components
│   ︙
│   └── iframely.js ※新規生成
└── templates
    └── blog-post.js (headに)

components/iframely.js を新規作成し、iframelyのCDNスクリプトをコンポーネントで定義する

import React, { useEffect } from 'react'
import { Helmet } from 'react-helmet'

const Iframely = () => {
  // 古い記事に遷移したときにもCDNがロードされるように、rendering後loadする
  useEffect(() => {
    if (window && window.iframely) {
      window.iframely.load()
    }
  }, [])

  return (
    <Helmet>
      <script
      type="text/javascript"
      src="https://cdn.iframe.ly/embed.js"
      />
    </Helmet>
  )
}

export default Iframely

templates/blog-post.jsIframely を配置する

import React from "react"
import { Link, graphql } from "gatsby"

import Bio from "../components/bio"
import Layout from "../components/layout"
import SEO from "../components/seo"
/* ここ */
import Iframely from "../components/iframely"

const BlogPostTemplate = ({ data, location }) => {
  const post = data.markdownRemark
  const siteTitle = data.site.siteMetadata?.title || `Title`
  const { previous, next } = data

  return (
    <Layout location={location} title={siteTitle}>
      /* ここ */
      <Iframely />
      <SEO
        title={post.frontmatter.title}

上記のコードの修正/追加に加え、iframelyで生成した埋め込み用コードを貼り付けるたびに1点修正が必要になる

  • embed.jsの埋め込みを削除

    • iframely専用のコンポーネント(components/iframely.js)で読み込むため

      // 埋め込みコード
      <div class="iframely-embed">
        <div class="iframely-responsive" style="height: 140px; padding-bottom: 0;">
            <a href="https://expfrom.me" data-iframely-url="//cdn.iframe.ly/tn9cRBk"></a>
        </div>
      </div>
      <!-- ココを削除 -->
      <script async src="//cdn.iframe.ly/embed.js" charset="utf-8"></script>

上記の設定をすることで、以下のようにiframelyのHTMLの埋め込みコードが表示される

まとめ

jekyllで作ったブログでは、HTMLの埋め込みコードがそのまま使えたが、React製の静的ウェブサイトだと工夫が必要になることがわかった

実装時の手順や参照ページに関してはinouetakumonさんの記事が大変参考になった

余談だけど、素の状態のReactで埋め込みコードを簡単に使いたい場合、react-embedというパッケージがあるので、これを使うのもいいかもしれない