[レポート] Webコンテンツ強化へのCloudinaryの活用事例 #ImageCon2020

Cloudinary ImageCon 2020 の "Leveraging Cloudinary for Progressive Enhancement" のセッションレポートです。Cloudinary、Puppeteer、Cloudflareを組み合わせて、Javascriptが使えない環境に向けてWebコンテンツをさらに強化させた事例を紹介しています。
2020.08.18

Guten Tag! ベルリンの伊藤です。

Cloudinary の ImageCon 2020 が開催されており、誰でも無料で登録し、オンライン配信を視聴することができます。本稿では、私が試聴したセッション「Leveraging Cloudinary for Progressive Enhancement」のレポートを行います。

概要

スピーカー: Ire Aderinokun (BuyCoins)

  • フロントエンドの開発者 & UI デザイナー
  • ナイジェリア発、仮想通貨の取引を行うBuyCoinsの共同創設者
  • Google ウェブ、Cloudinary メディアに長けている
  • ブログ: bitsofco.de

セッション: Leveraging Cloudinary for Progressive Enhancement

https://www.imagecon.com/agenda/session/276193

Cloudinary and other JAMstack tools have enabled developers to do so much more than we could have previously done by ourselves. In this talk, Ire Aderinokun, COO & VP Engineering at BuyCoins will show how tools like Cloudinary, Puppeteer, and Cloudflare can be leveraged to create what she call “live images.” These images are screenshots of CanIUse compatibility tables, allowing her company to have static images of dynamic content and deliver engaging experiences for end users.

Cloudinary などの JAMstack ツールにより、今まで自分たちではできなかったような様々なことが可能になりました。今回は、Cloudinary、Puppeteer、Cloudflareを使って、Javascriptが使えない環境の中で動的なスクリーンショットを取得して表示させる "ライブ画像" を作成した方法を紹介します。

セッションレポート

Javascriptの重要性

  • 2006年時点、ウェブサイトの73%で主な機能にJavascriptが利用されている
  • つまり、Javascriptが使えないとほとんどのウェブサイトの主な機能が使えない
  • Angularのリリースもあり、恐らく現時点ではさらに割合は増えているであろう

Javascriptを無効にしてみると

いくつかのサイトでは、完全にサイトを利用することができない

例: Facebookでは、サインインまで可能だが、"Javascript Required" のメッセージが出てコンテンツを全く表示させることができない。

しかし、いくつかのサイトでは、Javascriptを無効にした方が良いエクスペリエンスになってしまうことも。

例: あるニュース・メディアウェブサイトでは、通常はサイトアクセス時にコンテンツへ到達する前にクッキー同意に関するポップアップが表示されるが、Javascriptを無効にするとポップアップが表示されることなく直接ニュース記事を読むことができる。

Javascriptに依存することによる欠点

  • Performance(サイトの出来栄え):様々なフレームワークを利用しているようなサイトでは、Javascriptがないと完全に静的なサイトとなってしまう
  • Accessibility(サイトの利便性):特に1ページのウェブアプリなど、Javascriptがないとナビゲーションや操作が正しく動作しない可能性がある
  • Progressive Enhancement(段階的な強化):一般的には誰もが利用できるエクスペリエンスでなく、Javascriptが使える前提での開発を行うので、後から使わない場合の一部のケースについてさらに追加で確認しなければならなくなる

Javascriptを使い、JAMstackで改善させる

もちろんJavascriptを使うべきでない、ということではない。Javascriptを使いながらも、JAMstack (Webサーバに依存せずに Javascript/API/Markup でサイト開発する技術) でエクスペリエンスを改善させた方法を紹介する。

自身のブログ bitsofco.de でフロントエンド開発に関する技術記事を書き、その中でよく CanIUse.com の情報を参照することがあるため、CanIUse の最新情報を取得して即座にインタラクティブに互換性のテーブルを表示させる埋め込みスクリプト The CanIUse Embed を作った。

問題 - もし読み込みに失敗した場合、フォールバックの文言を表示させるようにしていた。しかし、以下のような場合で読み込みに失敗してしまい、テーブルが表示されず失敗メッセージのみが表示されてしまう:

  • Javascriptが無効化されていて使えない
  • 接続が遅い(結果、Javascriptが読み込めない)
  • Eメールでコンテンツを送る等、そもそもJavascriptが読み込まれない

CanIUse Embed with/out Javascript

解決策 - Javascriptが使えない場合に、そのテーブルのスクリーンショットを表示させる

次のライブラリやSaaSを使って実現:

  • puppeteer: Headless Chrome(UIなしで使うChrome)でJavascript有効時のページのスクリーンショットを取得
  • Cloudinary: スクリーンショットをアップロードし、CDNで高速配信
  • Cloudflare: 分かりやすいドメインの短いURLを使うよう、CloudinaryのURLへリダイレクト

