PRPL パターン

試験運用: PRPL は、大きな可能性を秘めた新しいパターンです。現時点で、Google はこのパターンに関するアイデアを反復しながら実験を行い、最高のメリットをもたらす条件についてさらにデータを収集しています。

モバイルウェブは非常に低速です。何年もかけて、ウェブはドキュメント中心のプラットフォームから最高クラスのアプリケーション プラットフォームへと進化を遂げました。 アプリを作成する際に使用できるプラットフォーム自体(Service Worker など)、ツール、テクニックが進化したおかげで、実際に、ネイティブ アプリと同様の機能がウェブでもほぼすべて実現できるようになりました。

それと同時に、コンピューティングの大部分は、高速で信頼性の高いネットワークに接続された高性能のデスクトップ パソコンから、低速または不安定(またはその両方)であることが多い接続を使用する比較的性能の低いモバイル端末に移りました。 これは特に、新たにオンラインに参入する 10 億人のユーザーがいる地域にあてはまります。

デスクトップの時代には、多機能で強力なウェブアプリを構築するためのパターンが考案されましたが、残念ながらそれらのパターンを使用して作成されたアプリは、モバイル端末で読み込むには時間がかかり過ぎてしまいます。あまりにも時間かかるため、多くのユーザーは諦めています。

これは、最新のウェブ プラットフォームの機能を活用して、きめ細かく、より高速にモバイルでのウェブ エクスペリエンスを提供する新しいパターンを生み出す機会だとも言えます。PRPL は、まさにそのようなパターンの 1 つです。

PRPL パターン

PRPL は、Progressive Web App(PWA)を構築および配信するためのパターンで、アプリの配信と起動時のパフォーマンスに重点を置いています。 PRPL は次の言葉を表しています。

  • Push: 最初の URL ルートに不可欠なリソースを Push(プッシュ)する。
  • Render: 最初のルートを Render(レンダリング)する。
  • Pre-cache: 残りのルートを Pre-cache(事前キャッシュ)する。
  • Lazy-load: オンデマンドで残りのルートを Lazy-load(遅延読み込み)する。

PWA の基本的な目標や標準を目指すだけでなく、PRPL は次のことを達成するための最適化に取り組んでいます。

  • TTI(Time To Interactive、インタラクティブ準備時間)の最小化
    • 特に初回の使用時(エントリ ポイントにかかわらず)
    • 特に実際のモバイル端末上
  • キャッシュ効率の最大化(特にアップデートがリリースされるのに伴って)
  • 簡素化された開発とデプロイメント

PRPL は、最新のウェブ プラットフォーム機能から着想を得ています。しかし、この頭字語のすべての文字があてはまらなくても、またすべての機能を使用しなくても、パターンを適用できます。

PRPL は実際のところ、特定のテクノロジーやテクニックではなく、むしろモバイルウェブのパフォーマンスを向上するための考え方や長期的なビジョンを表しています。PRPL の背景にある考え方は新しいものではありませんが、そのアプローチは Polymer チームによって枠組みと名前が決められ、Google I/O 2016 で発表されました。

Polymer の Shop e コマース デモは、PRPL を使用して、精巧にリソースを配信するアプリケーションの最高の例です。実際のモバイル端末上で、驚くほど高速に各ルートでインタラクティブな機能が実現されます。

Polymer Shop デモは 1.75 秒でインタラクティブになります

率直にいうと、実際のプロジェクトの多くは、PRPL のビジョンを最も純粋かつ完全な形で実感できる段階には至っていないでしょう。しかし、その考え方を取り入れ、あらゆる角度でそのビジョンの追求に着手するのに早すぎることはありません。 現在では、アプリのデベロッパー、ツールのデベロッパー、ブラウザのベンダーが PRPL を追求するために採用できる実用的なステップが数多くあります。

アプリの構造

