桌面端 PWA 应用:

移动端添加到桌面:

1 什么是 PWA

PWA(Progressive Web App - 渐进式网页应用)是一种理念,由 Google Chrome 在 2015 年提出。PWA 它不是特指某一项技术,而是应用多项技术来改善用户体验的 Web App,其核心技术包括 Web App ManifestService WorkerWeb Push 等,用户体验才是 PWA 的核心。

PWA 主要特点如下:

  • 可靠 - 即使在网络不稳定甚至断网的环境下,也能瞬间加载并展现。
  • 用户体验 - 快速响应,具有平滑的过渡动画及用户操作的反馈。
  • 用户黏性 - 和 Native App 一样,可以被添加到桌面,能接受离线通知,具有沉浸式的用户体验。

PWA 本身强调渐进式(Progressive),可以从两个角度来理解渐进式,首先,PWA 还在不断进化,Service Worker、Web App Manifest、Device API 等标准每年都会有不小的进步;其次,标准的设计向下兼容,并且侵入性小,开发者使用新特性代价很小,只需要在原有站点上新增,让站点的用户体验渐进式的增强。相关技术基准线:What makes a good Progressive Web App?。

  • 站点需要使用 HTTPS。
  • 页面需要响应式,能够在平板和移动设备上都具有良好的浏览体验。
  • 所有的 URL 在断网的情况下有内容展现,不会展现浏览器默认页面。
  • 需要支持 Wep App Manifest,能被添加到桌面。
  • 即使在 3G 网络下,页面加载要快,可交互时间要短。
  • 在主流浏览器下都能正常展现。
  • 动画要流畅,有用户操作反馈。
  • 每个页面都有独立的 URL。

2 案例调研

2.1 米哈游 - 崩坏3

访问地址:https://bbs.mihoyo.com/bh3/

PWA:仅支持在 IOS 端添加到桌面。

2.2 阿里速卖通(AliExpress)

访问地址:https://m.aliexpress.com/

PWA:使用 Google Workbox(CDN)

  1. 支持添加到桌面,manifest。
  2. 支持缓存,Service Worker。

2.3 饿了么

访问地址:https://h5.ele.me/msite/#pwa=true

PWA:自研 - PWA 在饿了么的实践经验

  1. 支持添加到桌面,manifest。
  2. 支持缓存和离线访问,Service Worker。

2.4 Instagram

左边原生应用,右边 PWA

访问地址:https://www.instagram.com/

PWA:使用 Google Workbox

  1. 支持添加到桌面,manifest。
  2. 支持缓存,Service Worker。

2.5 Twitter

访问地址:https://mobile.twitter.com/home

PWA:Twitter 自研 - How we built Twitter Lite

  1. 支持添加到桌面,manifest。
  2. 支持缓存和离线访问,Service Worker。

除了正常的静态资源以外,Twitter 把首页也缓存了下来。

离线状态下有很好的用户体验,而不是显示默认的浏览器页面。

3 技术选型(Service Worker)

3.1 使用 Google Workbox 构建 Service Worker

3.1.1 什么是 Workbox

Workbox 是一组库,可以帮助开发者编写 Service Worker,通过 CacheStorage API 缓存资源。当一起使用 Service Worker 和 CacheStorage API 时,可以控制网站上使用的资源(HTML、CSS、JS、图像等)如何从网络或缓存中请求,甚至允许在离线时返回缓存的内容。

3.1.2 如何使用 Workbox

Workbox 是由许多 NPM 模块组成的。首先要从 NPM 中安装它,然后导入项目 Service Worker 所需的模块。Workbox 的主要特性之一是它的路由和缓存策略模块。

路由和缓存策略

Workbox 允许使用不同的缓存策略来管理 HTTP 请求的缓存。首先确定正在处理的请求是否符合条件,如果符合,则对其应用缓存策略。匹配是通过返回真值的回调函数进行的。缓存策略可以是 Workbox 的一种预定义策略,也可以创建自己的策略。如下是一个使用路由和缓存的基本 Service Worker。

