无痛 PWA index.html sw.js

2025-06-10

无痛 PWA

索引.html

sw.js

免责声明:PWA 仍在不断发展,本文可能很快就会过时

可安装的 PWA 由以下部分组成:

  • 一个 HTML 页面,包含一些特定的<meta><link>标签
  • 服务工作脚本(sw.js),它将缓存您的资产以供离线使用。
  • 一些桌面和启动画面的图标
  • a manifest.json,它将向安装程序描述您的 PWA。

最小 manifest.json 示例

{
  "name": "Name",
  "short_name": "Short",
  "theme_color": "#1d3557",
  "background_color": "#ededed",
  "display": "standalone",
  "start_url": "./",
  "icons": [
    {
      "src": "192x192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "512x512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

它的主要缺点manifest.json是它只是重复您已经设置的内容index.html(图标、名称、主题颜色......)。

一个更简单的解决方案是在注册 serviceWorker 时从这些标签自动生成它:

索引.html

<!doctype html>
<html lang=en>
<meta charset="UTF-8">
<title>title</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#317EFB"/>
<meta name="short-name" content="short"/>
<meta name="background-color" content="#FFFFFF"/>
<meta name="display" content="standalone"/>
<meta name="description" content="description"/>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<link rel="apple-touch-icon" href="192x192.png">
<link rel="splash-icon" href="512x512.png">
<link rel="worker" href="sw.js">
<script type=module defer>
const qsa=s=>[...document.querySelectorAll(s)];
const i=(s,x)=>({src:qsa(`[rel=${s}-icon]`)[0].href,type:"image/png",sizes:`${x}x${x}`});
//TODO: submit this code to iojscc
navigator.serviceWorker&&navigator.serviceWorker.register(qsa('[rel=worker]')[0].href)
.then(sw=>document.head.appendChild(Object.assign(document.createElement("link"),
{rel:"manifest",href:'data:,'+JSON.stringify(qsa('meta[name]').reduce((a,m)=>
(a[m.name.replace(/-/g,'_')]=encodeURIComponent(m.content),a),{start_url:sw.scope,
name:qsa('title')[0].innerText,icons:[i('apple-touch',192),i('splash',512)]}))})));
</script>

<h1>I'm PWA</h1>
Enter fullscreen mode Exit fullscreen mode

sw.js

const cacheList = ["./"]; // add more if needed
const cacheName = "app-42";
self.addEventListener('install', e => e.waitUntil(caches.open(cacheName).then(cache => cache.addAll(cacheList).then(() => self.skipWaiting()))));
self.addEventListener('activate', e => e.waitUntil(self.clients.claim()));
self.addEventListener('fetch', e => e.respondWith(caches.open(cacheName).then(cache => cache.match(e.request, {ignoreSearch: true})).then(response => (e.request.cache !== 'only-if-cached' || e.request.mode === 'same-origin') ? (response || fetch(e.request)) : response)));
Enter fullscreen mode Exit fullscreen mode

您将获得完美的审计分数(如果您的服务器支持 HTTP/2)

替代文本

鏂囩珷鏉ユ簮锛�https://dev.to/yne/painless-pwa-5hao
PREV
IDE——初学者的陷阱!
NEXT
每个 Web 开发人员都应该访问的 8 个网站