PWA 渐进式 web 应用
简介
PWA(Progressive Web App,渐进式网页应用)是一种可以提供类似原生应用体验的网页应用。 通过利用最新的 Web 技术特性,实现跨平台兼容性,并且在桌面和移动设备上都能够以全屏或近似原生应用的方式运行。
特性
- 渐进式:PWA 适用于所有用户,无论他们使用什么浏览器,因为它是以渐进式增强作为核心原则构建的。
- 响应式:它们的界面自适应各种形态的设备:桌面、手机、平板电脑等。
- 离线工作:通过 Service Workers 来缓存应用外壳和数据,在没有网络的情况下也可以使用。
- 感觉像原生应用:PWA 可以添加到设备的主屏幕,发送推送通知,并访问设备功能。
- 始终更新:由于 Service Worker 的更新过程,PWA始终保持最新。
- 安全:通过 HTTPS 提供服务,确保应用数据的传输安全。
- 易找寻:由于是网页应用,所以 PWA 可以通过搜索引擎被发现,与普通网页同样优化 SEO。
- 可链接:通过 URL 容易分享应用,不需要复杂的安装流程。
关键技术
- Service Workers: 脚本工作在浏览器后台,独立于网页,可以拦截和处理网络请求,包括缓存或检索资源。
- Web App Manifest: JSON 文件,描述了个性化起始画面、全屏等展示解决方案以及PWA的外观。
- Application Shell (App Shell): 基础的 HTML/CSS/JS 架构,负责加载用户界面的速度。
- IndexedDB 和 Cache API: 缓存资料与结构,实现离线数据的有效管理。
从零创建一个简单的 PWA 渐进式应用
你如果希望使用脚手架搭建一个完整的 PWA 项目,可以尝试使用 Quasar 框架,这也是 Vue 官方推荐的框架。 (www.quasarchs.com/quasar-cli-...
应用目录如下
- index.html
- manifest.json
- service-worker.js
- icons
- icon-128x128.png
- icon-192x192.png
- icon-256x256.png
- icon-384x384.png
- icon-512x512.png
PWA 应用部署与普通网页基本一致,唯一不同的是 PWA 必须使用 https 协议(localhost 除外)。 windows 系统下可以直接下载 nginx,将 html 下的文件替换成项目文件,运行 nginx 即可(nginx.org/en/download...
代码实现
html
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>PWA渐进式应用</title>
<link rel="manifest" href="./manifest.json">
</head>
<body>
<h1>PWA渐进式应用</h1>
<script>
window.addEventListener("load", () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(function({ installing, waiting, active }) {
if (installing) console.log("正在安装 Service worker");
if (waiting) console.log("已安装 Service worker installed");
if (active) console.log("激活 Service worker");
})
.catch(function(err) {
console.log('Service Worker 注册失败:', err);
});
}
})
</script>
</body>
</html>
json
{
"manifest.json": "配置并引入该文件后即可实现下载,如果需要实现离线使用则需结合 Service Worker",
"参考地址": "https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/manifest.json",
"id": "pwa",
"name": "pwa",
"short_name": "pwa",
"description": "pwa",
"display": "standalone",
"start_url": "/",
"orientation": "portrait",
"background_color": "#aaa",
"theme_color": "#fff",
"icons": [
{
"src": "icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
js
// service-worker.js
// API 可参考 https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API
// 定义您想要缓存的文件列表
const CACHE_NAME = 'FIRSTPWA';
const urlsToCache = [
'/index.html',
'/manifest.json',
'/icons/icon-128x128.png',
'/icons/icon-192x192.png',
'/icons/icon-256x256.png',
'/icons/icon-384x384.png',
'/icons/icon-512x512.png'
];
// 安装 Service Worker 并缓存所有预定义资源
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
// 捕获页面请求,从缓存中提供数据
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// 如果缓存命中直接返回缓存内容,否则继续请求
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
// 更新缓存
self.addEventListener('activate', event => {
const cacheWhiteList = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
// 删除不在白名单中的缓存
if (cacheWhiteList.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});