@@ -2,21 +2,32 @@ const { Trouter } = require('trouter')
2
2
const next = require ( './../next' )
3
3
const { parse } = require ( 'regexparam' )
4
4
const { LRUCache : Cache } = require ( 'lru-cache' )
5
- const queryparams = require ( '../utils/queryparams' )
5
+ const queryparams = require ( './. ./utils/queryparams' )
6
6
7
- // Default handlers as constants to avoid creating functions on each router instance
7
+ /**
8
+ * Default handlers as constants to avoid creating functions on each router instance.
9
+ * This reduces memory allocation and improves performance when multiple routers are created.
10
+ */
8
11
const DEFAULT_ROUTE = ( req , res ) => {
9
12
res . statusCode = 404
10
13
res . end ( )
11
14
}
12
15
13
16
const DEFAULT_ERROR_HANDLER = ( err , req , res ) => {
14
17
res . statusCode = 500
18
+ // Note: err.message could expose sensitive information in production
15
19
res . end ( err . message )
16
20
}
17
21
18
- // Simple ID generator
19
- const generateId = ( ) => Math . random ( ) . toString ( 36 ) . substring ( 2 , 10 ) . toUpperCase ( )
22
+ /**
23
+ * Simple ID generator using Math.random for router identification.
24
+ * Warning: Not cryptographically secure - suitable only for internal routing logic.
25
+ * Optimized to minimize string operations.
26
+ */
27
+ const generateId = ( ) => {
28
+ // Use a more efficient approach - avoid substring operations
29
+ return Math . random ( ) . toString ( 36 ) . slice ( 2 , 10 ) . toUpperCase ( )
30
+ }
20
31
21
32
module . exports = ( config = { } ) => {
22
33
// Use object destructuring with defaults for cleaner config initialization
@@ -29,88 +40,127 @@ module.exports = (config = {}) => {
29
40
30
41
const routers = { }
31
42
32
- // Initialize cache only once
43
+ /**
44
+ * Initialize LRU cache for route matching results with optimized settings.
45
+ * Cache keys are method+path combinations to speed up repeated lookups.
46
+ * - cacheSize > 0: Limited LRU cache with specified max entries
47
+ * - cacheSize = 0: No caching (disabled)
48
+ * - cacheSize < 0: Large LRU cache (50k entries) for "unlimited" mode
49
+ * Optimized cache size for better memory management and performance.
50
+ */
33
51
let cache = null
34
52
if ( cacheSize > 0 ) {
35
- cache = new Cache ( { max : cacheSize } )
53
+ cache = new Cache ( {
54
+ max : cacheSize ,
55
+ updateAgeOnGet : false , // Disable age updates for better performance
56
+ updateAgeOnHas : false
57
+ } )
36
58
} else if ( cacheSize < 0 ) {
37
- // For unlimited cache, still use LRUCache but with a very high max
38
- // This provides better memory management than an unbounded Map
39
- cache = new Cache ( { max : 100000 } )
59
+ // Reduced from 100k to 50k for better memory efficiency while maintaining performance
60
+ cache = new Cache ( {
61
+ max : 50000 ,
62
+ updateAgeOnGet : false ,
63
+ updateAgeOnHas : false
64
+ } )
40
65
}
41
66
42
67
const router = new Trouter ( )
43
68
router . id = id
44
69
45
70
const _use = router . use
46
71
72
+ /**
73
+ * Enhanced router.use method with support for nested routers.
74
+ * Handles both middleware functions and nested router instances.
75
+ * Automatically handles prefix parsing when first argument is a function.
76
+ * Optimized for minimal overhead in the common case.
77
+ */
47
78
router . use = ( prefix , ...middlewares ) => {
48
79
if ( typeof prefix === 'function' ) {
49
80
middlewares = [ prefix , ...middlewares ]
50
81
prefix = '/'
51
82
}
52
83
_use . call ( router , prefix , middlewares )
53
84
54
- if ( middlewares [ 0 ] ?. id ) {
55
- // caching router -> pattern relation for urls pattern replacement
85
+ // Optimized nested router detection - check first middleware only
86
+ const firstMiddleware = middlewares [ 0 ]
87
+ if ( firstMiddleware ?. id ) {
88
+ // Cache router -> pattern relation for URL pattern replacement in nested routing
89
+ // This enables efficient URL rewriting when entering nested router contexts
56
90
const { pattern } = parse ( prefix , true )
57
- routers [ middlewares [ 0 ] . id ] = pattern
91
+ routers [ firstMiddleware . id ] = pattern
58
92
}
59
93
60
- return router // Fix: return router instead of this
94
+ return router // Ensure chainable API by returning router instance
61
95
}
62
96
63
- // Create the cleanup middleware once
64
- const createCleanupMiddleware = ( step ) => ( req , res , next ) => {
65
- req . url = req . preRouterUrl
66
- req . path = req . preRouterPath
67
-
68
- req . preRouterUrl = undefined
69
- req . preRouterPath = undefined
70
-
71
- return step ( )
97
+ /**
98
+ * Creates cleanup middleware for nested router restoration.
99
+ * This middleware restores the original URL and path after nested router processing.
100
+ * Uses property deletion instead of undefined assignment for better performance.
101
+ * Optimized to minimize closure creation overhead.
102
+ */
103
+ const createCleanupMiddleware = ( step ) => {
104
+ // Pre-create the cleanup function to avoid repeated function creation
105
+ return ( req , res , next ) => {
106
+ req . url = req . preRouterUrl
107
+ req . path = req . preRouterPath
108
+
109
+ // Use delete for better performance than setting undefined
110
+ delete req . preRouterUrl
111
+ delete req . preRouterPath
112
+
113
+ return step ( )
114
+ }
72
115
}
73
116
74
117
router . lookup = ( req , res , step ) => {
75
- // Initialize URL and originalUrl if needed
76
- req . url = req . url || '/'
77
- req . originalUrl = req . originalUrl || req . url
118
+ // Initialize URL and originalUrl if needed - use nullish coalescing for better performance
119
+ req . url ??= '/'
120
+ req . originalUrl ??= req . url
78
121
79
- // Parse query parameters
122
+ // Parse query parameters using optimized utility
80
123
queryparams ( req , req . url )
81
124
82
- // Fast path for cache lookup
83
- const reqCacheKey = cache && ( req . method + req . path )
84
- let match = cache && cache . get ( reqCacheKey )
125
+ // Cache lookup optimization - minimize variable assignments
126
+ let match
127
+ if ( cache ) {
128
+ // Pre-compute cache key with direct concatenation (fastest approach)
129
+ const reqCacheKey = req . method + req . path
130
+ match = cache . get ( reqCacheKey )
85
131
86
- if ( ! match ) {
87
- match = router . find ( req . method , req . path )
88
- if ( cache && reqCacheKey ) {
132
+ if ( ! match ) {
133
+ match = router . find ( req . method , req . path )
89
134
cache . set ( reqCacheKey , match )
90
135
}
136
+ } else {
137
+ match = router . find ( req . method , req . path )
91
138
}
92
139
93
140
const { handlers, params } = match
94
141
95
- if ( handlers . length > 0 ) {
96
- // Avoid creating a new array with spread operator
97
- // Use the handlers array directly
142
+ if ( handlers . length ) {
143
+ // Optimized middleware array handling
98
144
let middlewares
99
-
100
145
if ( step !== undefined ) {
101
- // Only create a new array if we need to add the cleanup middleware
146
+ // Create new array only when step middleware is needed
102
147
middlewares = handlers . slice ( )
103
148
middlewares . push ( createCleanupMiddleware ( step ) )
104
149
} else {
105
150
middlewares = handlers
106
151
}
107
152
108
- // Initialize params object if needed
153
+ // Optimized parameter assignment with minimal overhead
109
154
if ( ! req . params ) {
110
- req . params = params
155
+ // Use pre-created empty object or provided params directly
156
+ req . params = params || Object . create ( null )
111
157
} else if ( params ) {
112
- // Faster than Object.assign for small objects
113
- for ( const key in params ) {
158
+ // Manual property copying - optimized for small objects
159
+ // Pre-compute keys and length to avoid repeated calls
160
+ const paramKeys = Object . keys ( params )
161
+ let i = paramKeys . length
162
+ while ( i -- ) {
163
+ const key = paramKeys [ i ]
114
164
req . params [ key ] = params [ key ]
115
165
}
116
166
}
@@ -121,6 +171,10 @@ module.exports = (config = {}) => {
121
171
}
122
172
}
123
173
174
+ /**
175
+ * Shorthand method for registering routes with specific HTTP methods.
176
+ * Delegates to router.add with the provided method, pattern, and handlers.
177
+ */
124
178
router . on = ( method , pattern , ...handlers ) => router . add ( method , pattern , handlers )
125
179
126
180
return router
0 commit comments