同じドメインに複数のプログレッシブ ウェブアプリを構築する

Chase Phillips
Demián Renzulli
Demián Renzulli
Matt Giuca
Matt Giuca

マルチオリジン サイトのプログレッシブ ウェブアプリに関するブログ投稿で、Demian は、複数のオリジンで構築されたサイトが、それらすべてを包含する単一のプログレッシブ ウェブアプリを構築しようとする際に直面する課題について説明しました。

このタイプのサイト アーキテクチャの例としては、次のような e コマースサイトがあります。

  • ホームページは https://www.example.com にあります。
  • カテゴリ ページは https://category.example.com でホストされています。
  • https://product.example.com の商品詳細ページ。

記事で説明したように、同一オリジン ポリシーにはいくつかの制限があり、オリジン間でサービス ワーカー、キャッシュ、権限を共有することはできません。そのため、このタイプの構成は避けることを強くおすすめします。また、この方法でサイトを構築している場合は、可能な限り単一オリジン サイト アーキテクチャへの移行を検討してください。

サイトが複数のオリジンに分割されていることを示す図。この手法は PWA の構築では推奨されていません。
統一されたプログレッシブ ウェブアプリを構築しようとする場合は、同じサイトのセクションに異なるオリジンを使用しないようにします。

この記事では、異なるオリジンにまたがる単一の PWA ではなく、同じドメイン名を利用して複数の PWA を提供し、それらの PWA が同じ組織またはサービスに属していることをユーザーに認識させたい企業のケースを分析します。

お気づきかもしれませんが、ドメインやオリジンなど、異なるが相互に関連する用語を使用しています。先に進む前に、これらのコンセプトを確認してください。

技術用語

  • ドメイン: ドメイン ネーム システム(DNS)で定義されているラベルの任意のシーケンス。たとえば、comexample.com はドメインです。
  • ホスト名: 1 つ以上の IP アドレスに解決される DNS エントリ。たとえば、www.example.com はホスト名になります。example.com は IP アドレスがあればホスト名になります。com は IP アドレスに解決されないため、ホスト名にはなりません。
  • オリジン: スキーム、ホスト名、ポート(省略可)の組み合わせ。たとえば、https://www.example.com:443 はオリジンです。

その名のとおり、同一オリジン ポリシーはオリジンに制限を課すため、この記事では主にこの用語を使用します。ただし、さまざまな「オリジン」を作成するために使用される手法を説明する際には、「ドメイン」または「サブドメイン」という用語が使用されることがあります。

独立したアプリを構築しながら、同じ組織または「ブランド」に属するものとして識別したい場合があります。同じドメイン名を再利用することは、その関係を確立するうえで有効な方法です。次に例を示します。

  • e コマース サイトで、販売者が在庫を管理できるスタンドアロンのエクスペリエンスを作成したいと考えています。その際、ユーザーが商品を購入するメインのウェブサイトに属していることを販売者に理解してもらう必要があります。
  • スポーツ ニュースサイトが、主要なスポーツ イベント専用のアプリを構築したいと考えています。ユーザーが通知を使用してお気に入りの試合の統計情報を受け取れるようにし、プログレッシブ ウェブアプリとしてインストールできるようにしながら、ユーザーがニュース会社によって構築されたアプリとして認識できるようにしたいと考えています。
  • 会社が、チャット、メール、カレンダーのアプリを個別に作成し、会社名に関連付けられた個別のアプリとして機能させたいと考えています。
統合されたプログレッシブ ウェブアプリを構築しようとする場合は、同じサイトのサイト セクションに異なるオリジンを使用しないでください。同じドメインを使用して、それらの関係を確立します。

別のオリジンを使用する

このような場合におすすめの方法は、概念的に異なる各アプリを独自のオリジンで公開することです。

