はてなにおけるPortals
2019/05/30 #portals_study
株式会社はてな Pasta-K / hitode909
アジェンダ
マンガビューワ特有の苦労
Portals以前のアプローチ
マンガビューワへPortalsの導入デモ3連発とその開発中の知見
Portalsへの期待
自己紹介(1)
pastak.icon Pasta-K
京都大学工学部情報学科 在籍中
株式会社はてな マンガチーム アルバイト 主にフロントエンド
Notaでスクリーンショット共有サービスGyazoのフロントエンドもやってます
最近の代表作: となりのヤングジャンプにオフラインで読む機能(β)を追加しました。 - となりのヤングジャンプ 編集部ブログ
ウェブアプリケーションがオフラインでも動作できるようにやっていった話 / ServiceWorker for Offline WebApp in MANGA Viewer - Speaker Deck
自己紹介(2)
hitode909.icon hitode909
株式会社はてな マンガチーム サーバーサイドとフロントエンド
インターネットが好きで、自分のブログで新しいブラウザのAPIの練習をしている
デスクトップにmasawadaを表示するmasawadaデスクトップボタン
はてなにおけるPortals
二人の所属するマンガチームでの取り組みを紹介します
GigaViewerについて
サーバーサイドでの画像や書誌の取り込み+更新情報を伝えるメディア面+いい感じに表示するビューワで
2017年1月リリース
はてな開発の新マンガビューワを「少年ジャンプ+」が採用。集英社と共同でサイト成長、マネタイズの両面を加速 - プレスリリース - 株式会社はてな
現在7サイトに対応
https://hatenacorp.jp/press/release/search?q=マンガビューワ
いろんなサイトに同じビューワ・アプリケーションが導入されている
よく見るといろんな違い
オフラインに保存する機能や、目次機能など
ウェブブラウザで快適に漫画を読めるマンガビューワ
URLを開くとすぐに読み始められる
スマホでもPCでもタブレットでもブラウザさえあればOK
とはいえ、ほとんどスマホなので余計な帯域を使わないように
ブラウザで出来ることをドンドン取り込んで進化させている
GIFアニメ埋め込み・フルウィンドウ・オフラインなどなど
アプリケーション全体の設計
さまざまなサイトのコードベースは共通
管理しやすく、あるサイト用に作った機能の横展開を容易に
1行書いたら新機能が追加される
アプリケーションサーバーも共通
サイトによって更新スケジュールがちがうので、サーバーを束ねてトラフィックのスパイクに強く
マンガの更新直後にアクセスが集中するという特徴がある
フロントエンド側も色々なことをしながら、ビューワーなどが共通で在れるようにしている
令和に向けてフロントエンドツール群を整えた話 - pastak-pub
マンガサービス固有の課題と、高速化へのアプローチ
一般的な話題として
サービス全体の速度
PageSpeedをグラフにしてMackerelで見ている
PageSpeed Insights のスコアを Mackerel に投稿するアプリケーションをボタン1つで Heroku にデプロイできる状態にした - Sexually Knowing
コミックDAYS|検索
WebPを試している
動的なリサイズが不要なところから練習
ビューワーでは幾つかの問題があって利用できていない
何のための速度を求めるのか
画像の先読みが必要である
サクサク読み進めたい。ページをめくるたびに待ち時間が発生してしまう
次のエピソードの先読みが必要である
「連載」という形でさまざまな作品の最新エピソードが毎日公開されているので、たくさん読んでほしい
→紙の単行本や雑誌に負けないように
地下鉄など、回線状況が悪いときにも読みたい
無駄な通信をしたくない
最新話を読みたいこともあれば、1話から一気に読みたいパターンもある
アプリケーションが遅いと読書体験悪化
ページ読み込み高速化が体験に直結する
大量の画像を表示する
プレミアムユーザーになると雑誌をまるごとブラウザで読める
コミックDAYS|DAYSプレミアム
分厚い雑誌は700ページくらいある
ビューワの設計
2015年にジャンプルーキー用にjQuery, MVPアーキテクチャパターンで実装
TypeScript で実現する MVP アーキテクチャパターン - Hatena Developer Blog
その設計をひきついでGigaViewerも実装
touchイベント等をハンドリングして自前でページめくりを管理
現在表示中のページを管理することで、画像の遅延ロードを実現
ページ遷移へのアプローチ
2018年夏のインターンで画面遷移を高速化
ビューワ→ビューワのみ
pjax, Turbolinks的なことを手で書く(Reactは使っていません)
MVPアーキテクチャからReactなどを使ってSPAにする難しさ
フルスクリーンで読み続けたい→次の話に行くとフルスクリーンが解除されて不便という話題もあった
他のモダンブラウザでは解除されるが、Safariでは解除されないまま遷移してしまう
手作り画面遷移の課題
実装が難しい
ページ遷移で変わる部分と変わらない部分を分ける
取得するまで読めるか読めないかわからない問題
遷移先が読めるビューワでないときは普通の画面遷移にフォールバック
動けば良いだけではなくサードパーティのグッズとの兼ね合い
計測、広告、SNSウィジット
通常はブラウザがやってくれている機能をページ内部に実装することになる
プログレスバーを手作り
ページを開きっぱなしにしたときに古いコードが動き続ける
毎日デプロイしてると昨日のJSはもう動かないということがある
そこでPortals pastak.icon
Portals触ったことある?
動画は見た
ハンズオンやってみた
色々遊んでみている
仕様を読んだ
はてなマンガチームとPortals
uskayさんにご紹介頂いて、昨年のからぼんやりと試していて、4月くらいから本格検証をしています
GigaViewerでどう使えるかデモをしたりしながら、方向性を探っている最中
検証の過程で見つけたことをchromiumのissueで積極的に還元しています
GigaViewerを埋め込むとクラッシュした
レンダリングが重いとmacでブラウザの一部が真っ白になったり
Basic認証がかかっているページを読み込むとクラッシュしたり
GigaViewerでのデモ
3連発紹介します
※ 画面は開発中のものです
動画内の作品: 中間管理録トネガワ - 福本伸行/萩原天晴/三好智樹/橋本智広 / 第1話 紹介 | コミックDAYS
デモ①
巻末の次のページへの遷移のところにPortalsで自作の冒頭ページを埋め込む
https://youtu.be/jUYqdiw-RPk
デモ②
埋め込む箇所を左下に
カウントダウンさせて5秒経ったら次の作品へ移るみたいなのもやったけど、動画内には無いです
今のところactivate()はユーザージェスチャーを要求しないので出来る
https://youtu.be/GE6xE-3ZiKg
デモ③
メディアトップからビューワーを開く
ビューワーの裏にはadoptPredecessorでトップページを埋め込んでいる
https://youtu.be/A9MAcJWigDY
開発中のエピソード
デモを色々作っていたときのエピソード紹介のコーナー
現状のPortalsの使用感
<portal src='...'></portal>書くだけでウェブサイトを埋め込めて、適当なタイミングでactivate()呼べば遷移してくれるのでとにかくお手軽
ちょっとした体験の向上やページ遷移の高速化のためだけだったら、これで十分。数分で取り込める。
他のウェブサイトがによってPortalsで埋め込まれた際に体験を提供することも出来そう
デモでは、window.portalHostがあるときだけ、1ページ目の画像を表示するようにしています
ページ遷移を手作りしていたのを代替出来る+表現力とpreloadがアップ
iframeの代替ではなくて、preloadと画面遷移の体験の向上の為に利用している
preload的にページを先に読んでDOMなどの構築も終えているのでスピードアップ
adoptPredecessorがあれば前のページ(BrowserContext)に戻れる
pushStateとかでやっていたのをPortalsに移譲出来る
ページ遷移ではなく、前のページがそのまま保持される(うつのみやさんも話されそう)
ページ内での状態をリストアする必要がないので便利、ここはiframeとpushStateでは作りきれない部分
手作りの課題が解決される
取得するまで読めるか読めないかわからない問題
→画面内に表示できるのでユーザーにフィードバックは返せる
→postMessage、activate(data)、window.portalHost
通常はブラウザがやってくれている機能をページ内部に実装することになる
→プログレスバー作らなくて良くなる
困ったところ
ブラウザのヒストリーバック出来ないの仕様ではなくバグらしい
https://bugs.chromium.org/p/chromium/issues/detail?id=944198
計測、広告
普通に作るとJSがPortals内でも動いてしまうので、PVが倍になったりしませんか
行って戻った場合にページの訪問を増やすべきなのかそうでもないのか
Portalsとして埋め込まれたPVが増えるのはよいが、広告のインプレッションが増えてしまうのはまずいのではないか
window.portalHostとかをみて制御したらよい?
アニメーションと組み合わせて遷移させたりすると、adoptPredecessorを使って戻ってきたときにその状態が維持されている
activate()で遷移した後にバックグラウンドでJSとかでゴリゴリ元に戻しておく
これ結局SPAとかの辛さがあるのでは🤔
今後への期待
開発者ツール
https://bugs.chromium.org/p/chromium/issues/detail?id=929356
Portalsをinspect elementしたい
クリックしても選択できない
onclickでactivateしている場合、activateされてしまう
Portalsの前後の要素をinspectして、そのまわりをたどっていくとinspectできている
遷移時にDevtoolがdeactivateされてしまうので、上手い感じになってほしい
Portalがループしたときに無限に読み込みが続く hitode909.icon
<portal src="."></portal>すると自分自身を読み込み続ける
自分自身を参照することはないにせよ、相互に参照する場合はありそう
リダイレクトループの検知みたいな感じで防いでもらえるとうれしそう
X-Frames-Option相当のものが入るらしい
We should explicitly cover how this specification interacts with CSP, RFC7034 and other specifications that confine the behavior of frames.
from https://wicg.github.io/portals/#security-considerations
https://bugs.chromium.org/p/chromium/issues/detail?id=958042
読み込まれる側でもそうだし、読み込む側でも制御したいですね
読み込まれる側で制御したい場合(X-Frame-Optionsのようなイメージ)→ログインページとかを知らない外部サイトにPortalsとして貼られてしまうのは怖い
Content Security Policyは見てくれている
Portals内がフィッシングサイトにすりかわっていると怖い
標準化と他のブラウザでの導入の温度感どうですか?
Chromeだけでしか入ってない状態で大きくブラウザに依存するUXを作るのは怖い
PortalsはそれくらいUI/UXに大きな影響を与える要素だと感じています
特にadoptPredecessorが非常に強力でPortalsの魅力を体現している
<portal><iframe><img alt=...></iframe></portal> で回避するのは?
portalを使って認証して、戻ってくることで、ブラウザをリロードしなくてもよい、という体験を作れる
はてなブログを見たときにログインしていない→グローバルヘッダをPortalsにする、というユースケースを話していました
<iframe>やhistory.pushStateを組み合わせてもpolyfillできない
<iframe>は親フレームにネストする形でブラウザコンテキストを共有している。Portalsはそうではない。
まとめ
Portalsは非常に強力な武器
ページ遷移体験を簡単に向上できる
まだまだ発展途上という認識
ドンドン遊んで試して良いものになるように貢献していきたい
左下に埋め込むようなデモくらいだと代替可能なので、まずはそれくらいからやってみると良いかも?
We are hiring! hitode909.icon
https://developer.hatenastaff.com/intern2019 https://cdn-ak.f.st-hatena.com/images/fotolife/h/hatenatech/20190516/20190516190954.png
↑これもPortalsにしたかったけどScrapboxのContent Security Policyに阻まれて失敗
code:a.js
const portal = document.createElement('portal');
document.body.appendChild(portal);
portal.style = 'position: fixed; right: 10px; bottom: 10px; width: 300px; height: 200px;z-index: 99999';
portal.src = 'https://developer.hatenastaff.com/intern2019';
portal.addEventListener('click', () => portal.activate());
https://gyazo.com/8d95ca69ca52e5579369fa935f9289bb
Portalsでインターン来てくれを体験できるURL
https://blog.sushi.money/
Question?
#Portals