@@ -67,6 +67,12 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
6767 // Key: directory path, Value: Set of middleware file paths applied to that directory
6868 const appliedMiddlewaresByDirectory = new Map < string , Set < string > > ( )
6969
70+ // Track responses that have already been processed by 404 handler to prevent double execution
71+ const processedNotFoundResponses = new WeakSet < Response > ( )
72+
73+ // Track requests that have been processed by each renderer to prevent double execution
74+ const processedRendererRequests = new WeakMap < MiddlewareHandler , WeakSet < Request > > ( )
75+
7076 // Share context by AsyncLocalStorage
7177 app . use ( async function ShareContext ( c , next ) {
7278 await contextStorage . run ( c , ( ) => next ( ) )
@@ -128,13 +134,14 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
128134 if ( notFoundHandler ) {
129135 subApp . use ( async ( c , next ) => {
130136 await next ( )
131- if ( c . res . status === 404 ) {
137+ if ( c . res . status === 404 && ! processedNotFoundResponses . has ( c . res ) ) {
132138 const notFoundResponse = await notFoundHandler ( c )
133139 const res = new Response ( notFoundResponse . body , {
134140 status : 404 ,
135141 headers : notFoundResponse . headers ,
136142 } )
137143 c . res = res
144+ processedNotFoundResponses . add ( c . res )
138145 }
139146 } )
140147 }
@@ -177,19 +184,34 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
177184 }
178185 const rendererDefault = renderer . default
179186 if ( rendererDefault ) {
180- subApp . use ( '*' , rendererDefault )
187+ // Get or create WeakSet for this renderer
188+ if ( ! processedRendererRequests . has ( rendererDefault ) ) {
189+ processedRendererRequests . set ( rendererDefault , new WeakSet < Request > ( ) )
190+ }
191+ const processedRequests = processedRendererRequests . get ( rendererDefault ) !
192+
193+ // Wrap renderer to check if already processed
194+ const wrappedRenderer = createMiddleware ( async ( c , next ) => {
195+ if ( ! processedRequests . has ( c . req . raw ) ) {
196+ processedRequests . add ( c . req . raw )
197+ return rendererDefault ( c , next )
198+ }
199+ return next ( )
200+ } )
201+
202+ subApp . use ( '*' , wrappedRenderer )
181203
182204 // Apply extra middleware for parent routing patterns like /:lang{en} or /:lang?
183205 const rootPath = dir . replace ( rootRegExp , '' )
184206 const isRootLevel = ! rootPath . includes ( '/' )
185207 const isSimpleStructure = ! Object . keys ( content ) . some ( ( f ) => f . includes ( '/' ) )
186208
187209 if ( Object . keys ( content ) . length > 0 && isRootLevel && isSimpleStructure ) {
188- subApp . use ( '/' , rendererDefault )
210+ subApp . use ( '/' , wrappedRenderer )
189211 Object . keys ( content ) . forEach ( ( filename ) => {
190212 const path = filePathToPath ( filename )
191213 if ( path !== '/' && ! path . includes ( '[' ) && ! path . includes ( '*' ) ) {
192- subApp . use ( path , rendererDefault )
214+ subApp . use ( path , wrappedRenderer )
193215 }
194216 } )
195217 }
@@ -320,7 +342,7 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
320342 const subApp = new Hono < {
321343 Variables : Variables
322344 } > ( )
323- applyNotFound ( subApp , dir , notFoundMap )
345+ applyNotFound ( subApp , dir , notFoundMap , processedNotFoundResponses )
324346 const rootPath = getRootPath ( dir )
325347 app . route ( rootPath , subApp )
326348 }
@@ -344,7 +366,8 @@ function applyNotFound(
344366 Variables : Variables
345367 } > ,
346368 dir : string ,
347- map : Record < string , Record < string , NotFoundFile > >
369+ map : Record < string , Record < string , NotFoundFile > > ,
370+ processedNotFoundResponses : WeakSet < Response >
348371) {
349372 for ( const [ mapDir , content ] of Object . entries ( map ) ) {
350373 if ( dir === mapDir ) {
@@ -358,9 +381,13 @@ function applyNotFound(
358381 return next ( )
359382 } )
360383 }
361- app . get ( '*' , ( c ) => {
362- c . status ( 404 )
363- return notFoundHandler ( c )
384+ app . get ( '*' , async ( c , next ) => {
385+ await next ( )
386+ if ( processedNotFoundResponses . has ( c . res ) ) {
387+ c . status ( 404 )
388+ processedNotFoundResponses . add ( c . res )
389+ c . res = await notFoundHandler ( c )
390+ }
364391 } )
365392 }
366393 }
0 commit comments