在同一域名上构建多个渐进式 Web 应用

如何构建多个 PWA,利用同一域名,让用户意识到它们属于同一组织或服务。

多源站点中的渐进式 Web 应用博文中,Demián 讨论了在尝试构建包含所有来源的单个渐进式 Web 应用时,基于多个来源构建的站点所面临的挑战。

这种类型的站点架构的一个示例是电子商务站点,其中:

  • 首页位于 https://www.example.com
  • 类别页面托管在 https://category.example.com
  • 产品详情页面位于 https://product.example.com

正如文章中所讨论的,同源策略施加了多项限制,阻止了跨源共享 Service Worker、缓存和权限。因此,我们强烈建议避免使用这种类型的配置,对于那些已经以这种方式构建站点的用户,请考虑在可能的情况下迁移到单源站点架构。

Diagram showing a site divded into multiple origins and showing that technique is discouraged when building PWAs.
当尝试构建统一的渐进式 Web 应用时,请避免对同一站点的站点部分使用不同的来源。

在这篇文章中,我们将着眼于相反的情况:我们将分析公司希望利用同一域名提供多个 PWA,并让用户意识到这些 PWA 属于同一组织或服务的情况,而不是跨不同来源的单个 PWA。

您可能已经注意到,我们正在使用不同的但相互关联的术语,如域名和来源。在继续之前,让我们回顾一下这些概念。

技术术语

  • 域名:域名系统 (DNS) 中定义的任何标签序列。例如:comexample.com 都是域名。
  • 主机名:解析为至少一个 IP 地址的 DNS 条目。例如:www.example.com 将是一个主机名,example.com 如果它有一个 IP 地址,也可以是一个主机名,而 com 永远不会解析为 IP 地址,因此它永远不会是一个主机名。
  • 来源:方案、主机名和(可选)端口的组合。例如,https://www.example.com:443 是一个来源。

顾名思义,同源策略对来源施加了限制,因此我们将在整篇文章中主要使用“来源”一词。尽管如此,我们有时会使用“域名”或“子域名”来描述正在使用的技术,以便创建不同的“来源”。

在某些情况下,您可能想要构建独立的应用程序,但仍然将它们标识为属于同一组织或“品牌”。重用同一域名是建立这种关系的好方法。例如:

  • 一个电子商务站点想要创建一个独立的体验,让卖家管理他们的库存,同时确保他们明白这属于用户购买产品的主网站。
  • 一个体育新闻站点想要为一个主要的体育赛事构建一个特定的应用程序,让用户通过通知接收他们最喜欢的比赛的统计数据,并将其作为渐进式 Web 应用安装,同时确保用户认识到这是新闻公司构建的应用程序。
  • 一家公司想要构建单独的聊天、邮件和日历应用程序,并希望它们作为与公司名称相关的单独应用程序工作。
Avoid using different origins for site sections of the same site when trying to build a unified Progresive Web App.
拥有 example.com 的公司想要提供三个独立的应用程序或 PWA,使用同一域名来建立它们之间的关系。

使用单独的来源

在这些情况下,推荐的方法是让每个概念上不同的应用程序都位于其自己的来源上。

如果您想在所有应用程序中使用同一域名,您可以使用子域名来实现。例如,一家提供多个互联网应用程序或服务的公司可以将邮件应用程序托管在 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 的应用程序。

使用不同的来源可确保应用程序之间的隔离,这意味着它们中的每一个都可以独立管理不同的浏览器功能,包括:

  • 可安装性:每个应用程序都有自己的清单,并提供自己的可安装体验。
  • 存储:每个应用程序都有自己的缓存、本地存储,以及基本上所有形式的设备本地存储,而无需与其他应用程序共享。
  • Service Worker:每个应用程序都有自己的 Service Worker 用于已注册的作用域。
  • 权限:权限也按来源划分作用域。因此,用户将确切地知道他们正在为哪个服务授予权限,并且诸如通知之类的功能将正确归因于每个应用程序。

在多个独立的 PWA 的用例中,创建这种程度的隔离是最理想的,因此我们强烈推荐这种方法

如果子域名上的应用程序想要相互共享本地数据,它们仍然可以通过 Cookie 来实现,或者对于更高级的场景,它们可以考虑通过服务器同步存储。

ALT_TEXT_HERE
通过使用子域名在不同的来源中构建不同的 PWA 是一种好的做法。

使用同一来源

第二种方法是在同一来源上构建不同的 PWA。这包括以下场景:

非重叠路径

