Drupal 开发者 Progressive Web Apps 指南

这是一个针对 Drupal 站点 PWA 实施的概述方法,但当然也有其他具有类似设计的选项。
3 位读者喜欢这篇文章。
Digital creative of a browser on the internet

以下文章是我在 Drupalcon 和 Drupalcamp 上关于 Progressive Web Apps 实施演示的配套材料。

Progressive Web Apps (PWA) 得到了包括 Google 和 Microsoft 在内的一些顶级科技公司的支持,他们的共同目标是“Web 应用程序应该能够做到 iOS、Android 或桌面应用程序可以做的任何事情。” PWA 可以在不同的阶段为企业增加价值。所有项目都有局限性,无论是开发资源、时间表、预算还是技术债务。即使拥有“无限资源”,从单个代码库开发应用程序,使用常用的 Web 技术,也可以实现更顺畅、更合理的发布周期。

免责声明

  • PWA 是在 Web 浏览器中结合使用的不同技术的集合,旨在创建“类似应用程序”的体验。
  • 此信息是从架构师的角度选择和实施各种技术以构建产品的观点。
  • 以下是在应用商店发布 Drupal 网站的高级端到端概述。每个部分都可以是一篇深入的博客文章。
  • 这些技术是针对 Drupal 编写的,但您可以将其中许多技术应用于所有 Web 应用程序。

什么是 PWA?

What is PWA

(Alex Borsody, CC BY-SA 4.0)

PWA 实施的优势

  • 提高 Lighthouse 分数和 SEO。
  • 单一代码库。
  • 无摩擦测试。
  • 开发周期的即时反馈循环。
  • 使用现有的 PaaS 部署工作流程,包括 Acquia、Pantheon、Platform.sh 等。
  • 使用 Web 技术,这些技术是广大开发人员熟悉的技能。
  • 提供唯一的跨平台开发解决方案,可提供全面的桌面体验。
  • 提供无限的自定义设计选项,而无需依赖跨平台框架有限的 UI 组件。

本文介绍了一些 PWA 部署的基本要点。在架构师和开发人员层面都有许多细节需要考虑。以下是讨论的主题

  • PWA 最低要求和 Drupal PWA 模块作为起点。
  • 在应用商店发布。
  • 关于如何使您的 PWA 感觉像应用程序的一切须知。

Drupal.org 上的 PWA 模块

Drupal PWA 模块是一个解决方案,它生成一个用于缓存策略和离线功能的服务工作线程。它的辅助功能还生成一个 manifest.json,因此一旦安装,它将满足PWA 的基本要求,开箱即用。

模块的服务工作线程中具有为 Drupal 特定行为提供独特解决方案的功能,尽管您也可以将这些解决方案应用于 Drupal 之外的应用程序。

Drupal PWA module

(Alex Borsody, CC BY-SA 4.0)

离线缓存

使用服务工作线程进行离线缓存是定义 PWA 的功能之一。

以下图片总结了服务工作线程如何充当代理(位于客户端和互联网/Web 服务器之间)来拦截来自浏览器的 HTTP 请求。

在首次请求 /about 页面期间,浏览器访问网络,并在从服务器返回 200 响应后,Javascript 服务工作线程调用 cache.put() 将 HTML 和所有资源存储在Cache API中。

Offline caching example in service worker

(Alex Borsody, CC BY-SA 4.0)

在第二次访问时,服务工作线程完全绕过网络,并从用户浏览器中的 Cache API 存储中提供页面,从而立即加载页面。它也可以离线加载页面。

Second visit to site

(Alex Borsody, CC BY-SA 4.0)

浏览器可以预缓存页面,使其在用户访问之前甚至在离线状态下加载,以便立即加载。但是,由于在 Drupal 中,CSS/JS 文件名在压缩后会更改,因此该解决方案必须解决在服务工作线程预缓存这些资源之前识别它们的问题。它通过内部请求管理面板中设置的 URL 并从 DOM 中提取资源来实现这一点。这允许服务工作线程安装事件从这些文档中获取所有 CSS/JS 和图像,以存储在 Cache API 中。然后,即使在用户从未首次访问过这些页面,完整页面也可以离线查看并立即加载。

Service worker

(Alex Borsody, CC BY-SA 4.0)

Offline caching demo

(Alex Borsody, CC BY-SA 4.0)