PRPL は、次の構造を持つシングルページ アプリ(SPA)でうまく機能します。

  • アプリケーションのメインとなる entrypoint。有効なすべてのルートから配信されます。 このファイルは別の URL から配信され、何度もキャッシュされるため、サイズを非常に小さくする必要があります。 エントリポイントのリソース URL はすべて、絶対 URL で指定する必要があります。最上位以外の URL から配信される可能性があるためです。

  • shell または app-shell。これには最上位のアプリのロジック、ルーターなどがあります。

  • 遅延読み込みされたアプリの fragment。フラグメントは、特定のビューのコード、または遅延読み込み可能なその他のコードを表すことができます(たとえば、ユーザーがアプリを操作するまで表示されないメニューなど、最初の描画には不要なメインアプリのパーツ)。shell は、必要に応じて動的にフラグメントをインポートする機能を担います。

サーバーと Service Worker は連動して、非アクティブなルートのリソースを事前にキャッシュします。

ユーザーがルートを切り替えると、アプリはまだキャッシュしていなかった必要なリソースを遅延読み込みして、必要なビューを作成します。 ルートへのアクセスを繰り返すと、即座にインタラクティブになるはずです。 Service Worker はここで大いに役立ちます。

以下の図は、ウェブ コンポーネントを使用して構造化可能なシンプルなアプリのコンポーネントを示しています。

個別と共有の依存関係を持つ 2 つのビューがあるアプリの図

注: HTML Imports は Polymer の優先バンドル戦略ですが、コード分割やルートベースのチャンクを使用して、最新の JavaScript モジュール バンドラで同様のセットアップが可能です。

この図で、実線は static dependencies を表します。<link> タグと <script> タグを使用してファイルで指定した外部リソースです。 破線は dynamic または demand-loaded dependencies を表します。必要に応じてシェルで読み込まれるファイルです。

ビルドプロセスではこれらの依存関係をすべてビルドし、サーバーはこの情報を使用して、ファイルを効率良く配信します。 また、HTTP/2 をサポートしていないブラウザ向けに vulcanize を実行したバンドルのセットをビルドします。

アプリのエントリポイント

エントリポイントでは、シェルをインポートおよびインスタンス化し、条件に応じて必要な polyfill を読み込みます。

エントリポイントに関する主な考慮事項は次のとおりです。

  • 静的な依存関係を最小限にする。つまり、app-shell 自体より大きくなりすぎないようにする。
  • 条件に応じて必要な polyfill を読み込む。
  • すべての依存関係で絶対パスを使用する。

App shell

このシェルはルーティングを行い、通常はアプリのメイン ナビゲーション UI が含まれます。

アプリでは、必要に応じてフラグメントを遅延読み込みする必要があります。たとえば、ユーザーが新しいルートに変更すると、そのルートに関連するフラグメントをインポートします。これにより、サーバーに対する新しいリクエストが開始されるか、または単にキャッシュからリソースが読み込みまれます。

シェル(シェルの静的な依存関係も含む)には、最初の描画に必要なものがすべて含まれている必要があります。

ビルドの出力

これは PRPL を使用するうえで難しい要件ではありませんが、ビルド プロセスでは 2 つのビルドが生成される場合があります。

  • バンドルされていないビルド。HTTP/2 をサポートするサーバー / ブラウザの組み合わせのために設計されています。キャッシュを最適化しながら、ブラウザが最初に描画するために必要なリソースを配信します。これらのリソースの配信は、<link rel="preload">または HTTP/2 Push を使用して効率的にトリガーできます。

  • バンドルされたビルド。サーバー プッシュをサポートしていないサーバー / ブラウザの組み合わせでアプリケーションを実行するために必要なラウンドトリップを最小限に抑えるよう設計されています。

サーバー ロジックで、各ブラウザに適切なビルドを配信する必要があります。

バンドルされたビルド

HTTP/2 に対応していないブラウザの場合、ビルドプロセスでは、シェル用、各フラグメント用など、一連の異なるバンドルが生成されます。 以下の図は再び、ウェブ コンポーネントを使用して、シンプルなアプリがバンドルされる状況を示しています。