すべてのサイトで同じドメイン名を使用する場合は、サブドメインを使用します。たとえば、複数のインターネット アプリやサービスを提供する企業は、メールアプリを https://mail.example.com で、カレンダー アプリを https://calendar.example.com でホストし、ビジネスのメイン サービスを https://www.example.com で提供できます。別の例として、https://footballcup.example.com で開催されるサッカーの選手権などの重要なスポーツ イベント専用の独立したアプリを作成したいスポーツ サイトがあります。このアプリは、https://www.example.com でホストされているメインのスポーツ サイトとは別に、ユーザーがインストールして使用できます。このアプローチは、顧客が会社のブランドで独自の独立したアプリを作成できるプラットフォームにも役立つ可能性があります。たとえば、販売者が https://merchant1.example.comhttps://merchant2.example.com などで独自の PWA を作成できるアプリなどです。

異なるオリジンを使用すると、アプリ間の分離が保証されます。つまり、各アプリは次のブラウザ機能を個別に管理できます。

  • インストール可能性: 各アプリには独自の Manifest があり、独自のインストール可能なエクスペリエンスを提供します。
  • ストレージ: 各アプリには独自のキャッシュ、ローカル ストレージ、デバイスローカル ストレージのすべての形式が用意されており、他のアプリと共有されることはありません。
  • サービス ワーカー: 各アプリには、登録されたスコープ用の独自のサービス ワーカーがあります。
  • 権限: 権限もオリジンごとにスコープ設定されます。これにより、ユーザーはどのサービスに権限を付与しているかを正確に把握でき、通知などの機能が各アプリに適切に割り当てられます。

このような分離は、複数の独立した PWA のユースケースで最も望ましいものであり、このアプローチを強くおすすめします

サブドメインのアプリがローカルデータを共有したい場合は、Cookie を使用して共有できます。より高度なシナリオでは、サーバーを介してストレージを同期できます。

サブドメインを使用して、異なるオリジンで異なる PWA をビルドすることは、良い方法です。

同じオリジンを使用する

2 つ目のアプローチは、同じオリジンに異なる PWA を構築することです。これには、次のシナリオが含まれます。

重複しないパス

同じオリジンでホストされ、パスが重複しない複数の PWA または概念的な「ウェブアプリ」。次に例を示します。

  • https://example.com/app1/
  • https://example.com/app2/

重なり合うパスまたはネストされたパス

同じオリジンに複数の PWA があり、そのうちの 1 つのスコープがもう 1 つのスコープ内にネストされている場合:

  • https://example.com/(「外部アプリ」)
  • https://example.com/app/(「内部アプリ」)

サービス ワーカー API とマニフェスト形式を使用すると、パスレベルのスコープを使用して、どちらも実行できます。ただし、どちらの場合も、同じオリジンを使用すると多くの問題や制限が発生します。その根本原因は、ブラウザがこれらを別個の「アプリ」として完全に認識しないことにあります。そのため、このアプローチは推奨されません

同じオリジンでパス(重複の有無を問わず)を使用して 2 つの独立した PWA(「app1」、「app2」)を提供することは推奨されません。

次のセクションでは、これらの課題について詳しく分析し、別のオリジンを使用できない場合にできることについて説明します。

複数の同一オリジン PWA の課題

以下に、同一オリジン アプローチに共通する実用的な問題を示します。

  • ストレージ: Cookie、ローカル ストレージ、デバイスローカル ストレージのすべての形式はアプリ間で共有されます。そのため、ユーザーが 1 つのアプリのローカルデータを消去すると、オリジンからすべてのデータが消去されます。1 つのアプリに対してこれを行う方法はありません。Chrome や他のブラウザでは、アプリの 1 つをアンインストールする際に、ローカルデータを消去するようユーザーに積極的に促すことに注意してください。これは、オリジンの他のアプリのデータにも影響します。もう 1 つの問題は、アプリがストレージ割り当てを共有する必要があることです。つまり、どちらかのアプリが過剰な容量を使用すると、もう一方のアプリに悪影響が及ぶことになります。
  • 権限: ブラウザの権限はオリジンに関連付けられています。つまり、ユーザーが 1 つのアプリに権限を付与すると、そのオリジンのすべてのアプリに同時に適用されます。これは良いことのように聞こえるかもしれませんが(権限を複数回リクエストする必要がない)、ユーザーが 1 つのアプリの権限をブロックすると、他のアプリがその権限をリクエストしたり、その機能を使用したりできなくなることを覚えておいてください。ブラウザの権限はオリジンごとに 1 回付与するだけで済みますが、システムレベルの権限は、複数のアプリが同じオリジンを指しているかどうかに関係なく、アプリごとに 1 回付与する必要があります。
  • ユーザー設定: 設定はオリジンごとに設定されます。たとえば、2 つのアプリでフォントサイズが異なり、ユーザーがそのうちの 1 つのズームのみを調整して補正したい場合、他のアプリにも設定を適用しないと調整できません。