import { registerRoute } from 'workbox-routing';
import {NetworkFirst,StaleWhileRevalidate,CacheFirst,
} from 'workbox-strategies';// Used for filtering matches based on status code, header, or both
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
// Used to limit entries in cache, remove entries after a certain period of time
import { ExpirationPlugin } from 'workbox-expiration';// Cache page navigations (html) with a Network First strategy
registerRoute(// Check to see if the request is a navigation to a new page({ request }) => request.mode === 'navigate',// Use a Network First caching strategynew NetworkFirst({// Put all cached files in a cache named 'pages'cacheName: 'pages',plugins: [// Ensure that only requests that result in a 200 status are cachednew CacheableResponsePlugin({statuses: [200],}),],}),
);// Cache CSS, JS, and Web Worker requests with a Stale While Revalidate strategy
registerRoute(// Check to see if the request's destination is style for stylesheets, script for JavaScript, or worker for web worker({ request }) =>request.destination === 'style' ||request.destination === 'script' ||request.destination === 'worker',// Use a Stale While Revalidate caching strategynew StaleWhileRevalidate({// Put all cached files in a cache named 'assets'cacheName: 'assets',plugins: [// Ensure that only requests that result in a 200 status are cachednew CacheableResponsePlugin({statuses: [200],}),],}),
);// Cache images with a Cache First strategy
registerRoute(// Check to see if the request's destination is style for an image({ request }) => request.destination === 'image',// Use a Cache First caching strategynew CacheFirst({// Put all cached files in a cache named 'images'cacheName: 'images',plugins: [// Ensure that only requests that result in a 200 status are cachednew CacheableResponsePlugin({statuses: [200],}),// Don't cache more than 50 items, and expire them after 30 daysnew ExpirationPlugin({maxEntries: 50,maxAgeSeconds: 60 * 60 * 24 * 30, // 30 Days}),],}),
);

这个 Service Worker 使用一个网络优先的策略来缓存导航请求(用于新的 HTML 页面),当它状态码为 200 时,该策略将缓存的页面存储在一个名为 pages 的缓存中。使用 Stale While Revalidate strategy 缓存 CSS、JavaScript 和 Web Worker,将缓存的资源存储在一个名为 assets 的缓存中。采用缓存优先的策略来缓存图像,将缓存的图像存储在名为 images 的缓存中,30 天过期,并且一次只允许 50 个。

预缓存

除了在发出请求时进行缓存(运行时缓存)之外,Workbox 还支持预缓存,即在安装 Service Worker 时缓存资源。有许多资源是非常适合预缓存的:Web 应用程序的起始 URL、离线回退页面以及关键的 JavaScript 和 CSS 文件。

使用一个支持预缓存清单注入的插件(webpack 或 rollup)来在新的 Service Worker 中使用预缓存。

import { precacheAndRoute } from 'workbox-precaching';// Use with precache injection
precacheAndRoute(self.__WB_MANIFEST);

这个 Service Worker 将在安装时预缓存文件,替换 self.__WB_MANIFEST,其中包含在构建时注入到 Service Worker 中的资源。

离线回退

让 Web 应用在离线工作时感觉更健壮的常见模式是提供一个后退页面,而不是显示浏览器的默认错误页面。通过 Workbox 路由和预缓存,你可以在几行代码中设置这个模式。

import { precacheAndRoute, matchPrecache } from 'workbox-precaching';
import { setCatchHandler } from 'workbox-routing';// Ensure your build step is configured to include /offline.html as part of your precache manifest.
precacheAndRoute(self.__WB_MANIFEST);// Catch routing errors, like if the user is offline
setCatchHandler(async ({ event }) => {// Return the precached offline page if a document is being requestedif (event.request.destination === 'document') {return matchPrecache('/offline.html');}return Response.error();
});

如果用户处于离线状态,则返回缓存的离线页面的内容,而不是生成一个浏览器错误。

有了 Workbox,可以利用 Service Worker 的力量来提高性能,并给您的站点提供独立于网络的优秀的用户体验。

3.2 自研 Service Worker

自研 Service Worker 更加灵活、可控,但是因为需要考虑到各种兼容,研发成本较高。可以参考在线图书《PWA 应用实战》。

4 技术实践(Service Worker)

4.1 使用 CLI

安装 Workbox:

npm install workbox-cli -Dnpx workbox --help

按照引导配置 workbox-config.js

npx workbox wizard

根据配置生成 Service Worker 程序:

npx workbox generateSW workbox-config.js