3 つのバンドルされた依存関係が存在する、先ほどと同じアプリの図

2 つ以上のフラグメントで共有される依存関係は、シェルおよび静的な依存関係とバンドルされます。

各フラグメントと共有されていない静的な依存関係は、1 つのバンドルに統合されます。 サーバーはブラウザに応じて、適切なバージョン(バンドルあり / なし)のフラグメントを返す必要があります。 これは、バンドルされているかどうかを把握しなくても、シェルコードが detail-view.html を遅延読み込みできることを意味します。 最も効率的に依存関係を読み込めるかどうかは、サーバーとブラウザ次第です。

バックグラウンド:HTTP/2 および HTTP/2 サーバー プッシュ

HTTP/2 は 1 つの接続で多重接続によるダウンロードが可能であるため、複数の小さなファイルを効率的にダウンロードできます。

HTTP/2 サーバー プッシュを使用すると、サーバーはリソースをあらかじめブラウザに送信できます。

HTTP/2 サーバー プッシュでダウンロードを高速化できる例として、リンクされたスタイルシートを使用して、ブラウザで HTML ファイルを取得する方法について検討してみましょう。

HTTP/1:

  • ブラウザが HTML ファイルを要求します。
  • サーバーが HTML ファイルを返し、ブラウザは解析を開始します。
  • ブラウザが <link rel="stylesheet"> タグを見つけて、スタイルシートの新しいリクエストを開始します。
  • ブラウザがスタイルシートを受信します。

HTTP/2 プッシュ:

  • ブラウザが HTML ファイルを要求します。
  • サーバーが HTML ファイルを返し、同時にスタイルシートをプッシュします。
  • ブラウザが HTML の解析を開始します。ブラウザが ` を見つけるまでに、スタイルシートはすでにキャッシュに読み込まれています。

この最も単純なケースで、HTTP/2 サーバー プッシュによって、1 回の HTTP リクエスト / レスポンスが削減されています。

HTTP/1 では、デベロッパーはリソースをバンドルして、ページのレンダリングに必要な HTTP リクエストの数を削減します。 ただし、バンドルによってブラウザのキャッシュの効率が落ちます。各ページのリソースが 1 つのバンドルに統合されていると、ページがそれぞれ固有のバンドルを取得し、ブラウザは共有リソースを特定できません。

HTTP/2 と HTTP/2 サーバー プッシュの組み合わせでは、実際にバンドルしなくてもバンドルのメリット(レイテンシの短縮)が得られます。 リソースを分けておくことで、効率的なキャッシュが可能になり、ページ間で共有できます。

HTTP/2 プッシュの使用には注意が必要です。ファイルがすでにブラウザのローカル キャッシュに存在したり、帯域幅がいっぱいになっていても、データがブラウザに強制的に送信されます。 使い方を誤ると、パフォーマンスが損なわれる可能性があります。ブラウザがこれらのリクエストの優先順位について適切に判断するための代替手段として、<link rel="preload"> を使用できる場合があります。

まとめ

アプリケーションが高速でインタラクティブ状態に到達するようにするには、ルートのコードをより細かく読み込み、ブラウザで処理を適切にスケジューリングできるようにすると非常に効果的です。 迅速にインタラクティブな状態に移行できる優れたアーキテクチャが求められていますが、PRPL パターンは、実際のモバイル端末でこの目標を達成する方法として興味深い例です。

これはゆとりの問題で、抽出したものの読み込みを完了したら、あとは自分を信頼することです。 入力イベントの送信を阻害する数秒間のスクリプトによってリンクのタップが遅延した場合、それはパフォーマンスについてなんらかの手を打つ必要があるという明確なサインです。 これは現在、大きな JavaScript ライブラリを使用して構築したアプリケーションでよく見られる問題ですが、レンダリングされた UI が機能しているように見えても、実際はそうではないことがあります。

PRPL では、ユーザーが選択したルートをインタラクティブにするために必要最小限の関数のコードを配信できるようにサポートすることで、この課題に対処しています。