2022年08月19日の日記です


vue-tweet-embed で表示していた Tweet が崩れる  2022-08-19 17:10:34  コンピュータ

昨日 8/18 の夕方ごろから、仕事で作っていたプロダクトで、Tweet のタイムラインを表示していた部分で画面崩れが起きるようになった。


この時点では、リロードを繰り返すと崩れたり正常だったり。

あ、これは Twitter がウィジェット用の出力を変えたな、と気づいた。


普通は、Web ページに Twitter のタイムラインを埋め込みたければ、Twitter が公式に用意したサイトで作成した HTML の断片を埋め込めばよい。

この断片の中では、widget.js というプログラムを読み込んでいて、このプログラムがタイムラインを埋め込む。


しかし、Javascript のフレームワークである vue ではこの方法が使えなかった。




HTML は、画面を表現するための言語だ。

Javascript は、一般的な意味でのプログラム言語であり、HTML を操作するための機能も充実している。


ここで、Javascript でプログラムを作る際は、「データ操作」と HTML 操作を同時に行うことが要求される。

内部データを計算によって書き換えても、画面に反映されなくてはわからないからだ。


しかし、内部データと画面を常に一致させておく、というのが結構面倒くさい。


vue はこれを解消するフレームワークだ。

HTML とデータのつながりを記述できるようになっている。

そのうえで、Javascript でデータを操作すると、自動的に HTML に反映される。


非常に便利だ。

その代わり、今までのように「Javascript で HTML を操作する」のは禁じ手になった。

vue が書き換えることが前提なので、それ以外の書き換えがあると破綻するためだ。


さて、vue の説明が長くなった。

先に書いた Twitter の widget.js は「HTML を操作してツイートを埋め込むプログラム」であり、vue と相性が悪い。


そこで作られていたのが、vue-tweet-embed というライブラリだ。

これを使うと、非常に簡単に vue 内にツイートを埋め込める。




さて、今回、Twitter が送信するデータの形式が大きく変わったようだ。

widget.js は一緒にバージョンアップされているので問題はない。

しかし、vue-tweet-embed で表示する場合は、問題が出た。


具体的には、vue-tweet-embed のやり方で指定したサイズや、表示の際のオプションがすべて無視される。

縦に長い…とても長い「タイムライン」が表示され、スクロールバーも出ない。


これが冒頭に書いた画面崩れの状況だ。


僕が作っていた環境では、ツイートの冒頭に、以前はなかった「@~さんのツイート」という表示が入るようになった。

これ、noheader という指定で消していたものだが、vue-tweet-embed ではその指定も利かなくなっている。


昨日夕方は「時々崩れる」だったのが、今朝仕事を開始するときには「100%崩れる」状態になっていた。

Twitter 社が、数あるサーバーのすべてで新プログラムに更新が終わったのだろう。


これはどうにかしなくては。




ほぼ一日かけて何とかした。


まず、vue-tweet-embed の使用は廃止。

だましだまし使う方法もあるが、今後も同じようなことが起きては困るからだ。


公式 widget.js で何とかできる環境を構築するのが良いだろう。

先に書いた vue との相性の悪さは、v-once で解決できる。


vue で HTML とデータのつながりを記述する際のオプションで、「一度だけ描画」を意味するものだ。

最初に描画されたら、その後は更新しない。だから、widget.js が書き換えた後の内容が保証される。


あとは widget.js の読み込みをどうするかだ。

本当は、ツイッターの埋め込みを行う部分を指示する HTML などを準備したうえで、「最後に」読み込むと、埋め込みを行ってくれる。


しかし、vue だと埋め込みタイミングがいつになるかわからない。

(vue を使うと、ページ遷移なども画面の書き換えで行い、通信を起こさないようなことが可能になるため)


Twitter 公式に、widget.js 内の「埋め込み」メソッドの呼び出し方が定められていた。


すでに widget.js が読み込まれていることが前提だが、メソッドを呼び出したタイミングで埋め込みを行える。

これは公式に定められたものなので、今後も安心して使えるだろう。


さらに、公式に「widget.js を必要な時に読み込ませるが、読み込みが終わる前に、読み込みが終わったらやって欲しい処理を登録しておく」プログラムも公開されていた



そのままでは vue で使えないが、改造して使うことにしよう。




というわけで、出来上がったのが次のような仕組みだ。


まず、全体としては vue のコンポーネントだ。

このコンポーネントは、ツイートを埋め込むためのものになる。


