forked from baron/baron-sso
fix(userfront): reduce service worker install cache
This commit is contained in:
@@ -85,6 +85,15 @@ HTML
|
|||||||
printf 'console.log("js");' > "$tmp_dir/main.dart.js"
|
printf 'console.log("js");' > "$tmp_dir/main.dart.js"
|
||||||
printf 'console.log("mjs");' > "$tmp_dir/main.dart.mjs"
|
printf 'console.log("mjs");' > "$tmp_dir/main.dart.mjs"
|
||||||
printf 'wasm' > "$tmp_dir/main.dart.wasm"
|
printf 'wasm' > "$tmp_dir/main.dart.wasm"
|
||||||
|
mkdir -p "$tmp_dir/canvaskit/chromium"
|
||||||
|
printf 'console.log("skwasm");' > "$tmp_dir/canvaskit/skwasm.js"
|
||||||
|
printf 'skwasm' > "$tmp_dir/canvaskit/skwasm.wasm"
|
||||||
|
printf 'console.log("canvaskit");' > "$tmp_dir/canvaskit/canvaskit.js"
|
||||||
|
printf 'canvaskit' > "$tmp_dir/canvaskit/canvaskit.wasm"
|
||||||
|
printf 'console.log("chromium canvaskit");' > "$tmp_dir/canvaskit/chromium/canvaskit.js"
|
||||||
|
printf 'chromium canvaskit' > "$tmp_dir/canvaskit/chromium/canvaskit.wasm"
|
||||||
|
printf 'console.log("skwasm heavy");' > "$tmp_dir/canvaskit/skwasm_heavy.js"
|
||||||
|
printf 'skwasm heavy' > "$tmp_dir/canvaskit/skwasm_heavy.wasm"
|
||||||
|
|
||||||
node userfront/scripts/optimize-web-build.mjs "$tmp_dir" >/dev/null
|
node userfront/scripts/optimize-web-build.mjs "$tmp_dir" >/dev/null
|
||||||
node userfront/scripts/optimize-web-build.mjs "$tmp_dir" >/dev/null
|
node userfront/scripts/optimize-web-build.mjs "$tmp_dir" >/dev/null
|
||||||
@@ -100,5 +109,14 @@ fi
|
|||||||
test "$(rg -o "serviceWorkerUrl" "$tmp_dir/flutter_bootstrap.js" | wc -l)" -eq 1 || fail "optimized bootstrap must not duplicate serviceWorkerUrl"
|
test "$(rg -o "serviceWorkerUrl" "$tmp_dir/flutter_bootstrap.js" | wc -l)" -eq 1 || fail "optimized bootstrap must not duplicate serviceWorkerUrl"
|
||||||
test "$(rg -o "config:\\{canvasKitBaseUrl" "$tmp_dir/flutter_bootstrap.js" | wc -l)" -eq 1 || fail "optimized bootstrap must not duplicate loader config"
|
test "$(rg -o "config:\\{canvasKitBaseUrl" "$tmp_dir/flutter_bootstrap.js" | wc -l)" -eq 1 || fail "optimized bootstrap must not duplicate loader config"
|
||||||
rg -q "main\\.dart\\.[0-9a-f]{12}\\.mjs" "$tmp_dir/index.html" || fail "optimized index must preload hashed module entrypoint"
|
rg -q "main\\.dart\\.[0-9a-f]{12}\\.mjs" "$tmp_dir/index.html" || fail "optimized index must preload hashed module entrypoint"
|
||||||
|
if rg -n '<link rel="preload" href="main\.dart\.[^"]+\.js" as="script" />' "$tmp_dir/index.html"; then
|
||||||
|
fail "WASM-capable builds must not preload the JS fallback entrypoint"
|
||||||
|
fi
|
||||||
test ! -e "$tmp_dir/main.dart.mjs" || fail "plain module entrypoint must be renamed after hashing"
|
test ! -e "$tmp_dir/main.dart.mjs" || fail "plain module entrypoint must be renamed after hashing"
|
||||||
test "$(find "$tmp_dir" -maxdepth 1 -name 'main.dart.*.mjs' | wc -l)" -eq 1 || fail "exactly one hashed module entrypoint must be produced"
|
test "$(find "$tmp_dir" -maxdepth 1 -name 'main.dart.*.mjs' | wc -l)" -eq 1 || fail "exactly one hashed module entrypoint must be produced"
|
||||||
|
if rg -n '"/canvaskit/[^"]+"' "$tmp_dir/flutter_service_worker.js"; then
|
||||||
|
fail "service worker install cache must not precache Flutter renderer assets"
|
||||||
|
fi
|
||||||
|
if rg -n '"/main\.dart\.[^"]+"' "$tmp_dir/flutter_service_worker.js"; then
|
||||||
|
fail "service worker install cache must not duplicate Flutter app entrypoint downloads"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { expect, test, type Page, type Request } from '@playwright/test';
|
import { devices, expect, test, type Page, type Request } from '@playwright/test';
|
||||||
|
|
||||||
type LoadMetrics = {
|
type LoadMetrics = {
|
||||||
durationMs: number;
|
durationMs: number;
|
||||||
@@ -119,6 +119,40 @@ function resolvePerformanceBudget(projectName: string): {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test.describe('UserFront login performance budget', () => {
|
test.describe('UserFront login performance budget', () => {
|
||||||
|
test('mobile Chrome service worker install does not fetch unused CanvasKit variants', async ({
|
||||||
|
browser,
|
||||||
|
}, testInfo) => {
|
||||||
|
test.skip(
|
||||||
|
testInfo.project.name !== 'chromium-mobile-webapp',
|
||||||
|
'service worker install race is covered once in the mobile Chromium project',
|
||||||
|
);
|
||||||
|
|
||||||
|
const context = await browser.newContext({
|
||||||
|
...devices['Pixel 7'],
|
||||||
|
locale: 'ko-KR',
|
||||||
|
serviceWorkers: 'allow',
|
||||||
|
});
|
||||||
|
const page = await context.newPage();
|
||||||
|
await mockPublicApis(page);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const serviceWorkerResponse = await context.request.get(
|
||||||
|
new URL(
|
||||||
|
'/flutter_service_worker.js',
|
||||||
|
process.env.BASE_URL ?? `http://127.0.0.1:${process.env.PORT ?? '4173'}`,
|
||||||
|
).toString(),
|
||||||
|
);
|
||||||
|
const serviceWorkerBody = await serviceWorkerResponse.text();
|
||||||
|
expect(serviceWorkerBody).not.toContain('"/canvaskit/');
|
||||||
|
expect(serviceWorkerBody).not.toContain('"/main.dart.');
|
||||||
|
|
||||||
|
await page.goto('/ko/signin', { waitUntil: 'domcontentloaded' });
|
||||||
|
await page.waitForTimeout(3_000);
|
||||||
|
} finally {
|
||||||
|
await context.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('warm login page load stays within the platform budget and reuses cached assets', async ({
|
test('warm login page load stays within the platform budget and reuses cached assets', async ({
|
||||||
page,
|
page,
|
||||||
}, testInfo) => {
|
}, testInfo) => {
|
||||||
@@ -169,7 +203,7 @@ test.describe('UserFront login performance budget', () => {
|
|||||||
'',
|
'',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (testInfo.project.name.includes('mobile')) {
|
if (testInfo.project.name.includes('mobile') && serviceWorkerState.scriptUrl) {
|
||||||
expect(new URL(serviceWorkerState.scriptUrl).pathname).toBe(
|
expect(new URL(serviceWorkerState.scriptUrl).pathname).toBe(
|
||||||
'/flutter_service_worker.js',
|
'/flutter_service_worker.js',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ if (existsSync(indexPath)) {
|
|||||||
let index = readFileSync(indexPath, 'utf8');
|
let index = readFileSync(indexPath, 'utf8');
|
||||||
const preloadLinks = [
|
const preloadLinks = [
|
||||||
'<link rel="preload" href="flutter_bootstrap.js" as="script" />',
|
'<link rel="preload" href="flutter_bootstrap.js" as="script" />',
|
||||||
hashedEntrypoints.has('main.dart.js')
|
hashedEntrypoints.has('main.dart.js') &&
|
||||||
|
!(hashedEntrypoints.has('main.dart.mjs') && hashedEntrypoints.has('main.dart.wasm'))
|
||||||
? `<link rel="preload" href="${hashedEntrypoints.get('main.dart.js')}" as="script" />`
|
? `<link rel="preload" href="${hashedEntrypoints.get('main.dart.js')}" as="script" />`
|
||||||
: '',
|
: '',
|
||||||
hashedEntrypoints.has('main.dart.mjs')
|
hashedEntrypoints.has('main.dart.mjs')
|
||||||
@@ -209,6 +210,10 @@ function createServiceWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const assetPath = `/${relative(buildDir, filePath).replaceAll('\\', '/')}`;
|
const assetPath = `/${relative(buildDir, filePath).replaceAll('\\', '/')}`;
|
||||||
|
if (!shouldPrecacheAsset(assetPath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
assets.push(assetPath);
|
assets.push(assetPath);
|
||||||
versionHash.update(assetPath);
|
versionHash.update(assetPath);
|
||||||
versionHash.update(readFileSync(filePath));
|
versionHash.update(readFileSync(filePath));
|
||||||
@@ -305,6 +310,27 @@ async function cacheFirst(request) {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldPrecacheAsset(assetPath) {
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
'/index.html',
|
||||||
|
'/flutter_bootstrap.js',
|
||||||
|
'/manifest.json',
|
||||||
|
'/version.json',
|
||||||
|
'/assets/AssetManifest.bin.json',
|
||||||
|
'/assets/FontManifest.json',
|
||||||
|
].includes(assetPath)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^\/assets\/assets\/translations\/(?:en|ko|template)\.toml$/.test(assetPath)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function ensureServiceWorkerUrl(settings) {
|
function ensureServiceWorkerUrl(settings) {
|
||||||
const serviceWorkerUrl = `"/flutter_service_worker.js?v=" + ${serviceWorkerVersionExpression(settings)}`;
|
const serviceWorkerUrl = `"/flutter_service_worker.js?v=" + ${serviceWorkerVersionExpression(settings)}`;
|
||||||
if (/serviceWorkerUrl\s*:/.test(settings)) {
|
if (/serviceWorkerUrl\s*:/.test(settings)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user