下面,我从管理面板中设置的 URL 中获取所有资源,以便稍后注入到服务工作线程预缓存资源数组中。在 D8 中,我更改了请求以使用 Drupal::httpClient(),这是 D7 中 drupal_http_request() 的更新版本,并且是 PHP Guzzle 库的包装器。

 foreach ($pages as $page) {
      try {
        // URL is validated as internal in ConfigurationForm.php.
        $url = Url::fromUserInput($page, ['absolute' => TRUE])->toString(TRUE);
        $url_string = $url->getGeneratedUrl();
        $response = \Drupal::httpClient()->get($url_string, array('headers' => array('Accept' => 'text/plain')));

此代码匹配所有需要的资源

// Get all DOM data.
      $dom = new \DOMDocument();
      @$dom->loadHTML($data);

      $xpath = new \DOMXPath($dom);
      foreach ($xpath->query('//script[@src]') as $script) {
        $resources[] = $script->getAttribute('src');
      }
      foreach ($xpath->query('//link[@rel="stylesheet"][@href]') as $stylesheet) {
        $resources[] = $stylesheet->getAttribute('href');
      }
      foreach ($xpath->query('//style[@media="all" or @media="screen"]') as $stylesheets) {
        preg_match_all(
          "#(/(\S*?\.\S*?))(\s|\;|\)|\]|\[|\{|\}|,|\"|'|:|\<|$|\.\s)#ie",
          ' ' . $stylesheets->textContent,
          $matches
        );
        $resources = array_merge($resources, $matches[0]);
      }
      foreach ($xpath->query('//img[@src]') as $image) {
        $resources[] = $image->getAttribute('src');
      }
    }

下面,您可以看到浏览器中输出的处理后的 serviceworker.js 文件中的最终结果。服务工作线程中的变量被替换为要缓存的资源的路径。

Final test of offline caching

(Alex Borsody, CC BY-SA 4.0)

卸载时回调

该模块提供了另一个巧妙的功能——卸载时的负责任清理。该模块向模块创建的 URL 发送请求。如果 URL 不存在,则表示该模块已被卸载。然后,服务工作线程取消注册自身并删除用户浏览器上留下的所有相关缓存。

// Fetch phone-home URL and process response.
  let phoneHomeUrl = fetch(PWA_PHONE_HOME_URL)
  .then(function (response) {
    // if no network, don't try to phone-home.
    if (!navigator.onLine) {
      console.debug('PWA: Phone-home - Network not detected.');
    }

    // if network + 200, do nothing
    if (response.status === 200) {
      console.debug('PWA: Phone-home - Network detected, module detected.');
    }


    // if network + 404, uninstall
    if (response.status === 404) {
      console.debug('PWA: Phone-home - Network detected, module NOT detected. UNINSTALLING.');
// Let SW attempt to unregister itself.
      Promise.resolve(pwaUninstallServiceWorker());
    }

    return Promise.resolve();
  })
  .catch(function(error) {
    console.error('PWA: Phone-home - ', error);
  });
};

测试说明

在开发环境中禁用该模块,因为它提供了一个额外的缓存层。对于 CSS 或其他具有缓存优先策略的资源,推送到生产环境的任何更改都应随后增加服务工作线程版本以清除缓存。

您可以在此 PWA 模块文档页面上找到有关服务工作线程的其他调试步骤。

在 Android 上可以使用 Chrome 控制台在移动设备上进行远程调试,这可能会有所帮助。

2.x 版本

2.x 和 7.2x 版本将服务工作线程移植到 Workbox,您可以在其中设置缓存策略。在这里,为不同的资源类型和路由设置缓存策略从仅使用 Javascript Fetch API 的大约 30 行代码简化为大约 5 行代码。有些人可能对库有抵触情绪,但这是 Google 对 PWA 采取的方向。

Workbox 缓存策略与其他缓存层(如 Varnish)中的策略类似。例如,默认情况下,图像资源和字体设置为“缓存优先”,因此它们始终可以立即提供。HTML 最好实现为 stale-while-revalidate

Workbox and PWA module

(Alex Borsody, CC BY-SA 4.0)

Workbox 中还有一些功能,例如后台同步,其中失败的 post 请求将在重新联机后重试。

Offline cache

(Alex Borsody, CC BY-SA 4.0)

有关服务工作线程可以执行的操作以及它可能有所帮助的所有用例的更多信息,请查看 GitHub 上的W3 Service Workers Demo repo

将您的 Web 应用程序放入应用商店

PWA Builder 是一个由 Microsoft 驱动的 Web 应用程序,您可以在其中输入您的 URL,它会生成提交到应用商店所需的一切。

对于 Android,它使用 TWA;对于 iOS,它使用 WebKit 的 WKWebView 将您的 Web 应用程序包装在原生 SWIFT 代码中。这些是我自 2013 年以来一直在使用的技术,那时 Drupal 还是一项热门技术,并被初创公司使用。拥有移动优化的 Drupal 网站的企业希望将它们放在应用商店中。在 Android TWA 之前,开发人员使用 Webview,而在 WKWebView 之前,有 UIWebView。