だから、「埋め込みたい」側の vue プログラムからは、このコンポーネントを読み込んで組み込む必要がある。

この際、v-once タグをつけておいて欲しい。そうしないと、widget.js が書き換えたものが保証されないから。


template の中で、一番最初のタグに ref="tweet" をつけておいて欲しい。

また、ツイートを埋め込みたい部分には、ツイッター公式の埋め込み HTML 断片の、埋め込み部分を書いておく必要がある。

(だって、公式 widget.js は、それを見つけて書き換えるものだから)


あとは、このコンポーネントが読み込まれ、DOM が構築された際に適切なプログラムが動けばよい。

なので、mounted に仕込みを行う。


mounted(){ window.twttr = ((() => { const fjs = this.$refs.tweet; let js; let t = window.twttr || {}; if(t.widgets) return t; // もう関数定義されている js = document.createElement("script"); js.src = "https://platform.twitter.com/widgets.js"; fjs.appendChild(js); t._e = []; t.ready = function(f){ t._e.push(f); }; return t; })()); twttr.ready( () => { twttr.widgets.load( this.$refs.tweet); }); },


先に書いた通り、twitter 公式のプログラムから少し変わっている。


まず、一番重要なのは「widget.js の読み込みタグがなければ、追加することで読み込ませる」だ。

元のプログラムでは、HTML 内にタグがあるかどうかを確認していた。


でも、その追加したタグは、vue によって消されてしまうことがある。

なので、widget.js が読み込まれて関数定義されたかどうかを確認するように変更した。


タグを追加する位置は、元のプログラムでは特定のタグのすぐ後ろ、となっていた。

しかし、v-once された内部にしたいので、「内部の一番最後」に追加している。


あとは、そうした DOM を探し出す方法が vue 向けに変わっているくらいか。



最後に、twttr.ready に「埋め込み」を指示する関数を書いてある。

twttr.ready は、上のプログラムの中で、キューに登録するプログラムとして作ってある。


これ、widget.js が読み込まれた時点で、キューに入っている関数を実行してくれる。

そのうえで、twttr.ready 自体が書き換えられ、キューに登録ではなく「即時実行」になる。


そのため、再度この部分が読み込まれた場合には、新たに widget.js を読み込むこともなく、即時に埋め込みが行われる。




ひとまず、相性が悪い widget.js を、無理やり vue の中にねじ込んだ。

これで、今後 widget.js がバージョンアップすることがあっても大丈夫だろう。


でも、今回もこれだけでなく、文字サイズが変わったり、全体デザインが変わったり、いろいろ変わってるんだよね。


最初の方に書いた noheader が効いていないのは、公式 widget.js では大丈夫だった。

でも、以前は使えた noborder や nofooter は廃止されているようだ。


今回廃止されたのか、以前から実は使えてないのかはわからない。


今後も、「崩れる」ほどではないが、「見た目が変わる」くらいのことはあるかもしれない。



翌日追記

これを書いている「翌日」というのは土曜日。


昨日は、とにかく突貫作業でどうにかしなくてはならなくて、作り上げて日記ネタにした。

今日になって、気になったので、仕事時間外だけど vue-tweet-embed のソースを読んでみた。


驚くことに、構造はほとんど僕が作ったものと同じだった。

公式の widget.js を読み込み、widget.js の埋め込む対象位置を教えるタグを埋め込み、埋め込むための関数を呼び出す。


呼び出す関数が少し機能の違うものだったり、タグの作り方が違ったり、vue の再描画に対する保障方法が違ったり、という違いはあるのだけど、大きくは変わらない。


そうすると、なぜ表示崩れが起きたのかよくわからない。

いろいろな「若干の違い」によるものかもしれない。


また、vue-tweet-embed が広く使われている割に騒ぎになっていないのが不思議だったのだが、これも環境によって動作が違うのかもしれない。



謎はいろいろある。ここに書いたこと自体が、多くの人にとっては無意味なのかもしれない。


しかしまぁ、ライブラリに頼らず問題を自分の手元でコントロールできる状態に置いたことで、今後の保証をある程度得られた、と思うことにしよう。



同じテーマの日記(最近の一覧)

コンピュータ

別年同日の日記

04年 お披露目

09年 13日

09年 夏祭り

09年 誕生日

14年 ブレーズ・パスカルの命日(1662)

16年 ゴードン・ベル 誕生日(1934)

20年 視野欠損・経過観察


申し訳ありませんが、現在意見投稿をできない状態にしています


戻る
トップページへ

-- share --

0000

-- follow --




- Reverse Link -