Skip to content

Commit a29218d

Browse files
committed
fix(app, router): improve perf by caching regex and using push instead of spread
1 parent 6ca52b4 commit a29218d

3 files changed

Lines changed: 39 additions & 25 deletions

File tree

packages/app/src/app.ts

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -247,17 +247,33 @@ export class App<Req extends Request = Request, Res extends Response = Response>
247247
}
248248

249249
#find(url: string): Middleware<Req, Res>[] {
250-
return this.middleware.filter((m) => {
251-
m.regex = m.regex || rg(m.path as string, m.type === 'mw')
250+
const result: Middleware<Req, Res>[] = []
252251

253-
let fullPathRegex: { keys: string[]; pattern: RegExp } | null
252+
for (let i = 0; i < this.middleware.length; i++) {
253+
const m = this.middleware[i]
254254

255-
m.fullPath && typeof m.fullPath === 'string'
256-
? (fullPathRegex = rg(m.fullPath, m.type === 'mw'))
257-
: (fullPathRegex = null)
255+
if (!m.regex) {
256+
m.regex = rg(m.path as string, m.type === 'mw')
257+
}
258+
259+
if (!m.regex.pattern.test(url)) {
260+
continue
261+
}
262+
263+
if (m.type === 'mw' && m.fullPath && typeof m.fullPath === 'string') {
264+
if (!m.fullPathRegex) {
265+
m.fullPathRegex = rg(m.fullPath, true)
266+
}
267+
268+
if (!m.fullPathRegex.pattern.test(url)) {
269+
continue
270+
}
271+
}
272+
273+
result.push(m)
274+
}
258275

259-
return m.regex.pattern.test(url) && (m.type === 'mw' && fullPathRegex ? fullPathRegex.pattern.test(url) : true)
260-
})
276+
return result
261277
}
262278

263279
handler<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(
@@ -271,7 +287,7 @@ export class App<Req extends Request = Request, Res extends Response = Response>
271287
// @ts-expect-error typescript is not smart enough to understand "this" ts(2345)
272288
const exts = this.applyExtensions || extendMiddleware<RenderOptions>(this)
273289

274-
let mw: Middleware[] = [
290+
const mw: Middleware[] = [
275291
{
276292
handler: exts,
277293
type: 'mw',
@@ -333,21 +349,18 @@ export class App<Req extends Request = Request, Res extends Response = Response>
333349
idx = mw.length
334350
req.params = {}
335351
}
336-
mw = [
337-
...mw,
338-
...matched,
339-
{
340-
type: 'mw',
341-
handler: (req, res, next) => {
342-
if (req.method === 'HEAD') {
343-
res.statusCode = 204
344-
return res.end('')
345-
}
346-
next?.()
347-
},
348-
path: '/'
349-
}
350-
]
352+
mw.push(...matched)
353+
mw.push({
354+
type: 'mw',
355+
handler: (req, res, next) => {
356+
if (req.method === 'HEAD') {
357+
res.statusCode = 204
358+
return res.end('')
359+
}
360+
next?.()
361+
},
362+
path: '/'
363+
})
351364
} else if (this.parent == null) {
352365
mw.push({
353366
handler: this.noMatchHandler,

packages/app/src/extend.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export const extendMiddleware = <EngineOptions extends TemplateEngineOptions = T
100100
res.attachment = attachment<Response>(res)
101101
res.download = download<Request, Response>(req, res)
102102
res.append = append<Response>(res)
103-
res.locals = res.locals || Object.create(null)
103+
res.locals ??= {}
104104

105105
Object.defineProperty(req, 'fresh', { get: getFreshOrStale.bind(null, req, res), configurable: true })
106106
req.stale = !req.fresh

packages/router/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export interface Middleware<Req = any, Res = any> {
6868
type: MiddlewareType
6969
regex?: RegexParams
7070
fullPath?: string
71+
fullPathRegex?: RegexParams
7172
}
7273

7374
export type MethodHandler<Req = any, Res = any> = {

0 commit comments

Comments
 (0)