最近,PWA Builder 使用 WKWebView 添加了一个针对 iOS 的解决方案,这证实了我认为这是将您的 PWA 放入 App Store 的最佳选择。Maximilian Firtman 也在他的课程“使用 Vue 创建 Progressive Web Apps”中揭示了这一点,我购买该课程是为了了解他对这个问题的解答。

PWA 模块提供了通过 PWA Builder 运行所需的一切

  • 对于 Android,它创建一个轻量级的 .apk/.aap,使用 TWA 提交到 Play 商店,大小为 800kb。
  • 对于 iOS,它将您的网站包装在 WKWebView 中以提交到 App Store。

我整理的 PWA Builder 的实时演示在这里。 [[编辑 - 缺少链接]]

Android 和 TWA

Google 和 Chromium 团队目前是 PWA 最强大的驱动力。因此,TWA 专门设计用于将您的 PWA 放入 Play 商店。相反,WKWebView 本质上是 Apple 不明确支持的变通方法。但是,WKWebView 非常强大,即使 Apple 没有宣传这一点或对其功能进行太多文档说明。

Trusted Web Activity 本质上是一个全屏运行并带有状态栏和加载屏幕的 Chrome 进程。该线程与您手机上的 Chrome 应用在同一进程中运行。例如,如果您在 Chrome 浏览器上登录,您将在您的 TWA 应用上登录。为了消除由此可能造成的任何混淆,TWA 团队添加了一个“toast”,这意味着用户首次打开应用时,会显示一条通知“在 Chrome 中运行”。这仅在首次安装应用时发生。对于某些团队来说,这种烦恼足以让他们放弃 TWA 而改用 WebView 类;但是,Google 不鼓励这样做,因为您会失去 Chrome Web 浏览器中内置的一切。

Google 关于使用 TWA 的主要观点

  • Chrome 功能完整。
  • 比 Webview 更快。
  • 常青(始终是最新的 Chrome 版本)。

其他有用的功能。

  • Chrome 处理无摩擦 OAuth 请求。
  • 与首选浏览器共享 Cookie、本地存储和保存的设置。

下面是使用 TWA 而不是 Webview 包装器时获得的一切的比较图表。

Google TWA

(Alex Borsody, CC BY-SA 4.0)

Webkit:WKWebView

在 App Store 上发布需要考虑几个方面。WKWebView 本质上是一种变通方法,而不是 Apple 明确认可的启动原生应用程序的方法。这带来了一些注意事项。最重要的是要注意 Apple 的最低功能指南

根据我的经验,如果您尽一切努力使您的 Web 应用程序“像应用程序”一样具有有用的功能,您将被批准。使用 Webkit API 来增强您的 Web 应用程序是提供网站之外的其他功能的另一种方式。

一种技术是根据 start_url 设置 Cookie。例如,添加一个参数,如 myapp.com?ios_app 并设置一个 Cookie 以确定单独的样式表或自定义逻辑。

考虑以下示例实现。

注意:此技术不应与 Apple 有限的添加到主屏幕支持混淆,您通常会在 Apple + PWA 中听到这种支持。我不会介绍这一点,因为它不是用户期望的体验。

PWA Builder 提供了将网站包装在 WKWebView 中以提交到 App Store 所需的最低功能。对于生物识别或推送通知等功能,您需要 WKWebView 的自定义实现。

在下面的图形中,您可以看到提供的源文件。然后,您可以轻松地在 XCode 中编译您的应用程序并将其提交到应用商店。

Source code

(Alex Borsody, CC BY-SA 4.0)

PWA Builder 提供:

  • 使用 wKWebView.scrollView.bounces = false 时,在滚动出视图时不会反弹
  • 服务工作线程支持
  • 快捷方式 URL 捕获
  • 允许的导航范围
  • 状态栏自定义
  • 来自 manifest 属性的启动画面
  • 来自 JS 代码的 iOS 应用程序感知
  • Mac Store 支持

WKWebView 的自定义实现可以提供

  • 推送通知:通过发布与 Drupal UID 匹配的设备 ID 可以实现推送通知,UID 可以从 URL /user/{uid}/edit 中提取,例如。
  • 生物识别:生物识别在除 user/login 和 user/register 之外的所有页面上实现,并且 Cookie 的最大过期时间已延长。每次应用程序关闭并重新打开时都会显示生物识别。
  • WKUIDelegate:呈现原生 UI 元素,例如警报、输入或上下文菜单。
  • evaluateJavaScript():执行任何 Javascript。这里的可能性是无限的。
  • 使用关联域进行密码管理:在您的 /.well-known 目录中放置一个公钥对将允许您的原生应用程序信任您的网站并自动填充密码。

