Description
Hi,
I'm really excited about the direction this frontend integration is taking. It covers almost all we need.
There is one piece that is missing and still covered by Webpack: the service worker.
At the moment, I don't know how to manage that, but I will be happy to contribute to it.
Hereafter, an extract of the webpack.config.js
and the assets/sw.js
files
const {InjectManifest} = require('workbox-webpack-plugin');
const WebpackPwaManifest = require('webpack-pwa-manifest');
Encore
// Usual Webpack config goes here
// Plugin for compiling the service worker
.addPlugin(new InjectManifest({
swSrc: './assets/sw.js',
swDest: '../sw.js',
maximumFileSizeToCacheInBytes: 50000000,
exclude: [
/\.map$/,
/manifest$/,
/\.htaccess$/,
/service-worker\.js$/,
/sw\.js$/,
],
}))
// Plugin for writing the Progressive Web App manifest
.addPlugin(new WebpackPwaManifest({
name: 'My App',
short_name: 'my-app',
description: 'This is my application',
filename: "application.json",
orientation: "any",
display: "standalone",
id: "/",
start_url: "/app",
inject: false,
fingerprints: true,
ios: true,
publicPath: null,
includeDirectory: true,
background_color: '#ffffff',
crossorigin: 'use-credentials',
icons: [
{
src: path.resolve('assets/images/logo.png'),
sizes: [48, 57, 60, 72, 76, 96, 114, 128, 144, 152, 180, 192, 256, 384, 512, 1024], // multiple sizes,
},
{
purpose: "maskable",
src: path.resolve('assets/images/maskable_logo.png'),
sizes: [48, 57, 60, 72, 76, 96, 114, 128, 144, 152, 180, 192, 256, 384, 512, 1024],
}
],
protocol_handlers: [
{
protocol: "web+app-report",
url: "/dashboard/report/%s"
},
{
protocol: "web+app-customer",
url: "/dashboard/customer/%s"
}
]
}))
;
//... Export
import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {
pageCache,
imageCache,
staticResourceCache,
googleFontsCache,
offlineFallback,
warmStrategyCache,
} from 'workbox-recipes';
import { NetworkOnly, CacheFirst, NetworkFirst } from 'workbox-strategies';
import { precacheAndRoute } from 'workbox-precaching';
import {registerRoute} from "workbox-routing/registerRoute";
import {CacheableResponsePlugin} from "workbox-cacheable-response/CacheableResponsePlugin";
import {ExpirationPlugin} from "workbox-expiration/ExpirationPlugin";
const PAGE_CACHE_NAME = 'pages';
const FONT_CACHE_NAME = 'fonts';
const STATIC_CACHE_NAME = 'assets';
const CUSTOM_CACHE_NAME = 'custom';
const IMAGE_CACHE_NAME = 'images';
const OFFLINE_URI = '/';
const OFFLINE_MAX_RETENTION_TIME = 24*60*15;
const BACKGROUND_SYNC_QUEUE_NAME = 'my-app';
const warmCacheUrls = [
'/',
'/app',
];
const bgSyncPlugin = new BackgroundSyncPlugin(BACKGROUND_SYNC_QUEUE_NAME, {
maxRetentionTime: OFFLINE_MAX_RETENTION_TIME
});
registerRoute(
/\/app\/.*/,
new NetworkFirst({
cacheName: CUSTOM_CACHE_NAME ,
}),
'GET'
);
registerRoute(
/\/app\/(something|other-things).*/,
new NetworkOnly({
plugins: [bgSyncPlugin],
}),
'POST'
);
registerRoute(
/\/dashboard\/.*/,
new NetworkOnly(),
'GET'
);
registerRoute(
/\/login/,
new NetworkOnly(),
'GET'
);
pageCache({
cacheName: PAGE_CACHE_NAME
});
googleFontsCache({
cacheName: FONT_CACHE_NAME,
});
staticResourceCache({
cacheName: STATIC_CACHE_NAME,
});
imageCache({
cacheName: IMAGE_CACHE_NAME,
maxEntries: 250,
maxAgeSeconds: 3600*24*365,
});
offlineFallback({
pageFallback: OFFLINE_URI,
});
// Cache the underlying font files with a cache-first strategy for 1 year.
registerRoute(
({request}) => request.destination === 'font',
new CacheFirst({
cacheName: FONT_CACHE_NAME,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
new ExpirationPlugin({
maxAgeSeconds: 60 * 60 * 24 * 365,
maxEntries: 30,
}),
],
}),
);
precacheAndRoute(self.__WB_MANIFEST);
const strategy = new CacheFirst();
warmStrategyCache({urls: warmCacheUrls, strategy});
The application manifest is then declared as a normal header meta tag <link rel="manifest" href="{{ asset('build/application.json') }}">
. Icons of all sizes are created.
The compiled service worker (I use Workbox in general) is loaded by the main app.js
file as follows:
// assets/app.js
//...
if (navigator.serviceWorker) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("/sw.js", {scope: '/'});
})
}
Honestly, I don't know how to deal with these two files without Webpack.If you have any clue on how to get rid of Webpack for such use case, let me know.