コード(その1)

puppeteer でスクリーンショットを取得

各セクションで、ビューポートを800x800でランドスケープに定義、Chromeのウィンドウを開く、ページにアクセスしてすべてのスクリプトが読み込まれるまで待機、スクリーンショットを取得、ブラウザを閉じる、という流れで行っている。

puppeteer code v1

Cloudinary にスクリーンショットをアップロード

CloudinaryのアップロードAPIで先ほど取得したスクリーンショットをアップロードし、レスポンスの secure_url(HTTPSの画像URL)を返す。

Cloudinary の Node.js SDK を試してみた - クレデンシャル設定

const cloudinary = require('cloudinary').V2;
cloudinary.config(/* config here */);

cloudinary.uploader.upload_stream((error, result) => {
	if (error) reject(error)

	return result.secure_url;

}).end(screenshot);

フォールバックの処理として、ただの文章の代わりに、Cloudinaryにアップロードしたスクリーンショット画像を配信するようコードを書き換える。さらに、Cloudinaryでは末尾の拡張子を書き換えるだけで即座にそのフォーマットの画像に変換して配信することができるので、最適なフォーマットで配信されるようwebp/png/jpgを並べた picture 要素を使う。

<picture>
	<source type="image/webp" srcset="https://res.cloudinary.com/CLOUD-NAME/iamge/upload/v1571256076/caniuse-embed/flexbox-2019-10-16.webp">
	<source type="image/png" srcset="https://res.cloudinary.com/CLOUD-NAME/iamge/upload/v1571256076/caniuse-embed/flexbox-2019-10-16.png">
	<img src="https://res.cloudinary.com/CLOUD-NAME/iamge/upload/v1571256076/caniuse-embed/flexbox-2019-10-16.jpg" alt="Data on support for the flexbox feature across the major browsers from caniuse.com">
</picture>

これでJavascriptが使えないユーザでもテーブルを表示させられる!???
...でも最新情報じゃないよね(´-`).。oO

==> ここまでの処理を日次で実行し、ユーザ側には変わらないURLを提供してリダイレクトさせることに。

コード(その2)

改) puppeteer でスクリーンショットを取得

CanIUseの全機能を1つずつ取得するのでなく、配列にして for 文でスクリーンショットを取得する。

puppeteer code v2

改) Cloudinary にスクリーンショットをアップロード

取得したスクリーンショットの変数を使い、こちらも for 文でアップロードする。   

const images = [];

for (let i = 0; i < screenshots.length; i++) {

	const options = {
		folder: 'caniuse-embed/all',
		pulic_id: screenshots[i].feature
	};

	cloudinary.uploader.upload_stream(options, (error, result) => {
		images.push({
			feature: screenshots[i].feature,
			url: result.secure_url
		});
	}).end(screenshot);
}

Cloudflare でリダイレクト

Cloudflareのページ転送ルールを作成することで、CloudinaryのURLでなく、ドメイン caniuse.bitsofco.de を使った簡単なURLを提供することが可能に。

Cloudflare転送ルール作成

ただし、CloudinaryのURLにはバージョン番号が含まれる。同じ名前の画像をアップロードし直すと、古い画像は配信されたURLで引き続きキャッシュされ、新しいバージョン番号のURLでアクセスした時に新しい画像が配信される仕組みになっているため、新しい画像にアクセスさせるにはURLのバージョン番号を更新しなければならない。

https://res.cloudinary.com/
ClOUD-NAME/         # クラウド名(≒アカウントID)
image/upload/      # アセットタイプ等
v1574685647/       # バージョン
caniuse-embed/all/ # フォルダ
css-grid.png       # 画像の名前と拡張子

デフォルトで返されるこのフルバージョンは画像更新日のUNIX時間だが、この番号は123等なんでもOKなので、今回はタイムスタンプを使ってCloudflare APIを使って実現することに。

Cloudflare code

これらのコードは Heroku で日次ジョブとして自動化。

これらにより、 The CanIUse Embed では、Javascriptがない場合でも、ドメインを使ったシンプルなURLから互換性のテーブルが表示できるように?

<img src="https://caniuse.bitsofco.de/image/css-grid.png" alt="Data on support for the flexbox feature across the major browsers from caniuse.com">

関連記事

おわり

Cloudinaryは主には画像最適化を目的に使用されることが多いですが、Cloudflareと組み合わせた興味深い利用事例でした。ImageCon 2020 は10月23日までオンデマンドでいつでも試聴可能です。

クラスメソッドでは、Cloudflare for Teams の導入もサポートしています。Cloudinary、Cloudflare ともにお気軽にこちらからお問い合わせください。