由于实际静态资源是挂载在 CDN 上面,需要修改预渲染资源的前缀。

Workbox CLI - generateSW - Configuration

// A transformation that prepended the origin of a CDN for any URL starting with '/assets/' could be implemented as:const cdnTransform = async (manifestEntries) => {const manifest = manifestEntries.map(entry => {const cdnOrigin = 'https://example.com';if (entry.url.startsWith('/assets/')) {entry.url = cdnOrigin + entry.url;}return entry;});return {manifest, warnings: []};
};

更多缓存配置可查阅官方文档。

4.2 使用 Webpack

安装:

npm install workbox-webpack-plugin --save-dev

Webpack 配置:

// Inside of webpack.config.js:
const WorkboxPlugin = require('workbox-webpack-plugin');
// Version info...
const id = `${page}-v${version}`;module.exports = {// Other webpack config...plugins: [// Other plugins...// WIKI https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-webpack-plugin.GenerateSW#GenerateSWnew WorkboxPlugin.GenerateSW({cacheId: `${id}-gsw`,// Do not precache imagesexclude: [/\.(?:png|jpg|jpeg|svg)$/, 'service-wroker.js'], // Page need refresh twice.// target dirswDest: `../dist/${page}/service-worker.js`,skipWaiting: true,clientsClaim: true,// Define runtime caching rules.// WIKI https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.RuntimeCachingEntry// Example https://gist.github.com/jeffposnick/fc761c06856fa10dbf93e62ce7c4bd57runtimeCaching: [// icon images{// Match any request that ends with .png, .jpg, .jpeg or .svg.urlPattern: /^https:\/\/cdn.example.com\/platform/, // /\.(?:png|jpg|jpeg|svg)$/,// Apply a cache-first strategy.handler: 'CacheFirst',options: {// Use a custom cache name.cacheName: `${id}-icon-images`,// Only cache 50 images, and expire them after 30 daysexpiration: {maxEntries: 50},// Ensure that only requests that result in a 200 status are cachedcacheableResponse: {statuses: [0, 200]}}},// note images & others{// Match any request that ends with .png, .jpg, .jpeg or .svg.urlPattern: /^https:\/\/image.example.com/, // /\.(?:png|jpg|jpeg|svg)$/,// Apply a cache-first strategy.handler: 'CacheFirst',options: {// Use a custom cache name.cacheName: `${id}-note-images`,// Only cache 50 images, and expire them after 30 daysexpiration: {maxEntries: 50,maxAgeSeconds: 60 * 60 * 24 * 30 // 30 Days},// Ensure that only requests that result in a 200 status are cachedcacheableResponse: {statuses: [0, 200]}}}]});]
};

页面中触发 Service Work:

<script>
// Check that service workers are supported
if ('serviceWorker' in navigator) {// Use the window load event to keep the page load performantwindow.addEventListener('load', () => {navigator.serviceWorker.register('/service-worker.js');});
}
</script>

5 添加到桌面方案

5.1 manifest.json 配置

{"name": "不知不问","short_name": "不知不问","description": "yyds","start_url": "/?entry_mode=standalone","display": "standalone","orientation": "portrait","background_color": "#F3F3F3","theme_color": "#F3F3F3","icons": [{"src": "https://mazey.cn/fav/logo-dark-circle-32x32.png","sizes": "32x32","type": "image/png"},{"src": "https://mazey.cn/fav/logo-dark-circle-144x144.png","sizes": "144x144","type": "image/png"},{"src": "https://mazey.cn/fav/logo-dark-circle-152x152.png","sizes": "152x152","type": "image/png"},{"src": "https://mazey.cn/fav/logo-dark-circle-180x180.png","sizes": "180x180","type": "image/png"},{"src": "https://mazey.cn/fav/logo-dark-circle-192x192.png","sizes": "192x192","type": "image/png"},{"src": "https://mazey.cn/fav/logo-dark-circle-512x512.png","sizes": "512x512","type": "image/png"}],"scope": "/"
}

5.2 <head> 配置

为网站配置开屏图片、状态栏等。

<!--Mazey's favicon begin-->
<link rel="shortcut icon" type="image/png" href="https://mazey.cn/fav/logo-dark-circle-transparent-144x144.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://mazey.cn/fav/logo-dark-circle-transparent-32x32.png">
<link rel="apple-touch-icon" sizes="144x144" href="https://mazey.cn/fav/logo-dark-circle-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="https://mazey.cn/fav/logo-dark-circle-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="https://mazey.cn/fav/logo-dark-circle-180x180.png">
<link rel="apple-touch-icon" sizes="192x192" href="https://mazey.cn/fav/logo-dark-circle-192x192.png">
<link rel="apple-touch-icon" sizes="512x512" href="https://mazey.cn/fav/logo-dark-circle-512x512.png">
<!--Mazey's favicon end-->
<!--Mazey's pwa manifest.json-->
<link rel="manifest" href="/wp-content/themes/polestar/manifest.json">
<!-- 开机图片 - begin -->
<!-- iPhone Xs Max (1242px × 2688px) -->
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)" href="https://i.mazey.net/asset/read/cat-lovers-1242x2688.jpg" sizes="1242x2688">
<!-- iPhone Xr (828px x 1792px) -->
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)" href="https://i.mazey.net/asset/read/cat-lovers-828x1792.jpg" sizes="828x1792">
<!-- iPhone X, Xs (1125px x 2436px) -->
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)" href="https://i.mazey.net/asset/read/cat-lovers-1125x2436.jpg" sizes="1125x2436">
<!-- iPhone 8, 7, 6s, 6 (750px x 1334px) -->
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" href="https://i.mazey.net/asset/read/cat-lovers-750x1334.jpg" sizes="750x1334">
<!-- iPhone 8 Plus, 7 Plus, 6s Plus, 6 Plus (1242px x 2208px) -->
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3)" href="https://i.mazey.net/asset/read/cat-lovers-1242x2208.jpg" sizes="1242x2208">
<!-- iPhone 5 (640px x 1136px) -->
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" href="https://i.mazey.net/asset/read/cat-lovers-640x1136.jpg" sizes="640x1136">
<!-- 开机图片 - end -->
<!-- Touch Bar区域显示的网站图标 -->
<link rel="mask-icon" href="https://mazey.cn/fav/logo-dark-circle.svg" color="#F3F3F3">
<!-- 主题色 = manifest.json theme_color -->
<meta name="theme-color" content="#F3F3F3">
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- 状态栏颜色 default/black/black-translucent -->
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<!-- 应用名 -->
<meta name="apple-mobile-web-app-title" content="不知不问">
<!-- 在Windows 8上,我们可以将网站固定在开始屏幕上,而且支持个性化自定义色块icon和背景图片。这个标签是用来定义色块的背景图的。色块图应该为144*144像素的png格式图片,背景透明。 -->
<meta name="msapplication-TileImage" content="https://mazey.cn/fav/logo-dark-circle-transparent-144x144.png">
<!-- 同前一个元数据msapplication-TileImage类似,这个功能是用来设置颜色值,个性化自定义色块(磁贴)icon -->
<meta name="msapplication-TileColor" content="#F3F3F3">

开屏图片尺寸总结:

屏幕尺寸 倍数 图片尺寸
1024x1366(512x683) x2 2048x2732
834x1194(417x597) x2 1668x2388
768x1024(384x512) x2 1536x2048
834x1112(417x556) x2 1668x2224
810x1080 x2 1620x2160
428x926(214x463) x3 1284x2778
390x844 x3 1170x2532
375x812 x3 1125x2436
414x896 x3 1242x2688
414x896 x2 828x1792
414x736 x3 1242x2208
375x667 x2 750x1334
320x568 x2 640x1136

版权声明

本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者后除和本文原始地址:https://blog.mazey.net/2675.html

(完)

