service worker stuff work in progress

This commit is contained in:
vabene1111 2021-01-21 16:16:49 +01:00
parent ec14338159
commit 47c690526e
14 changed files with 211 additions and 97 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Vue App</title><link href="css/chunk-vendors.css" rel="preload" as="style"><link href="js/chunk-vendors.js" rel="preload" as="script"><link href="js/offline_view.js" rel="preload" as="script"><link href="css/chunk-vendors.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="img/icons/favicon-16x16.png"><link rel="manifest" href="manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="apple-mobile-web-app-title" content="Recipes"><link rel="apple-touch-icon" href="img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><div id="app"></div><script src="js/chunk-vendors.js"></script></body></html>

View File

@ -1,4 +1,5 @@
{% extends "base.html" %}
{% load webpack_loader %}
{% load static %}
{% load i18n %}
@ -15,14 +16,14 @@
<h1 class="">Offline</h1>
<br/>
<span>{% trans 'You are currently offline!' %}</span>
<span>{% trans 'This app does not (yet) support offline functionality. Please make sure to re-establish a network connection.' %}</span>
<br/>
<br/>
<i class="fas fa-search fa-8x"></i>
<span>{% trans 'You are currently offline!' %}</span> <br/>
<span>{% trans 'The recipes listed below are available for offline viewing because you have recently viewed them. Keep in mind that data might be outdated.' %}</span>
<br/>
<br/>
<div id="app">
<offline-view recipe_id="5"></offline-view>
</div>
<br/>
<br/>
@ -32,15 +33,15 @@
{% block script %}
<script type="application/javascript">
<script src="{% url 'javascript-catalog' %}"></script>
caches.open('html').then(productsRuntimeCache => {
{% if debug %}
<script src="{% url 'js_reverse' %}"></script>
{% else %}
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
{% endif %}
productsRuntimeCache.keys().then(keys => {
console.log(keys)
});
});
</script>
{% render_bundle 'chunk-vendors' %}
{% render_bundle 'offline_view' %}
{% endblock %}

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,6 @@
"bootstrap-vue": "^2.21.2",
"core-js": "^3.6.5",
"moment": "^2.29.1",
"register-service-worker": "^1.7.1",
"vue": "^2.6.11",
"vue-multiselect": "^2.1.6",
"vue-template-compiler": "^2.6.12",
@ -31,7 +30,8 @@
"workbox-navigation-preload": "^6.0.2",
"workbox-precaching": "^6.0.2",
"workbox-routing": "^6.0.2",
"workbox-strategies": "^6.0.2"
"workbox-strategies": "^6.0.2",
"workbox-expiration": "^6.0.2"
},
"eslintConfig": {
"root": true,

View File

@ -0,0 +1,94 @@
<template>
<div id="app">
<label>
{{ _('Search') }}
<input type="text" v-model="filter" class="form-control">
</label>
<div class="row">
<div class="col-md-3" v-for="r in filtered_recipes" :key="r.id">
<b-card :title="r.name" tag="article">
<b-card-text>
<span class="text-muted">{{ formatDateTime(r.updated_at) }}</span>
{{ r.description }}
</b-card-text>
<b-button :href="resolveDjangoUrl('view_recipe', r.id)" variant="primary">{{ _('Open') }}</b-button>
</b-card>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import {BootstrapVue} from 'bootstrap-vue'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import {GettextMixin, ResolveUrlMixin} from "@/utils/utils";
import moment from "moment";
Vue.use(BootstrapVue)
Vue.prototype.moment = moment
export default {
name: 'OfflineView',
mixins: [
ResolveUrlMixin,
GettextMixin
],
computed: {
filtered_recipes: function () {
let filtered_list = {}
this.recipes.forEach((recipe) => {
if (recipe.name.toLowerCase().includes(this.filter.toLowerCase())) {
if (recipe.id in filtered_list) {
if (recipe.updated_at > filtered_list[recipe.id].updated_at) {
filtered_list[recipe.id] = recipe
}
} else {
filtered_list[recipe.id] = recipe
}
}
})
return filtered_list
}
},
data() {
return {
recipes: [],
filter: '',
}
},
mounted() {
this.loadRecipe()
},
methods: {
formatDateTime: function (datetime) {
moment.locale(window.navigator.language);
return moment(datetime).format('LLL')
},
loadRecipe: function () {
caches.open('api-recipe').then(productsRuntimeCache => {
productsRuntimeCache.keys().then(keys => {
keys.forEach((key) => {
caches.match(key).then((response) => {
response.json().then((json) => {
this.recipes.push(json)
})
})
})
});
});
},
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,8 @@
import Vue from 'vue'
import App from './OfflineView.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')

View File

@ -1,32 +0,0 @@
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.\n' +
'For more details, visit https://goo.gl/AFskqB'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}

View File

@ -2,50 +2,43 @@
import {precacheAndRoute} from 'workbox-precaching';
import {registerRoute, setCatchHandler} from 'workbox-routing';
import {CacheFirst, NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';
const CACHE_NAME = 'offline-html';
// This assumes /offline.html is a URL for your self-contained
// (no external images or styles) offline page.
const FALLBACK_HTML_URL = '/offline/';
// Populate the cache with the offline HTML page when the
// service worker is installed.
const OFFLINE_CACHE_NAME = 'offline-html';
const OFFLINE_PAGE_URL = '/offline/';
self.addEventListener('install', async (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.add(new Request(FALLBACK_HTML_URL, {cache: "reload"})))
);
event.waitUntil(
caches.open(OFFLINE_CACHE_NAME).then((cache) => cache.add(new Request(OFFLINE_PAGE_URL, {cache: "reload"})))
);
});
// default handler if everything else fails
setCatchHandler(({event}) => {
// The FALLBACK_URL entries must be added to the cache ahead of time, either
// via runtime or precaching. If they are precached, then call
// `matchPrecache(FALLBACK_URL)` (from the `workbox-precaching` package)
// to get the response from the correct cache.
//
// Use event, request, and url to figure out how to respond.
// One approach would be to use request.destination, see
// https://medium.com/dev-channel/service-worker-caching-strategies-based-on-request-types-57411dd7652c
switch (event.request.destination) {
case 'document':
// If using precached URLs:
// return matchPrecache(FALLBACK_HTML_URL);
console.log('Triggered fallback HTML')
return caches.match(FALLBACK_HTML_URL);
switch (event.request.destination) {
case 'document':
console.log('Triggered fallback HTML')
return caches.match(OFFLINE_PAGE_URL);
default:
// If we don't have a fallback, just return an error response.
console.log('Triggered response ERROR')
return Response.error();
}
default:
console.log('Triggered response ERROR')
return Response.error();
}
});
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
({request}) => request.destination === 'image',
new CacheFirst({cacheName: 'images'}),
new CacheFirst({
cacheName: 'images',
plugins: [
new ExpirationPlugin({
maxEntries: 20,
}),
],
}),
);
registerRoute(
@ -65,14 +58,51 @@ registerRoute(
registerRoute(
new RegExp('api/*'),
new NetworkFirst({
cacheName: 'api'
cacheName: 'api',
plugins: [
new ExpirationPlugin({
maxEntries: 50
}),
],
})
)
registerRoute(
({request}) => request.destination === 'document',
new RegExp('api/recipe/([0-9]+)'),
new NetworkFirst({
cacheName: 'html'
cacheName: 'api-recipe',
plugins: [
new ExpirationPlugin({
maxEntries: 50,
}),
],
})
)
const matchHtml = ({url, request, event}) => {
if (request.destination === 'document') {
if (RegExp('view/recipe/*').test(url)) {
return true
}
if (RegExp('search/*').test(url)) {
return true
}
if (RegExp('plan/*').test(url)) {
return true
}
}
return false;
};
registerRoute(
matchHtml,
new NetworkFirst({
cacheName: 'html',
plugins: [
new ExpirationPlugin({
maxAgeSeconds: 60 * 60 * 24 * 30,
}),
],
})
)

View File

@ -5,6 +5,10 @@ const pages = {
entry: './src/apps/RecipeView/main.js',
chunks: ['chunk-vendors']
},
'offline_view': {
entry: './src/apps/OfflineView/main.js',
chunks: ['chunk-vendors']
},
}
module.exports = {

View File

@ -1 +1 @@
{"status":"done","chunks":{"chunk-vendors":[{"name":"css/chunk-vendors.css","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\css\\chunk-vendors.css"},{"name":"js/chunk-vendors.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\chunk-vendors.js"}],"recipe_view":[{"name":"js/recipe_view.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\recipe_view.js"}]}}
{"status":"done","chunks":{"chunk-vendors":[{"name":"css/chunk-vendors.css","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\css\\chunk-vendors.css"},{"name":"js/chunk-vendors.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\chunk-vendors.js"}],"offline_view":[{"name":"js/offline_view.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\offline_view.js"}],"recipe_view":[{"name":"js/recipe_view.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\recipe_view.js"}]}}

View File

@ -8865,6 +8865,13 @@ workbox-expiration@^5.1.4:
dependencies:
workbox-core "^5.1.4"
workbox-expiration@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-6.0.2.tgz#ac01e8d17f48daa31dc0872c09ee6f4d2cf28ccb"
integrity sha512-6+nbR18cklAdI3BPT675ytftXPwnVbXGR8mPWNWTJtl5y2urRYv56ZOJLD7FBFVkZ8EjWiRhNP/A0fkxgdKtWQ==
dependencies:
workbox-core "^6.0.2"
workbox-google-analytics@^5.1.4:
version "5.1.4"
resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-5.1.4.tgz#b3376806b1ac7d7df8418304d379707195fa8517"