This is a simple and rudmentar prototyping of a lazy loader for Hono to be used with Deno and Deno Deploy. Maybe can be adapated for others runtimes.
Pushing the limits of what is possible with Deno Deploy, I developed a moderately small Api service (44 files, 10 endpoints and 3 handlers). The project supports Postgres with Drizzle, called postgres and redis. However, as the project scaled and more libraries were added I began to experience very long cold starts, an inconsistent average of (4 - 15sec).
After many tests I verified that there was a bottleneck in loading the files (handlers), deno deploy started taking a long time to load the files, when eliminating the imports the problem disappeared, in essence Hono does not support Lazy Loading, this gist provides a prototype for that. When initializing, a standard and generic server will be loaded, only importing when the current route handler is requested.
Fee fre to use or adapat for your needs :)
// Imports
import { Hono } from "https://deno.land/x/hono@v3.9.2/preset/quick.ts";
import { registerDefaultRouter, registerLazyRouters, lazyRouter } from 'https://gist.githubusercontent.com/patrickalima98/4ae1e90c8b96e56f3747b9bbe677d51d/raw/1df12b42a85a0c85445db50a17b72ecf1f5c05b9/hono-lazy-load.ts';
// Declare here your handlers to lazy load
const lazyRoutes = {
user: (async () => (await import('./handlers/user/index.ts'))),
health: (async () => (await import('./handlers/health/index.ts'))),
} as const;
// This is an example of a custom function you can pass to
// registerDefaultRouter and lazyRouter functions to do sometind customized like apply a middleware
// to all handlers or to the default handler
// This is an optinal function, you can ignore this and using registerDefaultRouter and lazyRouter
// without it.
function main(newApp: Hono<any, {}, "/">) {
const app = newApp || new Hono()
// Hono App
app.use('*', cors({ credentials: true, origin: 'http://localhost:3000' }))
app.onError((err: any, c): any => {
if (err.message === 'Validation failure') {
return c.json({ errors: err.messages }, err.status)
}
if (err instanceof InternalValidation) {
return c.json({ errors: [err.error] }, err.status)
}
console.error(err)
})
return app;
}
// You need to register all the handlers. This will be saved in the globalThis.cacheRoutes and globalThis.lazyRouters.
registerLazyRouters(lazyRoutes)
registerDefaultRouter<Hono, any>(router());
// Initialize Deno and serve importing the lazyRouter
Deno.serve((req, evt) => lazyRouter(req, evt, router))