PWA 实践/应用(Google Workbox)相关推荐

  1. 【技术】PWA实践 - 应用激活与安装

    文章目录 你能用这项技术做什么? 适合人群 你可以学到什么 应用激活与安装 激活与安装 Manifest 注意 Service Worker Storage 管理应用 Demo 本章参考资料 你能用这 ...

  2. 老虎证券web端PWA实践总结

    历时两个月,PWA功能终于在web端稳定落地使用,网站 web.itiger.com. 从最新研究到落地上线,遇到不少坑:开发过程中也参考了不少资料,但总有那么几个是没有答案,需要自己摸索结果的.所以 ...

  3. 机器学习最佳实践,Google机器学习43条军规:

    本文是对Rules of Machine Learning: Best Practices for ML Engineering一文的翻译和解读.看过我翻译文章的同学知道我翻译文章一般都不太老实,没有 ...

  4. 【编程实践】Google Guava 极简教程

    前言 Guava 工程包含了若干被 Google 的 Java 项目广泛依赖 的核心库,我们希望通过此文档为 Guava 中最流行和最强大的功能,提供更具可读性和解释性的说明. 适用人群 本教程是基础 ...

  5. 工作实践 之 Google Guava 工具集的使用 ,提高效率

    Google Guava是什么? Google Guava 工程包含了若干被Google的java项目广泛依赖的核心库,例如:集合,缓存,原生类型支持,并发库,通用注解,字符串,I/O等等.所有这些工 ...

  6. 前端性能和加载体验优化实践(附:PWA、离线包、内存优化、预渲染)

    一.背景:页面为何会卡? 1.1 等待时间长(性能) 项目本身包/第三方脚本比较大. JavaScript 执行阻塞页面加载. 图片体积大且多. 特别是对于首屏资源加载中的白屏时间,用户等待的时间就越 ...

  7. 【PWA学习与实践】(3) 让你的WebApp离线可用

    <PWA学习与实践>系列文章已整理至gitbook - PWA学习手册,文字内容已同步至learning-pwa-ebook.转载请注明作者与出处. 本文是<PWA学习与实践> ...

  8. 我的新书《PWA入门与实践》上市了

    前言 我初接触PWA是在2017年年初,当时参加了一个前端分享会,其中一个主题就是与PWA相关的,介绍了PWA的Service Worker和安装到桌面的能力,以及这门技术未来的发展趋势,听完这个分享 ...

  9. 使用 workbox 协助构建 PWA 应用

    使用 workbox 协助构建 PWA 应用 1. 说明 workbox 是 GoogleChrome 团队推出的一套解决方案,提供站点离线访问能力,可以更方便.更简单的解决 Service Work ...

最新文章

  1. php sql server临时表,SQLServer中临时表与表变量的区别分析
  2. Ajax — 第五天
  3. 正则表达式 RegularExpressions
  4. linux 按键驱动中断 rockchip_7.自己写中断方式按键驱动程序(详解)
  5. 学生选课管理系统(python)
  6. ArcGIS | 01小技巧-矢量按某个字段重分类
  7. 读书印记 - 《批判性思维工具》
  8. c语言仿宋gb2312字体,【仿宋gb2312字体下载】仿宋gb2312字体官方下载 免费版-七喜软件园...
  9. C语言实现简单打字游戏
  10. MVVM?瞎搞一波?
  11. 怎么把线稿提取出来_PS怎么扣抠线稿?Adobe Photoshop CS6如何提取清晰的线稿
  12. matlab 年积日与年月日转换,空间大地测量与GPS导航定位时间系统相互转换,格里高利时通用时儒略日,GPS时,年积日相互转换的源代码程序...
  13. Control.Invoke用法注意事项
  14. 在办公室给智能手机充电怎么做最安全
  15. android 微信引导界面,昨天下午,微信启动页面图换了,但却害苦了安卓手机用户!...
  16. 微软 Windows 网络邻居
  17. 轻量级Kubernetes之k3s:4:离线安装与部署
  18. 从‘0’开始完成一个阻抗分析仪(初篇——原理讲解)
  19. [笔经/面经]面试热问——你的职业规划是什么?
  20. C# 高级编程个人笔记搬运 一(基础知识)

热门文章

  1. 灵能传输(贪心,前缀和)
  2. 前目的地罗伯森是谁_前目的地 - 隐藏的时间线
  3. 为什么华盛顿在圣诞节来临前上演关门
  4. Linux安装MySQL 5.7
  5. 堆排序,用一种清新脱俗的方式
  6. Leaf-美团分布式id生成系统
  7. IOS 如何获取app更新链接 如【itms-apps://itunes.apple.com/cn/app/id1362432761?mt=8】
  8. 组网技术:TP-Link无线路由器设置图解
  9. 如何对网站用户进行实名认证(使用阿里云服务)
  10. MongoDB账户密码设置