查看 README.md of WKWebView+,这是一个我正在开发的旨在轻松将此增强功能集成到任何 iOS PWA 中的项目。

WKWebView 的缺点

在实施 WKWebView 之前,请注意以下事项

  • 前端开发人员需要进行思维模式的转变才能正确调试 PWA。尽管它依赖于 Web 技术,但仍存在学习曲线。
  • 如果没有原生 iOS 开发人员,某些功能将无法实现。但是,WKWebView+ 的设计旨在解决这个问题。
  • 尽管 Apple 和 PWA 的前景看起来很乐观,但与往常一样,您仍然受制于下一个 Safari 版本。

展望未来

TWA 的许多功能仅在基于 Chromium 的浏览器上可用。Webkit mobile/WKWebView 滞后。这种滞后包括推送通知、“添加到主屏幕”和整体 Web 浏览器标准。Maximilian Firtman 的博客目前是最新 Safari 更新摘要的最佳资源之一,即使它们未在发行说明中公布

乐观的前景是 WKWebView 基于开源项目 Webkit,并且在 Chromium 和 WebKit 的开发人员之间存在合作。任何人都可以创建问题和拉取请求。通常,已经在 Chrome 中实现的功能都有提交给 Webkit 的补丁,这些补丁的作用相同。

使其像应用程序

服用所有正确维生素的网站A PWA 本质上是 Web 技术的集合,这些技术结合在一起使您的 Web 体验像应用程序一样,就好像该网站“服用了所有正确的维生素”。下面我确定了构成良好 PWA 的要点

  • UX/UI:视觉问题解决是使您的网站感觉像应用程序的核心。一位具有设计和细节眼光(例如动画、输入/字体大小和滚动问题)的出色 CSS 开发人员至关重要。
  • 与类似应用程序的增强功能保持同步:保持前端代码更新并与 WebKit/Chrome 兼容需要研究和定期更新,尤其是在发布新版本的 iPhone 时。
  • 实施扩展的 Web 功能:Chromium 团队不断改进浏览器体验。这可以在Project Fugu(总体 Web 功能项目)中进行跟踪。关于 PWA 最接近全面的文档是在 web.dev 上。
  • 页面速度:我介绍了使用服务工作线程进行缓存,但是还有无数其他技术和技巧。

类似应用程序的增强功能的一些示例包括使用 Web 开发人员常用的 HTML/CSS/JS 技术,然后使它们易于实施、测试和部署。您可以在此处找到使用许多这些建议的 Web 应用程序的良好示例。

建议包括

  • Javascript 触摸事件:禁用捏合缩放并添加滑动/多点触控手势。
  • CSS
    • 缩小/优化 CSS 并应用 Lighthouse 建议。
    • “类似应用程序”的输入/字体大小,并确保一切都适合视口;使其在视觉上看起来像一个应用程序。
    • 巧妙地使用预加载器。
  • 利用 Cookie:根据应用程序启动 URL 设置 Cookie。
  • HTML 属性
  • Ajax API (Drupal 特定), Websockets, 或 SPA 框架。
  • iPhone 特定建议
iPhone X status bar

(Alex Borsody, CC BY-SA 4.0)

总结

PWA 汇集了不同的技术,以在 Web 浏览器中创建类似应用程序的体验。我概述了一种针对 Drupal 站点的 PWA 实施方法,但当然也有其他具有类似设计的选项。PWA 的哪些实施可能有助于您组织的用户体验?

查看 WKWebView+ 的 README.md,这是一个我正在开发的旨在轻松将此增强功能集成到任何 iOS PWA 中的项目。 

Ionic 是 Cordova 的精神继承者,是一个流行的框架,它也利用 WKWebView 来构建原生 iOS 应用。

标签
Alex Borsody CarbonPay
我是一名软件开发人员,拥有超过 15 年的经验,并尝试弥合可靠的成熟技术与现代进步之间的差距。作为一名架构师,我专注于将不同的技术和方法结合在一起,以创建最高效的团队。

3 条评论

感谢您的文章!我一直很喜欢 Drupal 社区中“有一个模块可以做到这一点”的想法,对于 Progressive Web Apps 这样的主题,像 pwa 这样的模块是该领域巨大的起点加速器。虽然我已经有一年没有进行 Drupal 开发了,但 Web Platform API 的未来非常光明,尤其是在 Drupal 10 及更高版本中。

感谢您与我们分享如此有用的博客。我一定会将此网站加入书签,并将此博客分享给我的同事。
此致,Viaana。最佳 laravel 开发服务提供商。

我很荣幸看到您的这篇文章,非常感谢您。 csgo 账号

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 获得许可。
© . All rights reserved.