epicweb-dev / epicweb-dev/epic-stack
/img/* and /favicons/* 404 handler prevents static file serving when placed before dev/prod middleware
- 主要言語
- TypeScript
- スター
- 5.5k
- フォーク
- 460
- 平均マージ
- 2時間 43分
- マージ済み PR(30日)
- 1
説明
Problem
The 404 handler for /img/* and /favicons/* routes intercepts requests before the static file serving middleware can handle them, causing images and favicons to return 404 errors.
```
app.get(['/img/*splat', '/favicons/*splat'], (_req, res) => {
// if we made it past the express.static for these, then we're missing something.
// So we'll just send a 404 and won't bother calling other middleware.
res.status(404).send('Not found')
})
```
Current Behavior
When this handler is placed before the dev/prod server setup static files at /img/* and /favicons/* paths return 404 errors, unless the full /public/img path is used.
Expected Behavior
The 404 handler should only trigger after Express has attempted to serve static files from the public directory.
Solution
The 404 handler needs to be moved after the static file middleware setup block , so that:
In development: Vite middleware attempts to serve the files first
In production: express.static attempts to serve the files first
Only if neither finds the file, the 404 handler responds
Example:
```
if (IS_DEV) {
console.log('Starting development server')
const viteDevServer = await import('vite').then((vite) =>
vite.createServer({
server: { middlewareMode: true },
// We tell Vite we are running a custom app instead of
// the SPA default so it doesn't run HTML middleware
appType: 'custom',
}),
)
app.use(viteDevServer.middlewares)
app.use(async (req, res, next) => {
try {
const source = await viteDevServer.ssrLoadModule('./server/app.ts')
return await source.app(req, res, next)
} catch (error) {
if (typeof error === 'object' && error instanceof Error) {
viteDevServer.ssrFixStacktrace(error)
}
next(error)
}
})
} else {
console.log('Starting production server')
// React Router fingerprints its assets so we can cache forever.
app.use(
'/assets',
express.static('build/client/assets', {
immutable: true,
maxAge: '1y',
fallthrough: false,
}),
)
// Everything else (like favicon.ico) is cached for an hour. You may want to be
// more aggressive with this caching.
app.use(express.static('build/client', { maxAge: '1h' }))
app.use(await import(BUILD_PATH).then((mod) => mod.app))
}
app.get(['/img/*splat', '/favicons/*splat'], (_req, res) => {
// if we made it past the express.static for these, then we're missing something.
// So we'll just send a 404 and won't bother calling other middleware.
res.status(404).send('Not found')
})
```
コントリビューションガイド
調査の方向性
IS_DEV を含む開発/本番用ミドルウェアブロックがあるサーバーエントリから始め、開発時に server/app.ts をどのように読み込むかを確認します。Vite または express.static がフォールバックハンドラーの前に /img/* と /favicons/* を処理することを検証します。既存の静的ファイルが配信され、存在しないファイルには引き続き 404 レスポンスが返されれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- express, typescript, vite
- 領域
- backend, web-dev
- issue の種類
- バグ
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 活発さ
- 停滞
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 55/100