feat(routing): add 404 page and update redirects for proper asset handling
This commit is contained in:
@@ -23,7 +23,7 @@ pnpm -F @proj-airi/ui-server-auth build
|
||||
|
||||
## Deployment
|
||||
|
||||
`pnpm -F @proj-airi/ui-server-auth build` writes to `apps/ui-server-auth/dist`. Vue Router owns `/ui/*`, while Vite assets are served from root `/assets/*` so Cloudflare Pages can serve static files without rewriting nested asset paths. Cloudflare Pages uses `public/_redirects` to route `/ui/*` back to the SPA HTML.
|
||||
`pnpm -F @proj-airi/ui-server-auth build` writes to `apps/ui-server-auth/dist`. Vue Router owns `/ui/*`, while Vite assets are served from root `/assets/*` so Cloudflare Pages can serve static files without rewriting nested asset paths. `public/_redirects` scopes the SPA rewrite to `/ui/*`, and the top-level `public/404.html` keeps missing assets and other unknown paths as HTTP 404 responses.
|
||||
|
||||
The production GitHub Actions workflow deploys this app to the Cloudflare Pages project `moeru-ai-airi-auth` with separate auth-account credentials:
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Page not found</title>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Page not found</h1>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +1,7 @@
|
||||
/ /ui/profile 302
|
||||
/auth /ui/ 302
|
||||
/auth/* /ui/:splat 302
|
||||
/ui /index.html 200
|
||||
/ui/* /index.html 200
|
||||
# Pages canonicalizes explicit /index.html requests. Proxy UI routes to the
|
||||
# root asset so the browser keeps the original client-side route.
|
||||
/ui / 200
|
||||
/ui/* / 200
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const publicDirectory = resolve(import.meta.dirname, '..', 'public')
|
||||
|
||||
describe('cloudflare Pages routing', () => {
|
||||
it('keeps missing static assets as 404 responses while preserving the /ui SPA fallback', async () => {
|
||||
// ROOT CAUSE:
|
||||
//
|
||||
// Without a top-level 404.html, Cloudflare Pages treats every missing file
|
||||
// as an SPA navigation and returns index.html with 200. Missing hashed
|
||||
// assets are then cached as HTML under their immutable asset URLs.
|
||||
//
|
||||
// We keep the SPA rewrite scoped to /ui/* and provide the top-level 404
|
||||
// document that makes every other missing file return HTTP 404.
|
||||
const [notFoundPage, redirects] = await Promise.all([
|
||||
readFile(resolve(publicDirectory, '404.html'), 'utf8'),
|
||||
readFile(resolve(publicDirectory, '_redirects'), 'utf8'),
|
||||
])
|
||||
|
||||
expect(notFoundPage).toContain('<title>Page not found</title>')
|
||||
expect(redirects).toContain('/ui/* / 200')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user