feat: dynamically set PWA start_url

This commit fixes an issue where the PWA would always start at the
root of the application, regardless of the page you were on when
you installed it.

This is fixed by:
- Consolidating the two manifest files into a single file.
- Adding a new route to the server that dynamically generates the
  `start_url` in the manifest based on the current route.
- Adding an e2e test to verify the changes.
This commit is contained in:
google-labs-jules[bot]
2025-07-24 17:27:02 +00:00
parent ad2ef3b53f
commit 84459b06e2
8 changed files with 80 additions and 32 deletions
+1 -2
View File
@@ -9,8 +9,7 @@
<meta name="ontime" content="ontime - time keeping for live events" />
<link rel="apple-touch-icon" href="/ontime-logo.png" />
<link rel="icon" type="image/png" href="/ontime-logo.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="manifest" href="/manifest.json" />
<link rel="manifest" href="/manifest.webmanifest" />
<meta name="robots" content="noindex" />
<title>ontime</title>
<style>
-19
View File
@@ -1,19 +0,0 @@
{
"name": "ontime",
"short_name": "ontime",
"icons": [
{
"src": "favicon.ico",
"type": "image/x-icon"
},
{
"src": "ontime-logo.png",
"type": "image/png"
}
],
"scope": "/",
"start_url": "/",
"display": "",
"theme_color": "#121212",
"background_color": "#ffffff"
}
+15
View File
@@ -0,0 +1,15 @@
{
"name": "ontime",
"short_name": "ontime",
"icons": [
{
"src": "/ontime-logo.png",
"sizes": "295x295",
"type": "image/png"
}
],
"scope": "/",
"display": "standalone",
"theme_color": "#2B5ABC",
"background_color": "#101010"
}
-10
View File
@@ -1,10 +0,0 @@
{
"name": "",
"short_name": "",
"icons": [
{ "src": "/ontime-logo.png", "sizes": "295x295", "type": "image/png" }
],
"theme_color": "#2B5ABC",
"background_color": "#101010",
"display": "standalone"
}
+19
View File
@@ -8,6 +8,8 @@ import serverTiming from 'server-timing';
import cookieParser from 'cookie-parser';
// import utils
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { publicDir, srcDir } from './setup/index.js';
import { environment, isProduction } from './setup/environment.js';
import { updateRouterPrefix } from './externals.js';
@@ -98,6 +100,23 @@ app.use(`${prefix}/user`, express.static(publicDir.userDir, { etag: false, lastM
// Base route for static files
app.use(`${prefix}`, authenticateAndRedirect, compressedStatic);
app.get(`${prefix}/manifest.webmanifest`, (req, res) => {
// get the referer, if it doesnt exist, we send the default manifest
const referer = req.headers.referer || '/';
// read the manifest file
const manifest = JSON.parse(
readFileSync(join(publicDir.root, 'manifest.webmanifest'), 'utf-8'),
);
// set the start_url to the referer
manifest.start_url = referer;
// send the manifest
res.json(manifest);
});
app.use(`${prefix}/*splat`, authenticateAndRedirect, compressedStatic);
// Implement catch all
@@ -0,0 +1,37 @@
import { test, expect } from '@playwright/test';
test('manifest start_url is correct for cuesheet', async ({ page }) => {
await page.goto('/cuesheet');
const manifestUrl = await page.evaluate(() => {
const link = document.querySelector('link[rel="manifest"]');
if (!link) {
return null;
}
return (link as HTMLLinkElement).href;
});
expect(manifestUrl).not.toBeNull();
const response = await page.request.get(manifestUrl!);
const manifest = await response.json();
expect(manifest.start_url).toContain('/cuesheet');
});
test('manifest start_url is correct for op', async ({ page }) => {
await page.goto('/op');
const manifestUrl = await page.evaluate(() => {
const link = document.querySelector('link[rel="manifest"]');
if (!link) {
return null;
}
return (link as HTMLLinkElement).href;
});
expect(manifestUrl).not.toBeNull();
const response = await page.request.get(manifestUrl!);
const manifest = await response.json();
expect(manifest.start_url).toContain('/op');
});
+4 -1
View File
@@ -51,5 +51,8 @@
"turbo": "^2.3.3",
"typescript": "catalog:"
},
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977",
"dependencies": {
"tsx": "^4.20.3"
}
}
+4
View File
@@ -37,6 +37,10 @@ catalogs:
importers:
.:
dependencies:
tsx:
specifier: ^4.20.3
version: 4.20.3
devDependencies:
'@playwright/test':
specifier: ^1.51.1