Adding PWA Support to an Internal MFE – Manifest Not Loading in Production

Hi all,

I’m trying to add PWA support to an internal Micro Frontend (MFE), but I couldn’t find any existing discussions about this in the forum.

In development, everything seems to work fine — the manifest.json and service worker are successfully registered, and I can see them in Chrome DevTools.

However, in the production build, the manifest.json file doesn’t get loaded at all.

I’ve placed the manifest.json, service worker, and icon assets in the public folder, alongside the index.html file, as we typically do for standard React apps.

Has anyone implemented PWA support in an Open edX MFE before? Any tips on how to properly configure it for production?

Thanks in advance!

I have limited experience with PWAs, but from what I understand, as long as Webpack is building the app properly so that assets end up in the dist directory of the MFE, things should just work. Assuming you’re using Tutor, the tutor-mfe plugin doesn’t care what’s in dist and just copies over everything to be served by Caddy.

You might need to check this stanza in the Caddyfile, though. It could be that something’s not being exposed correctly for a PWA to work.

Thanks, Adolfo — The issue was indeed with the production Webpack build.

In development, everything was fine, but in production the manifest.json, service worker, and other PWA assets weren’t being copied into the dist folder. I confirmed this by inspecting the MFE container — those files simply weren’t there.

To fix it, I added a custom webpack-prod.config.js that uses copy-webpack-plugin to explicitly copy over the necessary files:

const path = require('path');
const { createConfig } = require('@openedx/frontend-build');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const config = createConfig('webpack-prod', {
    resolve: {
        alias: {
            Dashboard: path.resolve(__dirname, 'src/'),
        },
        fallback: {
            fs: false,
            constants: false,
        },
    },
    plugins: [
        new CopyWebpackPlugin({
            patterns: [
                { from: 'public/manifest.json', to: 'manifest.json' },
                { from: 'public/service-worker.js', to: 'service-worker.js' },
                { from: 'public/icons', to: 'icons' },
                { from: 'public/screenshots', to: 'screenshots' }
            ],
        }),
    ],
});

module.exports = config;

After rebuilding the MFE, the dist folder included everything needed — and the PWA now works correctly in production.

For anyone coming across this later:
Make sure your manifest.json is fully valid — include all required icon sizes (like 192x192 and 512x512), and at least one screenshot with both form_factor: "wide" and another (like "narrow"). Without this, install prompts (especially the richer UI on desktop and mobile) may not appear.

1 Like