PWA?SPA?WebAssembly?
うん、そうだね、よかったね。
それで、そのページは携帯で見れるのかい?
以下はAddy Osmani( Twitter / GitHub / Facebook / HP )による記事、Loading web pages fast on a $20 feature phoneの日本語訳です。
ちなみにこの人はGoogleのエンジニアで、Chromeの開発者のひとりです。
Loading web pages fast on a $20 feature phone
ヒント:高速なWeb基盤を構築することが、低価格のフィーチャーフォンにも、最新のハイエンドスマートフォンにも、全ての人々に良い体験を提供します。
Introduction
20~25ドル未満で購入できるフィーチャーフォンは、発展途上国において数億人が使用しているローエンドデバイスです。
それらはスマートフォンの低性能バージョンとも言えます。
低価格フィーチャーフォンは、CPUの性能が低く(ハイエンドスマホより6倍以上遅い)、RAMが少なく(通常4GB未満で、256-512MBも普通)、ストレージも少なく(4G)、そして大抵はタッチスクリーンもついておらず、ナビゲーションにはキーパッドや十字キーなどを使います。
たとえば以下のようなものです。
これらのデバイスは、ハイエンドスマホのようにリッチJavaScriptやメディアを処理することができません。
そのため、これらに送信するペイロードには特別な注意が必要です。
上記図はGeekbenchによる、2019年上半期に最も売れたスマートフォンのCPUベンチマークです。
人気のフィーチャーフォンであるNokia 3110のパフォーマンスを強調表示しています。
JavaScriptはシングルコアのパフォーマンスが重要であり(Webの他の技術と違い、JavaScriptは本質的にシングルスレッドです)、その性能はCPU性能に依存します。
発展途上国について考えるときは、このデバイス特性に留意する必要があることを意味します。
この記事では、デバイスの性能にかかわらず誰もが利用できるサイトを構築することで、これらの問題に対処していきます。
Background
フィーチャーフォンは、スマートフォンが登場する前、2000年代半ばまで人気のあった端末であることを覚えている人もいるかもしれませんし、覚えていない人もいるかもしれません。
タッチスクリーンではなく小さなキーパッドを備えていて、電話、テキストメッセージ、テキスト中心のシンプルなWebブラウジングなど、かなり基本的な機能でできていました。
スマートフォンの登場後、これらの電話は先進国ではあまり見られなくなりました。
発展途上国では、誰もが4Gネットワークの無制限データプランでスマートフォンを利用できるわけではありません。
この市場は、スマートフォンから最低限の機能を抽出し、ハードウェア性能と価格の妥協の産物、スマートフィーチャーフォンによって成り立っています。
スマートフィーチャーフォン市場は2017年から伸びに伸びており、2019年には世界で4億台ものスマートフィーチャーフォンが販売されると想定されています。
フィーチャーフォンの成長は、3110や8110(Paul Kinlanがデバッグガイドを公開しています)といった往年の名機をNokiaが復活させたことに支えられています。
インドでは、Reliance Jioが外出先でWebにアクセスするための、安価で最新のフィーチャーフォンを提供しています。
JiojはLinuxベースのフィーチャーフォン向けOSであるKaiOSを推進してきました。
フィーチャーフォン市場の成長により、効率的に動作するサイトが必要となってきており、そのためには注意すべき制約がいくつも存在します。
これはGoogle Images LiteとFacebook mBasicのサンプルです。
これらはいずれもフィーチャーフォンで快適に動作するようつくられており、クライアント側のスクリプト依存は最小限です。
ゲームであるProxxはスクリプトに多く依存しますが、フィーチャーフォンでも高速にロードするため積極的なコード分割設計を行っています。
Feature phone constraints
発展途上国のユーザは、3つの要因によって制限されています。
・低価格かつ高性能のデバイスはほとんどない
・高品質なネットワークがない
・手頃な価格のモバイルデータ通信がない
フィーチャーフォン向けサイトが必要であるならば、これらの制約に注意してください。
-
ハードウェア
フィーチャーフォンは大抵、低速(1.1GHz程度)のシングル・デュアルコアCPUと、512MB未満のRAMでできています。
この制約が意味するところにおいては、8コアCPUと4GBのRAMでできているiPhone XSと比較してみるとよいでしょう。 -
通信量
データプランは安くなりつつありますが、フィーチャーフォンが人気のある地域では依然として大きな制限があります。
ページが高速に読み込まれ、費用が多くならないように、できるかぎりペイロードを小さくしましょう。 -
スクリーンサイズ
フィーチャーフォンの画面サイズは通常、スマートフォンのそれよりはるかに小さいです。
2.4インチの大きさで、ほんの少ししか情報を出すことができません。
必要なリソースをビューポート内のコンテンツにできるだけ早くロードすることを第一に考えてください。 -
タッチスクリーン
タッチスクリーンがないので、画面上の各機能、アクションボタン、リンクへはキーパッドから簡単にアクセスできる必要があります。
必要以上にショートカットキーを埋め込む必要はありません。 -
キーパッド
フィーチャーフォンのキーパッドは、我々が使い慣れているQWERTYキーボードとは全く異なっています。
およそ15個のボタンでできていて、多くの文字はボタンを何度も押さなければなりません。
従って、タイピング量をできるだけ減らすUXを考える必要があります。
日本においても、データプランの上限がユーザエクスペリエンスに影響を与える可能性があります。
In Japan, the web is slower towards the end of the month due to data caps, resulting in reduced engagement pic.twitter.com/rKWClaqWUD
— Yoav Weiss (@yoavweiss) 2019年11月14日
Development Guidelines
以下のTIPSは、フィーチャーフォン向けWebサイトに高速なエクスペリエンスを提供するのに役立つでしょう。
全体的に、ユーザが要求したもの以外のために待たせないでください。
JavaScriptのダウンロード時間と実行時間を可能な限り抑えてください。
Set performance budgets for your initial payloads
良好なパフォーマンスを確保するために開発チームが従わなければならない制限を決める、Performance budgetsという考え方があります。
超過することを許さない制限です。
開発を始める前に定量化可能なメトリックを定義し、新しい機能を追加しても総量が制限を超えないようにします。
Performance budgetsの例としては、JavaScriptのバンドルサイズ、画像のサイズ、HTTPリクエスト数などがあります。
ユーザエクスペリエンスを図るための指標として、First Contentful Paint、Largest Contentful Paint、First Input Delayなどを採用可能です。
対象ユーザに応じて、これらのメトリックごとに閾値を決めていきましょう。
Performance budgetsはアプリケーションロジック、vendorやcommonsのバンドル、そしてその他の項目ごとに設定可能です。
Lighthouseを使ったビルドプロセスや、継続的インテグレーションにおいて強制させることができます。
PRPL-30 - a JavaScript budget for feature phones
Chrome開発チームは、低速ネットワーク上のローエンドデバイスでもなるべく早く操作可能にするため、コード量を細かく制御するPRPLパターンを推奨しています。
PRPLは、ページを表示するために必要な最小限のスクリプトのみをプリロードし、それ以外はあとから遅延ロードし、そしてService Workerで今後のナビゲーション用のデータをキャッシュしておくことを勧めています。
PRPL-50は、イニシャルリソースを50KBに制限するという、Performance budgetsを発展させた考え方です。
フィーチャーフォンはCPUによる制約も受けるため、JavaScriptにさらに厳しい制限を課す必要があります。
フィーチャーフォンを対象とするWebサイトは、PRPL-30(30キロバイト)がよいと考えています。
この仮定においては、SSLネゴシエーションが終わった後、適切なCDNからレスポンスの最初のバイトが返ってくるまでの時間はおよそ2秒です。
従って、初回のペイロードがダウンロードされ、レンダリングされ、ユーザが画面の操作をできるまでの時間は約3秒となります。
すなわち、JavaScript中心のWebサイトの場合は、minifyとgzip圧縮を行った後のバンドルサイズを30キロバイト未満に縮小しなければならないということです。
待って待って。
30キロバイトだって?
ふざけてんの?
Reactのライブラリすら入れることができないんですけど!
厳しい制約のあるデバイス向けのサイトを構築するのであれば、ユーザエクスペリエンスを追求するために難しいトレードオフを行う必要があります。
たとえばReactをサーバ側にしか使わない、あるいはアプリケーションロジックを最小限にして遅延ロードを行わせる、Preactのようなソリューションを使う、などです。
これらのトレードオフについては後で解説します。
PRPL-30を守ることのできるアプリケーションの例としては、たとえば25KBのファイルサイズと5秒未満のインタラクション時間を持つProxxです。
独自の指標を目的とする際は、パフォーマンス予測ツールが役に立つでしょう。
遅延ロードするファイルのサイズも35KB未満が目安です。
30-35KBのチャンクサイズは、V8スクリプトストリーミングが並列処理を行うのに十分な大きさです。
Be Frugal with JavaScript
tl;dr:可能なかぎりスクリプトへの依存を最小限に抑え、静的レンダリングもしくはサーバサイドレンダリングを採用する。
クライアント側レンダリングやハイブリッドレンダリングが必須であれば、必要最小限のスクリプトのみをできるだけ少ない回数リクエストする。
プログレッシブリハイドレーションのようなテクニックも検討する。
JS is the #1 bottleneck on feature phones
フィーチャーフォン向けにインタラクティブな体験を提供する場合、JavaScriptが最大のボトルネックになる可能性が高いことに気を付けてください。
ページをレンダリングする技術の選択によって、ユーザが実際にページを操作できるようになるための時間が遅くなる可能性があるため、この選定は重要です。
サーバサイドレンダリングや静的レンダリングを選んだ場合は、インタラクティブなペイロードはできるかぎり小さくしてください。
JavaScriptにはダウンロード時間および実行時間という、ふたつの大きなコストがあります。
ダウンロード時間は遅いネットワーク(3Gコネクションなど)によって伸び、遅いCPUは実行時間に遅延をもたらします。
下の図は、人気はあるが重いJavaScriptのあるサイトについて、CPUの種類による処理速度の違いを可視化したものです。
ハイエンドのスマートフォンに比べて、ローエンドのスマートフォンでは6倍もの実行時間がかかっていることがわかります。
これは即ち、レンダリングやインタラクティブ性を大きなJavaScriptバンドルに依存しているのであれば、フィーチャーフォンではユーザがUIを操作可能になるまで30から60秒待たされることすらあるということを意味します。
JavaScriptに必要なダウンロード時間と処理時間を最小限に収めるため、開発者はそれらのリソースをできるかぎり節約する必要があり、ユーザが必要とする可能性のあるルートやコンポーネントのためのJavaScriptだけを、それらが必要になったときにロードしなければなりません。
Keep interactive payloads lean
ペイロードを無駄にしないためにも、以下のことを守るべきです。
・画面外にあるコンポーネントやリソース、あるいはファーストビュー内でもクリティカルではないコンテンツについては、できるかぎり遅延ロードします。
・JavaScriptのコードを分割し、ファーストビューで必要なものだけを最初にロードするようにします。これによりダウンロードするスクリプトの量が減り、ページの読み込みが早くなります。
・バンドルから未使用コードを削除し、できるかぎり無駄のない状態にします。そのためにはバンドルを分析し、使用されていないライブラリや一部しか使われていないライブラリを差し替える必要があります。また、最初に使わないライブラリは遅延ロードさせる必要があります。
・差分ロードを用いて、必要な機能のみをブラウザに提供するようにし、過剰なトランスパイルや過剰なポリフィルを避ける必要があります。モダンブラウザに送られるレガシーコードの量を減らすことで、読み込みのパフォーマンスを上げることができます。
・レンダリングや、ファーストビューのUIのためにJavaScriptを使っているのであれば、それらをプリロードしてください。以下のように記述することでそれが重要であることをブラウザに伝えることができ、ブラウザはできるだけ早くロードします。
<link rel="preload" as="script" href="critical.js">
Choose your stack wisely
サードパーティ製ライブラリは開発を高速化し、複雑なタスクを容易に実現することに役立ちますが、その対価として重くなりがちです。
フィーチャーフォン向けに開発する場合は使用に注意しなければなりません。
以下のガイダンスを参考にしてください。
・フィーチャーフォンはリソースに大きな制約があるため、可能ならばJavaScriptフレームワークの使用そのものを避けるか、できるかぎり制限してください。
JavaScriptフレームワークは多大なオーバーヘッドを要求します。
Reactを使うのであればサーバサイドレンダリングするか、あるいはビルド時にPreact compatを使ってPreactに入れ替えて30キロバイト削減する、などの代替を検討してください。
Svelte、lit-html、そしてVanilla JSなどはバンドルを軽くするための良い選択肢です。
・サードパーティライブラリへの依存をできるかぎり減らし、初期ロードに必要なバンドルサイズを削減してください。たとえばMoment.jsのかわりにdate-fnsやluxonを使うなどです。bundlephobia.comなどでサイズのチェックができます。
・状態管理のためにReduxやStoreを使う場合は厳重な注意が必要です。
StateがしばしばHTMLにインライン展開され、レスポンスサイズが非常に大きくなってしまうことがあります。
Adapt to avoid loading heavy resources on slow connections
ヒント:このトピックの詳細については、adaptive loading - improving web performance on low-end devicesを参照してください。
Adaptive Loadingとは、提供するリソースをeffectiveTypeに基づいて変更する技術で、ブラウザからはNetwork Information APIで利用可能です。
Adaptive servingを使うことで、低速なユーザにも低機能であってもひとまずのエクスペリエンスを提供することが可能になります。
console.log(navigator.connection.effectiveType); // 3G
注意:たとえeffectiveTypeが"4G"であっても、スタバやカンファレンス会場のWifiのように実速度は低速である可能性は十分にあります。
Adaptive servingを使用すべき具体的な例としては、製品紹介ページなどがあります。
接続速度の遅いユーザには圧縮された商品画像だけを、高速なユーザには高品質な画像とJavaScriptによる強化された演出(画像のズームインや、別製品との比較を表示する機能など)を提供したりすることができるでしょう。
フィーチャーフォンにおいては、低速な回線が必ずしも最大の障害であるとは限りません。
遅いCPUや少ないメモリは、回線種別より多くの影響をユーザ体験に与えます。
Client Hintsは、CPUの性能にこそアクセスできないものの、デバイスのメモリ、Viewportの幅、ピクセルレート、ネットワーク情報、そしてその他の情報を集めることで、より詳細なサービス戦略を立てるために使うことができます。
Be respectful of users data plans with the Save-Data header
Android版Chromeにはライトモード(Data Saver)と呼ばれる機能があり、通信量を気にするユーザは、ブラウザがリソースを最適化してページの読み込み速度を向上させるオプションを選ぶことができます。
最適化には、画像を圧縮したり、重要でないリソースを後回しにしたり、ページをサーバ側でレンダリングすることなどが含まれています。
詳しくはChrome Lite Pagesをご覧ください。
対応しているブラウザでユーザがデータ節約モードを選択すると、あらゆるHTTP/HTTPSリクエストにSave-Dataリクエストヘッダが
アプリケーション開発者は、このヘッダがあれば重い機能をオフにするなど、データ節約モードをオンにしているユーザに最適化された体験を提供することができます。
JavaScriptでは以下のスニペットで確認可能です。
if ("connection" in navigator) {
if (navigator.connection.saveData === true) {
// Implement data saving operations here.
}
}
注意:お使いのフィーチャーフォンはChromeをサポートしているかもしれませんが、お使いのChromeがライトモードをサポートしているとは限りません。
Offload costly app logic and state handling to Web Workers
SurmaによるTechniques to make a web app load fast, even on a feature phoneを読んでください。
素晴らしい投稿です。
ブラウザのメインスレッドでは、JavaScript以外にもページレイアウト、ピクセルの描画、ユーザインタラクションの追跡など多くの機能が動いています。
複雑で時間のかかるJavaScriptは、これら他のタスクをブロックしてしまう可能性があります。
Web Workersは、メインスレッドをブロックせずにバックグラウンドでJavaScriptを実行できる技術です。
複雑なアプリロジックや状態管理サービスなど、コストのかかるJavaScriptのオーバーヘッドをメインスレッドから切り離すことができます。
メインスレッドとワーカースレッドは、postMessage()とonmessageハンドラでやりとりできます。
postMessage
を使って、任意の値やオブジェクトを含むひとつの値を送り付けることができます。
実装の困難はComlinkのようなライブラリで軽減することができます。
ワーカースレッドを使った場合と使わなかった場合でProxxの差を調べた、Surmaのケーススタディは読みごたえがあります。
Nokia2(RAM1GB、1.3GHzクアッドコア)では、ワーカースレッドを使わなければ6.6秒もの間アプリがフリーズしました。
しかし、ワーカースレッドを使った場合は、応答するまでの時間は48ミリ秒でした。
CPUをごりごり使う処理を書いているのであれば、それをワーカースレッドに移植する価値は十分にあると言っていいでしょう。
Optimize Images
画像は多くのデータ量を消費します。
低価格デバイスでは特に、デコードにも時間がかかります。
従ってフィーチャーフォンに画像を配信する際は、適切に画像のサイズと圧縮方法を選ぶことが大事です。
・Imageminのようなツールを使って、品質を下げずに画像のサイズを削減します。
・アニメーションGIFは動画に変換しましょう。ロードがはるかに速くなります。しかしその前に、ローエンドデバイスがそんなに重いメディアファイルを必要としているか考えてください。
・可能なら画像を遅延ロードしますが、遅延ロードさせるJavaScriptライブラリが重くては意味がありません。ネイティブのloading属性が役立つでしょう。
・同じ画像を複数のサイズで用意しておき、ユーザのviewportに最も適したものを選択して提供するレスポンシブイメージが役立ちます。
・画面に合った画像を提供します。低解像度のローエンドデバイスにはそれなりの画像を送ることで、より高速にデコードを行うことができます。
Detecting screen-size
現在は多くのスマホがQVGAで、解像度は320px * 240pxとなっています。
機能のオンオフやアダプティブローディングを画面サイズによって切り替えたい場合、以下のようなスニペットを使うことができます。
const isFeaturePhone = Math.min(screen.width, screen.height) <= 240;
これは、Porxxが採用しているアプローチに似た方法です。
Emulate a feature phone in Chrome DevTools
低価格フィーチャーフォン向けサイトを構築するのであれば、格安端末の実物を入手することを強くお勧めします。
PSA: if you like to test if your website works on KaiOS & if you live in US, a trip to BestBuy and $15 will get you this device for testing. pic.twitter.com/M4qbcgmtB3
— Mariko Kosaka (@kosamari) 2019年5月13日
Chrome DevToolsでフィーチャーフォンをエミュレートするのであれば、以下の手順で可能です。
・Chrome DevToolsを開く
・Toggle Device Toolbarを選択
・デバイスのドロップダウンからEdit→Add custom deviceを選択
・名前をKaiOS(もしくは必要な対象名)にする
・幅240、高さ320を指定
・UAをMozilla/5.0 (Mobile; LYF/F90M/LYF-F90M-000-02-23-181217; Android; rv:48.0) Gecko/48.0 Firefox/48.0 KAIOS/2.5 YouTube/1.66.51.J
にする
・保存する
・(オプション)CPU性能をカスタマイズすることもできますが、これはあまり正確ではありません
Conclusion
何処にいる誰にでも、全てのユーザに楽しい体験を提供することは可能です。
ただし、全てのユーザのハードウェアが同じではないので、その点には注意が必要です。
端末の価格が手頃であるほど、CPUの性能も同等に低い可能性が高まります。
JavaScriptのパフォーマンスがダウンロード時間と実行時間に依存していることを考慮し、適切なエクスペリエンスを提供することを考えてください。
これはスマートフォンでも注意すべき点ですが、フィーチャーフォンではさらに重要になります。
コメント欄
「すごい有意義な投稿だった!」
「よく見たらChromeの中の人じゃん。有益な情報をありがとう」
「Svelteのパフォーマンスが高いと感じていたので言及してくれてうれしい。Preact試してみる!」「SvelteとSapperが大好き!」「Svelteや類似のフレームワークが早く普及してほしいね」
「バンドルサイズを抑える最も簡単な方法?簡単さ、JavaScriptを使わなければいい。」
感想
JavaScriptなんてほぼ動かないからHTML全部べた書きな、CSSもまともに効かないからfontタグを使え、とかそういうレベルの話かと思っていたら全然違っていて、わりと最近のAndroidフィーチャーフォンの話だった。
JavaScriptもCSSもきちんと認識してくれるけど、単に性能が低くてネットワークも遅いから、そういうところでも見れるように出力をカスタマイズしろ、という話ですね。
日本ではローエンドと言われているデバイス、安価な通信回線でも一般的なWebサイトを見るには十分な能力を持っているため、日本向けのWebサイトであれば正直そこまで気にする必要はありません。
しかし、たとえば日本では完全に無名のTranssionは、アフリカに特化したフィーチャーフォンを作って2000円で毎年1億台売っています。
アフリカは次の中国と期待される未知の市場です。
2000円の超ローエンドデバイスでも快適に見られるWebサイト作りが、世界に目を向けるならば必要となってくることでしょう。
ともあれ、ローエンドだろうがハイエンドだろうが無駄にアニメーションとスクロールを要求するサイトは滅ぶべきである。