@@ -73,6 +73,9 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
7373 // Track requests that have been processed by each renderer to prevent double execution
7474 const processedRendererRequests = new WeakMap < MiddlewareHandler , WeakSet < Request > > ( )
7575
76+ // Track requests that have been processed by each middleware to prevent double execution
77+ const processedMiddlewareRequests = new WeakMap < MiddlewareHandler , WeakSet < Request > > ( )
78+
7679 // Share context by AsyncLocalStorage
7780 app . use ( async function ShareContext ( c , next ) {
7881 await contextStorage . run ( c , ( ) => next ( ) )
@@ -174,6 +177,23 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
174177 )
175178 }
176179
180+ // Helper function to apply extra handlers for parent routing patterns like /:lang{en} or /:lang?
181+ const applyExtraHandlersForRouting = ( handlers : MiddlewareHandler [ ] ) => {
182+ const rootPath = dir . replace ( rootRegExp , '' )
183+ const isRootLevel = ! rootPath . includes ( '/' )
184+ const isSimpleStructure = ! Object . keys ( content ) . some ( ( f ) => f . includes ( '/' ) )
185+
186+ if ( Object . keys ( content ) . length > 0 && isRootLevel && isSimpleStructure ) {
187+ subApp . use ( '/' , ...handlers )
188+ Object . keys ( content ) . forEach ( ( filename ) => {
189+ const path = filePathToPath ( filename )
190+ if ( path !== '/' && ! path . includes ( '[' ) && ! path . includes ( '*' ) ) {
191+ subApp . use ( path , ...handlers )
192+ }
193+ } )
194+ }
195+ }
196+
177197 // Apply renderer middleware more robustly to handle all routing scenarios
178198 const rendererPaths = getPaths ( dir , rendererList )
179199 rendererPaths . map ( ( path ) => {
@@ -202,19 +222,7 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
202222 subApp . use ( '*' , wrappedRenderer )
203223
204224 // Apply extra middleware for parent routing patterns like /:lang{en} or /:lang?
205- const rootPath = dir . replace ( rootRegExp , '' )
206- const isRootLevel = ! rootPath . includes ( '/' )
207- const isSimpleStructure = ! Object . keys ( content ) . some ( ( f ) => f . includes ( '/' ) )
208-
209- if ( Object . keys ( content ) . length > 0 && isRootLevel && isSimpleStructure ) {
210- subApp . use ( '/' , wrappedRenderer )
211- Object . keys ( content ) . forEach ( ( filename ) => {
212- const path = filePathToPath ( filename )
213- if ( path !== '/' && ! path . includes ( '[' ) && ! path . includes ( '*' ) ) {
214- subApp . use ( path , wrappedRenderer )
215- }
216- } )
217- }
225+ applyExtraHandlersForRouting ( [ wrappedRenderer ] )
218226 }
219227 } )
220228
@@ -253,8 +261,28 @@ export const createApp = <E extends Env>(options: BaseServerOptions<E>): Hono<E>
253261 const shouldApply = middlewareDir === dir || dir . startsWith ( middlewareDir + '/' )
254262
255263 if ( middleware . default && shouldApply ) {
256- // Use a dynamic route pattern that matches all paths including root
257- subApp . use ( '/:*{.+}?' , ...middleware . default )
264+ // Wrap each middleware to check if already processed
265+ const wrappedMiddleware = middleware . default . map ( ( mw ) => {
266+ // Get or create WeakSet for this specific middleware
267+ if ( ! processedMiddlewareRequests . has ( mw ) ) {
268+ processedMiddlewareRequests . set ( mw , new WeakSet < Request > ( ) )
269+ }
270+ const processedRequests = processedMiddlewareRequests . get ( mw ) !
271+
272+ return createMiddleware ( async ( c , next ) => {
273+ if ( ! processedRequests . has ( c . req . raw ) ) {
274+ processedRequests . add ( c . req . raw )
275+ return mw ( c , next )
276+ }
277+ return next ( )
278+ } )
279+ } )
280+
281+ // Use a wildcard pattern that matches all paths including root
282+ subApp . use ( '*' , ...wrappedMiddleware )
283+
284+ // Apply extra middleware for parent routing patterns like /:lang{en} or /:lang?
285+ applyExtraHandlersForRouting ( wrappedMiddleware )
258286
259287 // Track that this middleware has been applied to this directory
260288 if ( ! appliedMiddlewaresByDirectory . has ( dir ) ) {
0 commit comments