このような課題があるため、このアプローチを推奨することは困難です。ただし、別のオリジンを使用するセクションで説明したように、別のオリジン(サブドメインなど)を使用できない場合は、提示した 2 つの同一オリジン オプションのうち、重複するパスやネストされたパスよりも、重複しないパスを使用することを強くおすすめします。

前述のように、このセクションで説明する課題は、同一オリジン アプローチの両方に共通するものです。次のセクションでは、重複したパスやネストされたパスを使用することが最もおすすめできない戦略である理由について詳しく説明します。

重なり合うパスとネストされたパスに関するその他の課題

パスの重複とネストのアプローチ(https://example.com/ が外部アプリ、https://example.com/app/ が内部アプリ)の追加の問題は、内部アプリのすべての URL が実際には外部アプリと内部アプリの両方の一部と見なされることです。

実際には、次のような問題が発生します。

  • インストール プロモーション: ユーザーがインナーアプリ(ウェブブラウザなど)にアクセスしたときに、アウターアプリがすでにユーザーのデバイスにインストールされている場合、ブラウザにはインストール プロモーション バナーは表示されず、BeforeInstallPrompt イベントもトリガーされません。これは、ブラウザが現在のページがすでにインストールされているアプリに属するかどうかを確認し、属すると判断するためです。この問題を回避するには、内側のアプリを手動でインストールする(ブラウザのメニュー オプションの [ショートカットを作成] を使用する)か、外側のアプリの前に内側のアプリをインストールします。
  • 通知バッジ API: 外側のアプリはインストールされているが内側のアプリはインストールされていない場合、内側のアプリからの通知とバッジは、外側のアプリ(インストールされているアプリの最も近い囲みスコープ)に誤って関連付けられます。この機能は、両方のアプリがユーザーのデバイスにインストールされている場合に適切に動作します。
  • リンクのキャプチャ: 外側のアプリが内側のアプリに属する URL をキャプチャする可能性があります。これは、外側のアプリはインストールされているが、内側のアプリはインストールされていない場合に特に起こりやすくなります。同様に、外部アプリ内の内部アプリにリンクするリンクは、外部アプリのスコープ内と見なされるため、内部アプリへのリンク キャプチャは行われません。また、ChromeOS と Android では、これらのアプリが Google Play ストアに追加されると(信頼できるウェブ アクティビティとして)、外部アプリがすべてのリンクをキャプチャします。内部アプリがインストールされている場合でも、OS はユーザーに外部アプリで開く選択肢を提供します。

まとめ

デベロッパーが同じドメイン内で互いに関連する複数のプログレッシブ ウェブアプリを構築する方法について説明しました。

まとめると、独立した PWA をホストするには、別のオリジン(サブドメインの使用など)を使用することを強くおすすめします。これらを同じオリジンでホストすると、ブラウザがこれらを別個のアプリとして完全に認識しないため、多くの問題が発生します。

  • 別のオリジン: 推奨
  • 同じオリジン、重複しないパス: 非推奨
  • 同じオリジン、重複するパス、ネストされたパス: 強く推奨されません

異なるオリジンを使用できない場合は、重複しないパス(https://example.com/app1/https://example.com/app2/ など)を使用することを強くおすすめします。重複するパスやネストされたパス(https://example.com/(外部アプリ用)や https://example.com/app/(内部アプリ用)など)を使用するよりも、重複しないパスを使用する方が望ましいです。

参考情報

技術的なレビューと提案をしてくださった Joe Medley、Dominick Ng、Alan Cutter、Daniel Murphy、Penny McLachlan、Thomas Steiner、Darwin Huang に感謝いたします。