feat: add service-worker plugin

This commit is contained in:
tiddlygit-test 2020-10-16 22:27:28 +08:00
parent 353bfc25e8
commit 6c37677c2a
6 changed files with 231 additions and 1 deletions

View file

@ -0,0 +1,165 @@
<link rel="manifest" href="manifest.webmanifest" />
<script type="text/javascript">
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
);
function register(config) {
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
const swUrl = 'service-worker.js';
if (isLocalhost) {
// This is running on localhost. Let's do additional checks to see if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
console.log('Register service worker');
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
console.log('Service worker is speeding up this wiki.')
registration.onupdatefound = () => {
console.log('New content is found, prepare to fetch', registration);
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but normally the previous service worker will still serve the older
// content until all client tabs are closed.
// but we have set self.skipWaiting() in the service worker, so just inform user to reload the page to take effect.
console.log('New content is available and will be used when after refresh or refetch');
// Execute callback, prepare an info to inform user refresh here.
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (response.status === 404 || (contentType != null && contentType.indexOf('javascript') === -1)) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log('No internet connection found. App is running in offline mode.');
});
}
function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then((registration) => {
registration.unregister();
})
.catch((error) => {
console.error(error.message);
});
}
}
function informUserToReloadToGetLatestContent() {
const body = document.querySelector('body');
const infoElement = document.createElement('div');
infoElement.className = 'ask-user-reload';
infoElement.innerHTML =
navigator.language === 'zh-CN'
? '新内容已准备好,点击此处刷新页面更新到新版。'
: 'New content available. Click here to Refresh this page to get update.';
infoElement.onclick = () => location.reload();
infoElement.onKeyDown = () => location.reload();
infoElement.tabindex = 1;
infoElement.role = 'button';
const closeElement = document.createElement('div');
closeElement.className = 'ask-user-reload-close';
closeElement.innerHTML = navigator.language === 'zh-CN' ? '关闭 ×' : 'close ×';
closeElement.onclick = () => body.removeChild(infoElement);
closeElement.onKeyDown = () => body.removeChild(infoElement);
closeElement.tabindex = 0;
closeElement.role = 'button';
infoElement.appendChild(closeElement);
body.appendChild(infoElement);
}
register({ onUpdate: informUserToReloadToGetLatestContent });
</script>
<style>
.ask-user-reload {
padding: 25px;
position: absolute;
bottom: 10px;
right: 5px;
background: wheat;
z-index: 9999;
cursor: alias;
}
.ask-user-reload-close {
padding: 5px;
position: absolute;
top: 0;
right: 0;
cursor: pointer;
font-weight: bold;
}
</style>

View file

@ -0,0 +1,4 @@
creator: LinOnetwo
tags: $:/tags/RawMarkup
title: $:/plugins/linonetwo/service-worker/load-service-worker.html
type: text/html

View file

@ -0,0 +1,9 @@
{
"title": "$:/plugins/linonetwo/service-worker",
"description": "Use service worker to cache content, make it works even offline, and can be add to the desktop as an App.",
"author": "LinOnetwo",
"core-version": ">=5.1.22",
"plugin-type": "plugin",
"version": "0.0.1",
"list": "readme"
}

View file

@ -0,0 +1,51 @@
title: $:/plugins/linonetwo/service-worker/readme
created: 20200414135748497
modified: 20200602062349232
creator: LinOnetwo
type: text/vnd.tiddlywiki
!! Usage
After install, you have to publish your wiki as a HTTPS website to make it work.
!!! Make sure to include all necessary step in the build process
Add following files to your `/public` folder after build, you can use a script to copy them to the build folder after the wiki build process:
1. Add a `manifest.webmanifest` like:
```json
{
"background_color": "white",
"theme_color": "white",
"description": "Meme of LinOnetwo 林一二的模因和想法 - TiddlyWiki 非线性的知识库和博客",
"display": "standalone",
"icons": [
{
"src": "/TiddlyWikiIconBlack.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "/TiddlyWikiIconWhite.png",
"sizes": "144x144",
"type": "image/png"
}
],
"name": "TiddlyWiki",
"short_name": "Wiki",
"lang": "zh-CN",
"start_url": "/",
"scope": "/"
}
```
Make sure icon size is at least 144x144. And change all necessary fields.
2. Add `service-worker.js`:
See [[https://github.com/linonetwo/Meme-of-LinOnetwo/public/service-worker.js|https://github.com/linonetwo/Meme-of-LinOnetwo/blob/d088f72a2b95ee21b68af1b349d9993a3997bf19/Meme-of-LinOnetwo/public/service-worker.js]] for example.
!!! Config router
Sometimes request from this plugin to your `service-worker.js` will resulted in 404, this is basically because you are not putting `service-worker.js` just besides your `index.html`, or the router config is wrong.

View file

@ -1,4 +1,4 @@
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.3/workbox-sw.js');
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.4/workbox-sw.js');
if (workbox) {
console.log(`Yay! Workbox is loaded 🎉Service Worker is working!`);

View file

@ -37,6 +37,7 @@
"felixhayashi/topstoryview",
"mat/field-value-selector",
"linonetwo/opened-tiddlers-bar",
"linonetwo/service-worker",
"linonetwo/copy-on-select",
"linonetwo/source-control-management",
"linonetwo/prevent-edit"