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.