Help us understand the problem. What is going on with this article?

NuxtでInstagram記事の埋め込みを行う

やったこと

既存の静的サイトをNuxtでSSGしたかったので移行していた。
その際にinstagramの通常の埋め込みコードをそのままtemplateに記述してみていた。
↓一部省略したコード

<blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/p/[記事のID]/" data-instgrm-version="12" style=" background:"......>
</blockquote> <script async src="//www.instagram.com/embed.js"></script>

起こったこと

ページの読み込み時に表示されたりされなかったりと、不安定な状態に。

原因

instagramの埋め込みコードは<blockquote>をJavaScriptで<iframe>に置換する仕様(SNSの埋め込みコードの多くは似たような感じ)なので、Nuxtのライフサイクルとタイミングが合わない場合に要素が取得できていないようで、<blockquote>のままになってしまうことがあった。

対策その1

要素が取得出来ていないのなら<blockquote>直後のembed.jsをmounted内で実行すれば拾えそうなので以下のようにしてみる。

<template>
  <blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/p/...">
  </blockquote>
</template>

<script>
export default {
  mounted () {
    const script = document.createElement('script')
    script.src = '//www.instagram.com/embed.js'
    this.$el.appendChild(script)
  }
}
</script>

ロード時の不安定な挙動は解消された。
しかしながらnuxt-linkでの遷移後に再訪問すると100%表示されなくなってしまった。
ただ100%再現される事象なので一歩前進。

対策その2

追記 (2019/12/26)
対策その2のInstagram APIは2020年初めに廃止になるそうなので断念…
ログとして残しておきます。
https://www.instagram.com/developer/

対策その1のコードではembed.jsの実行タイミングが管理できないのでAPIを使う。
https://www.instagram.com/developer/embedding/#oembed

OMITSCRIPT
If set to true, the embed code does not include the script tag. This is useful for websites that want to handle the loading of the embeds.js script by themselves. To manually initialize the embed code, call the JS function instgrm.Embeds.process().

パラメータを見ていると、ロード処理を自分で処理できるというまさに今やりたいことが可能な夢の機能を発見したので早速使ってみる。

<template>
  <div v-html="html" />
</template>

<script>
export default {
  data () {
    return {
      html: ''
    }
  },
  mounted () {
    this.loadEmbedJS()
    this.getInstagram('http://instagr.am/p/[記事のID]/')
  },
  methods: {
    getInstagram (url) {
      fetch('https://api.instagram.com/oembed?url=' + url + '&omitscript=true')
        .then((res) => {
          return res.json()
        })
        .then((json) => {
          this.html = json.html
          this.$nextTick(() => {
            window.instgrm.Embeds.process()
          })
        })
    },
    loadEmbedJS () {
      const script = document.createElement('script')
      script.async = script.defer = true
      script.src = '//www.instagram.com/embed.js'
      this.$el.appendChild(script)
    }
  }
}
</script>

無事安定して表示されるように!
$nextTickの中でないとwindow.instgrmが取得できないところに注意が必要。
あとはv-htmlを使うならsanitizeもちゃんとした方が良いかも。。

対策その3

対策その1でnuxt-link遷移後に表示されなかったのは、一度embed.jsを読み込むとwindow.instgrmができ、nuxt-linkで遷移しても破棄されないため。
//www.instagram.com/embed.jsの中身を覗いてみると以下の記述があるので、
再訪問してもwindow.instgrmが既に存在することで実行されていない可能性が高い。

window.instgrm||(window.instgrm={Embeds:{}})

上記を踏まえてbeforeDestroywindow.instgrmdeleteしてみる。

<template>
  <blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/p/...">
  </blockquote>
</template>

<script>
export default {
  mounted () {
    this.loadEmbedJS()
  },
  beforeDestroy () {
    delete window.instgrm
  },
  methods: {
    loadEmbedJS () {
      const script = document.createElement('script')
      script.async = script.defer = true
      script.src = '//www.instagram.com/embed.js'
      this.$el.appendChild(script)
    }
  }
}
</script>

表示は問題なくされるようになった!
ただ再訪問時に以下のスクリプトエラーを吐くようになってしまった。。

Uncaught Error: Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.

minifiedされたJSなので例外の発生のみの警告。
フルメッセージを見るにはnon-minifiedなJSを使え、とのこと。
それは難しいのでどうしたものか。

同様のエラーに見舞われている方の記事を発見したものの、
//platform.instagram.com/en_US/embeds.jsは現在では
//www.instagram.com/embed.jsと同じソースにたどり着くようなので
解決には至らず。。
instagramの埋め込みコードがエラーを吐く件

表示と挙動には影響が見受けられなかったので、不本意ながらエラー処理は一旦保留。

おわり

現状はエラー解決まで至らなかったですが、表示だけでもAPIを経由してだいぶ遠回りするはめになったので、本記事が少しでもお役に立てば幸いです。
また間違いや改善点がありましたらご指摘いただけると嬉しいです!

kai-ono
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした