Creating PWAs

如果您是Web开发人员,您可能已经了解渐进式Web应用程序(PWA)或已经实现了自己的应用程序。 如果您不熟悉,本文将深入概述渐进式Web应用程序的实现原理,以及它们在现代Web开发中的重要程度。

渐进式Web应用程序自推出就被定义为响应式、可独立连接、APP般轻盈、安全、模块化、高度自定义、免安装、打开即用的Web体验。这是一个冗长的描述,如果用一句话简要的概括:我认为PWA只是一个具有良好用户体验的Web应用程序,仅此而已。

为了更清晰地理解这个定义,让我们来一探其核心原则。在此之前,你可能已经熟悉了其中的一些,但我保证,你并非全部了解。

渐进式 Web 应用的原则

Responsive(响应式)

对于Web开发人员,这意味着应用程序中显示的元素在不同的屏幕大小上可自行缩放,以便适应屏幕尺寸。对于设计人员,这意味着更高的性能,比如应用程序是否快速响应用户交互、事件、页面加载等。构建高性能的应用程序是产品最核心的竞争力,渐进式Web应用程序自然也同样遵循这一法则,尤其是针对 Web开发人员方面。响应式 Web 应用程序在任何设备上都具备同样良好的适应能力,无论屏幕是宽、窄、短,甚至是曲面,应用程序布局都会自适应,满足用户的最佳使用体验。

Connectivity-independent(独立连接)

由于我们讨论的是Web应用程序,因此在应用程序生命周期的某个时刻一定需要网络连接,特别是首次访问应用程序时。当网络不可用或速度太慢时,应用程序应做到不影响用户体验,即不应向用户显示空白页面或400错误,这在PWA出现以前难以做到,但PWA利用浏览器的存储机制使这成为可能。

App-like(app的样式)

我认为“原生app-like”是描述这一原则的最好方式,即本地化应用程序的外观和感觉就像是用于使用外部设备,某些应用程序专门针对iOS或Android等平台构建,然而之前的Web应用程序则无法提供相同的体验,尤其是在移动设备上。 PWA则不同,渐进式Web应用程序旨在提供所有设备类似的使用体验,用户可以从手机切换到笔记本电脑,在类似的UI下,轻松完成相同的任务。

Fresh (不断更新)

我想把它称为A.F.A.P - 应用程序中的数据应尽可能保持最新。如果新数据可用且与客户端相关,则需要使用最新数据更新应用程序。管理网络请求和浏览器存储对于提供出色的用户体验和在客户端上保持最新内容至关重要。

Safe (安全第一)

安全第一!如果应用程序不能保证数据的安全性,应用程序有什么用处?市场大多数 Web 应用程序中都包含了只应为通信方所知的客户敏感信息。因此,保护应用程序中的隐私数据是必要的。PWA采取了简单而有效的方式:使用HTTPS协议为网络流量添加一层安全防护。

Discoverable (可发现)

应用程序应该很容易在网上/应用商店中找到,这就是应用程序的可发现性。如果搜索引擎找不到应用程序,将怎样发掘潜在用户?应用程序搜索清单可以提供帮助。它在识别浏览器的应用程序方面起着重要作用,包含了有关应用程序的信息,即名称、作者和说明。应用程序搜索清单同样有助于识别安装在其设备上的PWA。

Re-engageable (可重用)

可重复使用的应用程序可以发送推送通知来拉回用户。目的是让用户知道应用程序推出了一些他们可能感兴趣的更新点。我们习惯于智能手机和原生移动应用程序,但浏览器也通过Push和Notification API支持这一特点。

Installable (可安装)

渐进式Web应用程序可以直接安装到移动设备的主屏幕上。这主要是移动浏览器功能,使用Chrome,您也可以在桌面上执行此操作。 iOS Safari也支持此功能,因此如果你有iPhone,你可以加入PWA阵营。 安装Web应用程序真的很酷,您无需通过App Store或Google Play Store等市场下载应用程序。只需访问该网站,点击“添加到主屏幕”选项,该应用程序将立即显示在您的主屏幕上。

Linkable (可链接)

可链接的Web应用程序是可共享的,因此托管在专用域上的应用程序不适用。 您只需要一个URL即可。

创建渐进式Web应用程序

上述原则在实践中如何实现?与标准Web应用程序相比,创建PWA只需要三个基本要求:

  1. 通过HTTPS提供Web应用程序
  2. 添加应用程序清单文件
  3. 使用服务器

HTTPS是现代Web应用程序的基本协议,渐进式Web应用程序也不例外。

应用程序清单是一个JSON文件,其中包含有关应用程序的元数据。它只提供基本信息。在Android应用程序中,清单文件要复杂得多,可能需要在整个应用程序开发过程中进行更改。 Web应用程序清单涉及较少,并且在创建后不需要经常更新,因为它们不包含配置参数或依赖项。

创建渐进式Web应用程序的最后一步是添加服务器。奇迹发生的地方是它启用了离线功能。对于PWA来说,服务器只是另一个JavaScript文件 - 一个非常强大的JavaScript文件。它实际上在浏览器中的一个单独的线程上运行,因此服务工作线程上的执行不会中断主应用程序线程。这使开发人员可以灵活地通过并发性创建更好的用户体验。服务器可以处理网络请求/响应和缓存。从主线程中删除此工作将应用程序逻辑与数据管理和网络相关的操作分开。

如您所见,这里的大多数渐进式应用都涉及服务器实现。但在实现之前,必须考虑应用程序的体系结构。

PWA应用程序结构

应用程序shell是描述应用程序基础结构的概念。它包含您的应用程序需要运行的所有静态文件。在Web开发的上下文中,这将包括HTML,CSS,JavaScript和图像文件。

内容是可以在应用程序的整个生命周期中更改的数据。它被排除在应用程序shell之外,因为它是动态的,并且在加载应用程序时可能会过时。它通常通过API服务公开,易于查询。需要在应用程序中管理此内容,以确保根据请求提供最新鲜的内容。 服务器承担此责任。

在首次加载应用程序时,应缓存应用程序shell文件,以便应用程序可以在没有网络连接的情况下工作。

一个好的PWA将避免显示此屏幕出现:

Progressive Web Application - an Overview

当页面未加载时,用户将完全脱离应用程序。显然,与网络相关的问题会影响用户体验,但不应该让用户远离应用程序。这个想法类似于原生体验,即使应用程序中显示空白屏幕,PWA也可以让用户参与应用程序。为了在网络较慢时让用户保持参与,您可以使用动画或提供具备视觉反馈的客户端交互,就像带有小拼图或3D交互模型的刷新按钮一样简单。要有创意!

使用应用程序shell模型的一个缺点是其性能。它确实减慢了初始加载时间;但是,这可以改善。要减少加载应用程序shell文件所需的时间,您可以尝试缩小代码(以减小文件大小)、捆绑文件(以最小化网络请求的数量)、删除未使用的代码。您可以在需要时将此删除的代码发送给客户端。这将根据要求而有所不同。

这里描述的架构非常常见。如果您已经开发了其他平台的应用程序,您可能会认识到类似的设计结构。例如,需要访问网络的移动应用程序遵循类似的方法与服务器进行通信。通常有一些Factory类处理网络请求和响应。 Factory类提供了一个抽象层,如果异步生成,则效果最佳。应用程序逻辑不必等待请求。它可以允许用户继续并在请求完成时通知他们,可以通过分离数据访问实用程序和UI逻辑来简化测试。

使用App Shell模型是一个很好的起点,但它不是渐进式Web应用程序的要求。如果您有现有的应用程序,则可以评估应用程序的哪些部分使用最多,并优化初始加载。如果95%的用户群仅使用25%的应用程序,那么仅下载和缓存25%的应用程序(最常用的应用程序)可能最有意义。用户可以根据需要,选择下载和缓存其他部分,这完全取决于用户与您应用程序的交互方式。

服务请求

服务请求的实现因应用程序而异,但在应用程序中开始使用它们时应该了解一些事项。之前,我提到服务请求在浏览器中的不同线程上运行。这意味着它具有管理生命周期的能力,就像您的应用程序一样。

以下是主要的服务器生命周期事件:

  • 注册

当应用程序第一次加载到浏览器中时,将发生这一请求。 这不是真正的Service Worker事件,因为此时服务不存在于浏览器上下文中,但这是重要的一步。 应用程序的主JavaScript文件应检查浏览器是否支持ServiceWorker API,如果是,请注册服务请求。注册成功后,将下载服务文件,然后开始安装。

if ('serviceWorker' in navigator) { 

  navigator.serviceWorker.register('./service-worker.js'); 
}

此代码在浏览器中注册服务请求(如果支持)。 下一个事件将在服务工作文件中处理。

  • 安装

Install事件是服务器可以自己处理的第一个事件。它在注册/下载后立即启动。 完成安装后,最好开始缓存静态资源,因为安装事件只发生一次。

self.addEventListener('install', function(e) {
    e.waitUntil( // waitUntil() from ExtendableEvent
        caches.open(cacheName).then(function(cache) {
                console.log('[ServiceWorker] Caching app shell');
                return cache.addAll(filesToCache);
        })
    );
});

waitUntil()方法将在安装事件完成后开始执行promise。

  • 激活

activate事件表示已安装服务器。 激活完成后,服务器将获得对主应用程序的控制权。 当服务变为“活动”时,它还将检查缓存的资源,并在数据过期时更新数据。 这可能需要进行额外的网络请求以进行对比,但这应该不是问题,因为应用程序不会受到请求执行的影响。 服务器还能够在处于活动状态时对Fetch,Push和Message等功能事件执行操作。

注意:注册并安装服务请求后,它将存在于浏览器中,直到用户将其删除。 当用户关闭应用程序时,不会自动删除该文件,浏览器将每24小时下载一次配置文件,以避免错误/陈旧的代码。

  • 抓取

只要调用来自主应用程序的网络请求,就会触发Fetch事件。 发生这种情况时,服务器将对该请求负责。 如果请求的信息已被缓存,则服务器可以返回该信息并完全绕过网络。 或者它仍然可以发送请求,将响应与缓存的信息进行对比,并在必要时进行更新。最后,选择最适合用户的策略。

Push和Message事件也是服务器在活动时侦听的事件。 它们可用于实现推送通知和同步发送的数据。

正如您所看到的,服务器是完成大部分工作的核心,也是使Web应用程序不断发展的重要组成部分。 它为您的应用程序提供网络代理和存储管理服务,是改善Web应用程序用户体验的绝佳工具。

构建渐进式Web应用程序

尝试构建PWA。如果您已经拥有Web应用程序,那么很容易上手。我们目前正在撰写一篇描述如何使用前端开发工具包WijmoJS构建PWA的文章。同时,这也是如何将现有应用程序迁移到渐进式标准的最佳示例。