2016年1月25日月曜日

ツイッターWebのページ遷移の仕組みについて調べた

私が作ったMuting on Twitterというユーザースクリプトはその名の通り,
ツイッターWeb(Twitter Web Client)と検索ページでよくあるミュート機能を使えるようにする
というものです.
長らく悩ませていたページ遷移問題に決着をつけることができた(と思う)ので,それについてここに書いておきます.

ページ遷移問題とは

ページ遷移しても別ページ扱いにならず,ホームに戻った時にスクリプトが死んでる.

原因

別ページに飛んだ場合,ページが変わるわけではなく,中身のHTMLのコンテンツ部分が切り替わる.
そのため,ホームに戻った場合,HTMLが切り替わってしまうのでスクリプトも(見た目上は)死んでる.

解決するために必要なこと

  • ページの切り替わりを監視する
  • 動的にHTMLをまた作り直す
  • 変数に格納したノードも死んでるので再び格納する

修正

まず.ページの切り替わりがわからないと何もできない.
デベロッパーツールを開いてページが切り替わる際のHTMLを見てみると,
BODYタグが変更されたのがまず目についたのでMutationObserverを使って監視してみる.
(MutationObserverはとても面白いAPIなので,またどこかに書きます.)
するとクラス名やスタイルがコロコロと変わることが確認できた.
しかし1回の変更部分が多くて条件を書くのがちょっと大変だし,判定漏れする可能性もあった.
そこで他にも変更があったノードの一つ,div#docを監視してみた.
すると少ない変更部分でページ切り替えを感知することができたのでそちらを監視対象にすることにした.
どのような判定で再処理を行っているかはコードを参照.

なお,ページによっては別ページ扱いになる場合もあったので,
以下にホームから各ページに遷移した場合の扱いをまとめた.
  • 別ページ扱い
    • リスト
    • ヘルプ
    • おすすめユーザー
    • Twitterについて
    • 規約
    • プライバシー
    • クッキー
    • 広告ヘルプ
    • ブランド
    • ブログ
    • ステータス
    • アプリ連携
    • 採用情報
    • 広告管理画面
    • 広告掲載方法
    • メディア
    • 開発者
    • おすすめユーザー部分
  • 別タブで開く
    • Twitter広告
    • アナリティクス
あとはページがホームor検索の時に再びHTMLを動的に作って,必要なノードを格納するだけ.
イベントリスナーなどの1回きりの処理とそうでない処理を分けて,ページ切り替え時に後者を実行する.

まとめ

ページ遷移に対応できた.
しかし,別ページにいる時間が長い,もしくはさらに別ページに遷移した場合,再構成できないことがあった.
詳しい条件がわからないので,判定をすり抜けたのか,切り替えを感知できなかったのかは断言できない.
そのどちらでもないとしたら新たな解決法を探す必要がある.
また追ってその問題は確認したいと思う.
もし再現できた人はどこでもいいので教えて欲しい.

追記(17:17:40)

報告により原因が解明できた.

他のページ(ユーザーページなど)を起点としてホームや検索に行った場合,ホームと検索以外ではスクリプトが動かないから,当然スクリプトは動いてない状態だしページ内移動扱いだから新たにスクリプトが動くこともない

これは例えばユーザーページへアドレスバーとかブックマークとかで移動した場合に限らず,ホームや検索で別ページ扱いになるページに移動した後,上部の「ホーム」でホームに戻った場合も該当する.
ホームを出す(スクリプト動く)→別ページに行く (ページが新たに読み込まれる.スクリプト死ぬ)→ホームに行く(ページ内移動扱いなのでHTMLが切り替わるだけで,ページは再読み込みされないし当然スクリプトは実行されない)

解決法として,スクリプトが動く範囲を Twitterのページ全てにすることでどのページでも動くようにした
しかし内部のページ読み込み(iFrame)でも反応してしまうので,そこらへんのページの除外を地道にやっていく必要がある
十分に検証をしたら修正版をあげる

追記(2016/01/27)

修正版を上げた.もしexcludeに不足があれば今後修正していく