托管在同一来源上的多个 PWA 或概念上的“Web 应用程序”,具有非重叠路径。例如:

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

重叠/嵌套路径

同一来源上的多个 PWA,其中一个的作用域嵌套在另一个的作用域内

  • https://example.com/(“外部应用程序”)
  • https://example.com/app/(“内部应用程序”)

Service Worker API 和清单格式允许您执行上述任一操作,使用路径级作用域。然而,在这两种情况下,使用同一来源都会带来许多问题和限制,其根源在于浏览器不会完全将这些视为不同的“应用程序”,因此不建议使用此方法

ALT_TEXT_HERE
不建议使用路径(重叠或不重叠)在同一来源下提供两个独立的 PWA(“app1”、“app2”)。

在下一节中,我们将更详细地分析这些挑战,以及如果无法使用单独的来源可以做些什么。

多个同源 PWA 的挑战

以下是同源方法常见的一些实际问题:

  • 存储:Cookie、本地存储和所有形式的设备本地存储在应用程序之间共享。因此,如果用户决定擦除一个应用程序的本地数据,它将擦除来自该来源的所有数据;无法为单个应用程序执行此操作。请注意,Chrome 和其他一些浏览器会在卸载其中一个应用程序时主动提示用户擦除本地数据,这也会影响该来源上其他应用程序的数据。另一个问题是应用程序还必须共享其存储配额,这意味着如果其中任何一个占用太多空间,另一个将受到负面影响。
  • 权限:浏览器权限与来源绑定。这意味着如果用户向一个应用程序授予权限,它将同时应用于该来源上的所有应用程序。这听起来可能是一件好事(不必多次请求权限),但请记住:如果用户阻止一个应用程序的权限,它将阻止其他应用程序请求该权限或使用该功能。请注意,即使浏览器权限每个来源只需要授予一次,另一方面,系统级权限也必须每个应用程序授予一次,无论多个应用程序是否指向同一来源。
  • 用户设置:设置也是按来源设置的。例如,如果两个应用程序具有不同的字体大小,并且用户想要仅在其中一个应用程序中调整缩放以进行补偿,他们将无法在不将设置应用于其他应用程序的情况下执行此操作。

这些挑战使得难以鼓励这种方法。尽管如此,如果您无法使用单独的来源(例如子域名),如使用单独的来源部分所述,从我们提出的两个同源选项中,强烈建议使用非重叠路径,而不是重叠/嵌套路径。

如前所述,本节中讨论的挑战对于两种同源方法都是常见的。在下一节中,我们将深入探讨为什么使用重叠/嵌套路径是最不推荐的策略的细节。

重叠/嵌套路径的其他挑战

重叠/嵌套路径方法(其中 https://example.com/ 是外部应用程序,https://example.com/app/ 是内部应用程序)的另一个问题是,内部应用程序中的所有 URL 实际上都将被视为外部应用程序和内部应用程序的一部分。

实际上,这会带来以下问题:

  • 安装推广:如果用户访问内部应用程序(例如,在 Web 浏览器中),当外部应用程序已安装在用户的设备中时,浏览器将不会显示安装推广横幅,并且不会触发 BeforeInstallPrompt 事件。原因是浏览器将检查并查看当前页面是否属于已安装的应用程序,并且它将得出结论,它是。对此的解决方法是手动安装内部应用程序(通过“创建快捷方式”浏览器菜单选项),或者先安装内部应用程序,然后再安装外部应用程序。
  • 通知Badging API:如果外部应用程序已安装但内部应用程序未安装,则来自内部应用程序的通知和标记将错误地归因于外部应用程序(这是已安装应用程序的最近封闭作用域)。此功能在两个应用程序都安装在用户设备上的情况下正常工作。
  • 链接捕获:外部应用程序可能会捕获属于内部应用程序的 URL。如果外部应用程序已安装但内部应用程序未安装,则尤其如此。同样,外部应用程序中链接到内部应用程序的链接将不会链接捕获到内部应用程序中,因为它们被认为在外部应用程序的作用域内。此外,在 ChromeOS 和 Android 上,如果这些应用程序添加到 Play 商店(作为 Trusted Web Activity),则外部应用程序将捕获所有链接。即使安装了内部应用程序,操作系统仍将为用户提供在外部应用程序中打开它们的选项。

结论

在本文中,我们研究了开发人员可以在同一域名内构建多个相互关联的渐进式 Web 应用的不同方式。

总而言之,我们强烈建议使用不同的来源(例如,通过使用子域名)来托管独立的 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

照片由 Tim MossholderUnsplash 上拍摄