{"id":24419099,"url":"https://github.com/electroluxcode/pwa_demo","last_synced_at":"2026-01-28T11:35:52.432Z","repository":{"id":267434667,"uuid":"901238759","full_name":"electroluxcode/pwa_demo","owner":"electroluxcode","description":"旧打包文档(sw测试)","archived":false,"fork":false,"pushed_at":"2025-08-09T18:21:06.000Z","size":15394,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-09T20:28:55.222Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://electroluxcode.github.io/pwa_demo/","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/electroluxcode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-10T09:44:54.000Z","updated_at":"2025-08-09T18:21:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"8ea07364-c221-400f-98d2-328e25db3fd0","html_url":"https://github.com/electroluxcode/pwa_demo","commit_stats":null,"previous_names":["electroluxcode/pwa_demo"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/electroluxcode/pwa_demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electroluxcode%2Fpwa_demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electroluxcode%2Fpwa_demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electroluxcode%2Fpwa_demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electroluxcode%2Fpwa_demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/electroluxcode","download_url":"https://codeload.github.com/electroluxcode/pwa_demo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electroluxcode%2Fpwa_demo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28845089,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T10:53:21.605Z","status":"ssl_error","status_checked_at":"2026-01-28T10:53:20.789Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-20T09:18:57.486Z","updated_at":"2026-01-28T11:35:52.427Z","avatar_url":"https://github.com/electroluxcode.png","language":null,"readme":"pwa 示例\n\n开发环境需要把 pwa_demo 换成  docs (manifest.json)\n\n\n### PWA |  service worker\n\n```js\n--1.定义：\nfcm 不能启动意味着消息推送\n移动端 安装 pwa应用需要 梯子（md。极大的心智负担）\n本质安装这个就是 一个chrome_proxy。另外这个东西在手机端吃\n渐进式 web 应用（Progressive Web App）\n渐进式 web 应用 就是 实现了和原生应用相近的用户体验的网页应用\n\nService Worker 是浏览器和网络之间的虚拟代理。 运行在一个与 页面的 JavaScript 主线程 独立的线程上，它没有对 DOM 结构的访问权限，可以在不同上下文间 发送/接收 信息。因为强大，所以 Service Workers 只能在安全的上下文中执行（即 HTTPS ）\n\n--2.示例：  \nif (\"serviceWorker\" in navigator) {\n    // 浏览器支持 Service Worker\n    navigator.serviceWorker\n      .register(\"serviceWorker.js\") // 这里可以接受第二个参数，用于设置 scope 范围\n      .then(function (registration) {\n        // 如果存放在网站根路径下，将会收到该网站的所有 fetch 事件\n        console.log(\"ServiceWorker注册成功: \", registration.scope);\n      })\n      .catch(function (err) {\n        console.log(\"ServiceWorker注册失败: \", err);\n      });\n  }\n\n--3.局限：\n遇到的阻碍：\n第一个是腾讯，微信/QQ——微信/QQ拥有最大的用户群，腾讯要推自家小程序，它不支持PWA就难搞，一个商业app很难无视腾讯背后的流量（除了阿里）。\n第二个，国内浏览器对PWA支持很差，连百度查到的chrome下载，长久以来一直都是停留在很古老版本。\n第三个阻碍，国内的GCM/FCM 基本无法用，其它厂商对web push实现很乱\n\nGoogle为安卓准备了基于Google服务的GCM/FCM推送服务，APP不需要驻留后台，只需要接入到GCM/FCM中，APP就可以借助Google服务器直接向安卓机推送消息。\n\n--4.链式启动是如何解决APP推送问题的?\n\nAPP驻留后台很容易被系统挂城墙\n此景此境下，APP们只能抱团取暖了——既然单个APP很难停留在后台，那么APP之间相互唤起，那就容易多了！开启一个APP后，就拉起另一个抱团的APP，那大家的进程都激活了，推送服务也就顺理成章。(大部分的链式唤醒，都是由于APP们接入了同样的推送SDK。那么为什么会有这个apk呢？\n国内APP们想要实现推送功能，需要借助第三方的推送SDK例如开发者熟知的友盟、极光、个推等等)\n\n--4.开发过程可以在application 中的service workers 和 cache storage去查看\n生命周期 \ninstall\nactivate（清理比较key）\nfetch （自定义缓存）\n更新我们要用 cacheName\n\n--5. 什么是CacheStorage？\nCacheStorage是浏览器中的一种存储机制，用于存储和检索网络请求和响应。它以Request 为key，Response为value去存储请求和响应对象\n\nCacheStorage不是Service Worker API，但它使SW能够缓存网络响应，以便在用户断开与网络的连接时提供脱机功能。\n\n--6.有哪些Service Worker能做但是web worker不能的？\n\nWeb Workers——为Web内容提供在后台线程中运行脚本的简单方法。工作线程可以在不干扰用户界面的情况下执行任务。此外，它们还可以使用XMLHttpRequest执行I/O（尽管responseXML和channel属性始终为空）。创建后，工作人员可以通过将消息发布到该代码指定的事件处理程序中来向创建该代码的JavaScript代码发送消息（反之亦然）。\nService Worker——本质上是充当位于Web app与浏览器和网络（如果可用）之间的代理服务器。它们旨在（除其他外）创建有效的脱机体验，拦截网络请求并根据网络是否可用以及服务器上是否存在更新的资产(assets)来采取适当的操作。它们还允许访问推送通知和后台同步API。\n\n作者：Earl_Lam\n链接：https://juejin.cn/post/6844904052166230030\n来源：稀土掘金\n著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。\n```\n\n\n\n\n\nserveice worker 生命周期\n\n\u003cimg src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d26737a3c0754b4da1e068432657306b~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp\"\u003e\n\n\n\n#### 2.1.43.1 manifest.json\n\n```js\n使用PWA很简单，只需要在HTML中的head中使用link标签引用一个manifest.json文件即可.点击底部工具栏的JSON 选择 json with comments\n{\n  // 应用的名称\n  \"name\": \"Electrolux_docs\",\n  // 简称\n  \"short_name\": \"demo\",\n  // 显示模式 fullscreen（全屏） | standalone(独立) | standalone（最小化） | browser（浏览器）\n  \"display\": \"standalone\",\n  // 启动页\n  \"start_url\": \"/\",  \n  // 主题颜色\n  \"theme_color\": \"#313131\",\n  // 背景颜色\n  \"background_color\": \"#313131\",\n  \"icons\": [\n    {\n      \"src\": \"e.png\",\n      \"sizes\": \"256x256\",\n      \"type\": \"image/png\"\n    }\n  ]\n}\n\u003clink rel=\"manifest\" href=\"manifest.json\" /\u003e\n\n\n```\n\n\n\n#### 2.1.43.2 sw.js 方法\n\n```js\nhtml 的 script标签 中写入.Add to Home Screen，即添加到主屏幕\n\n\nconsole.log('Script loaded!')\n/**\n * self: 表示 Service Worker 作用域, 也是全局变量\n * caches: 表示缓存\n * skipWaiting: 表示强制当前处在 waiting 状态的脚本进入 activate 状态\n * clients: 表示 Service Worker 接管的页面\n * \n */\n\n\n\n//重要：这里定义一个key，如果变化了 那么也会变\nvar cacheStorageKey = 'min'\n\nvar cacheList = [\n  \"/docs/main.css\",\n  \"/docs/e.png\",\n  \"/docs/pwa-fonts.png\",\n]\n//重点：可以在注册完成安装 Service Worker 时, 抓取静态资源写入缓存:\nself.addEventListener('install', function(e) {\n  console.log('Cache event!')\n  e.waitUntil(\n    caches.open(cacheStorageKey).then(function(cache) {\n      //写入内存 \n      console.log('Adding to Cache:', cacheList)\n      return cache.addAll(cacheList)\n    }).then(function() {\n      console.log('Skip waiting!')\n      //skipwaiting为了在页面更新的过程当中,\n      // 新的 Service Worker 脚本能立即激活和生效。\n      return self.skipWaiting()\n    })\n  )\n})\n\n//重要：更新静态资源 可以遍历所有的缓存名称逐一判断决决定是否清除\nself.addEventListener('activate', function(e) {\n  console.log('Activate event')\n  e.waitUntil(\n    console.log(\"sdsd\")\n    // Promise.all(\n    //   caches.keys().then(cacheNames =\u003e {\n    //     return cacheNames.map(name =\u003e {\n    //       if (name !== cacheStorageKey) {\n    //         return caches.delete(name)\n    //       }\n    //     })\n    //   })\n    // ).then(() =\u003e {\n    //   console.log('Clients claims.')\n    //   //在新安装的 Service Worker 中通过调用 self.clients.claim() \n    //   //取得页面的控制权, 这样之后打开页面都会使用版本更新的缓存。\n    //   //旧的 Service Worker 脚本不再控制着页面之后会被停止\n    //   return self.clients.claim()\n    // })\n  )\n})\n\n//重要：处理动态缓存\nself.addEventListener('fetch', function(e) {\n  // console.log('Fetch event:', e.request.url)\n  e.respondWith(\n    caches.match(e.request).then(function(response) {\n      if (response != null) {\n        console.log('Using cache for:', e.request.url)\n        return response\n      }\n      console.log('Fallback to fetch:', e.request.url)\n      return fetch(e.request.url)\n    })\n  )\n})\n\n\n//重要：消息推送\n\n// self.showNotification('Hello World!', {\n//   body: 'This is a notification!',\n//   icon: 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/703a0cee8b0b494eadd27adc61883956~tplv-k3u1fbpfcp-watermark.image?',\n//   actions: [{\n//       action: 'yes',\n//       title: 'Yes'\n//   }, {\n//       action: 'no',\n//       title: 'No'\n//   }]\n// });\n\n// self.addEventListener('notificationclick', (event) =\u003e {\n//   // 判断点击的是哪个按钮\n//   if (event.action === 'yes') {\n//       console.log('yes');\n//   } else if (event.action === 'no') {\n//       console.log('no');\n//   }\n// });\n\n\n\n\n```\n\n\n\n\n\n#### 2.1.43.3 html方法\n\n```html\n在安装Service Worker且用户转至其他页面或刷新当前页面后，Service Worker将开始接收fetch事件\n\n\n\u003chead\u003e\n  \u003ctitle\u003eElectrolux demo\u003c/title\u003e\n  \u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\n  \u003cmeta name=\"viewport\" content=\"width=device-width, user-scalable=no\" /\u003e\n  \u003clink rel=\"manifest\" href=\"/docs/manifest.json\" /\u003e\n  \u003clink rel=\"stylesheet\" type=\"text/css\" href=\"/docs/main.css\"\u003e\n  \u003clink rel=\"icon\" href=\"/docs/e.png\" type=\"image/png\" /\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n  \u003cdiv class=\"revision\"\u003e测试\u003c/div\u003e\n  \u003cimg src=\"/docs/pwa-fonts.png\"\u003e\n  \u003cdiv class=\"main-text\"\u003e\n    Electrolux demo 示例\n  \u003c/div\u003e\n  \u003cdiv class=\"network-message\"\u003e\n    Network:\n    \u003cspan id=\"network-status\" class=\"\"\u003eGood\u003c/span\u003e\n    \u003cbutton id=\"notifications\" onclick=\"addToDesktop()\"\u003e安装\u003c/button\u003e\n  \u003c/div\u003e\n\n\n\n\n  \u003cscript\u003e\n    //这里是进行sw.js 离线缓存的设置，注册service worker\n    if (navigator.serviceWorker != null) {\n      navigator.serviceWorker.register('/docs/sw.js')\n        .then(function (registration) {\n          console.log('Registered events at scope: ', registration.scope);\n        });\n    }\n\n   \n\n    var statusEl = document.querySelector('#network-status')\n    if (!navigator.onLine) {\n      statusEl.classList = ['is-offline']\n      statusEl.innerText = 'Offline'\n    }\n  \u003c/script\u003e\n\n  \u003cscript\u003e\n\n    //首先进行授权\n    Notification.requestPermission().then(function (result) {\n      if (result === 'granted') {\n        console.log(\"已经授权\")\n      }\n    });\n\n    \n    var deferredPrompt = null;\n\n    // 监听beforeinstallprompt事件，该事件在网站满足PWA安装条件时触发，保存安装事件\n    window.addEventListener(\"beforeinstallprompt\", e =\u003e {\n        e.preventDefault();\n        deferredPrompt = e;\n    });\n\n    // 监听appinstalled事件，该事件在用户同意安装后触发，清空安装事件\n    window.addEventListener(\"appinstalled\", () =\u003e {\n        deferredPrompt = null;\n    });\n\n    // 手动触发PWA安装\n    function addToDesktop() {\n      \n        deferredPrompt.prompt();\n    }\n\n\n    \n  \u003c/script\u003e\n\u003c/body\u003e\n```\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felectroluxcode%2Fpwa_demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felectroluxcode%2Fpwa_demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felectroluxcode%2Fpwa_demo/lists"}