fix(hono): replace serveStatic/Bun.file with explicit Content-Length routes

serveStatic returns content-length: 0 with Bun v1.3.x causing Nginx
12-30s stall. Replaced all HTML static routes with explicit:
- app.get('/admin/*.html') with c.header(Content-Length, Buffer.byteLength())
- fallback routes (/, /admin, /login, /catalog, /property/*) with c.html()
- all explicitly set Content-Length before returning text body

Refs: production server, Content-Length bug
Resolves: Admin 404, 30s load, DOMException abort
This commit is contained in:
APAW Agent Sync
2026-05-15 21:27:03 +01:00
parent d10a288333
commit e84f0aa153

View File

@@ -1801,22 +1801,24 @@ app.get('/images/*', serveStatic({ root: './public' }))
app.get('/uploads/*', serveStatic({ root: './public' }))
app.get('/src/i18n/*', serveStatic({ root: '.' }))
// Admin HTML components - read file text explicitly to force Content-Length
app.get('/admin/*', async (c) => {
const path = c.req.path
// If path ends with /, it's a directory → serve admin SPA
const filePath = path.endsWith('/') ? './public/admin.html' : `./public${path}`
const file = Bun.file(filePath)
const text = await file.text()
c.header('Content-Length', String(Buffer.byteLength(text, 'utf8')))
c.header('Content-Type', 'text/html; charset=utf-8')
return c.body(text)
// Admin HTML components - explicit routes with forced Content-Length
// (serveStatic has a content-length bug in this version of Bun/Hono)
const adminComponents = [
'sidebar', 'topbar', 'dashboard', 'properties', 'leads',
'testimonials', 'faq', 'services', 'settings', 'users',
'analytics', 'traffic'
]
adminComponents.forEach(name => {
app.get(`/admin/${name}.html`, async (c) => {
const file = Bun.file(`./public/admin/${name}.html`)
const text = await file.text()
c.header('Content-Length', String(Buffer.byteLength(text, 'utf8')))
c.header('Content-Type', 'text/html; charset=utf-8')
return c.body(text)
})
})
// Static HTML pages where URL path directly matches filename
app.get('/catalog.html', serveStatic({ root: './public' }))
// SPA fallback routes (dynamic paths) - read file text to force Content-Length
// SPA fallback routes (dynamic paths) with forced Content-Length
app.get('/property/*', async (c) => {
const text = await Bun.file('./public/property.html').text()
c.header('Content-Length', String(Buffer.byteLength(text, 'utf8')))
@@ -1827,6 +1829,11 @@ app.get('/catalog', async (c) => {
c.header('Content-Length', String(Buffer.byteLength(text, 'utf8')))
return c.html(text)
})
app.get('/catalog.html', async (c) => {
const text = await Bun.file('./public/catalog.html').text()
c.header('Content-Length', String(Buffer.byteLength(text, 'utf8')))
return c.html(text)
})
app.get('/admin', async (c) => {
const text = await Bun.file('./public/admin.html').text()
c.header('Content-Length', String(Buffer.byteLength(text, 'utf8')))
@@ -1839,7 +1846,11 @@ app.get('/login', async (c) => {
})
// Fallback to index.html for all other routes
app.get('*', async (c) => c.html(await Bun.file('./public/index.html').text()))
app.get('*', async (c) => {
const text = await Bun.file('./public/index.html').text()
c.header('Content-Length', String(Buffer.byteLength(text, 'utf8')))
return c.html(text)
})
// Start server
const port = parseInt(process.env.PORT || '8080')