Skip to content

Get rid of Webpack for app manifest and service worker #1279

Closed
@Spomky

Description

@Spomky

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions