New routers, presets,
app.mount()
, Node server v1. Let's go!
Hono v3.2 is now available! It introduces many features while maintaining simplicity.
- Two new routers: LinearRouter and PatternRouter.
- Presets:
hono/tiny
,hono/quick
. app.mount()
- Release of Node adapter server v1.0.0!
- Support for AWS Lambda function URLs.
- Cookie Middleware.
- Renaming
hono/nextjs
tohono/vercel
.
Let's take a look!
New Routers
We introduce two new routers: LinearRouter and PatternRouter.
LinearRouter
LinearRouter is "quick". While RegExpRouter is one of the fastest routers in the JavaScript world, it's a bit slow when registering routing paths.
app.get('/', handler) // <=== Registering routing paths - a little slow
//...
app.fetch(request) // <=== Handle request - ultra-fast
So, in environments that are initialized with every request, such as Fastly Compute@Edge, RegExpRouter may not be the best choice.
LinearRouter registers routes very quickly, even compared to other fast JavaScript routers. The following is one of the benchmark results, which includes the route registration phase.
• GET /user/lookup/username/hey
----------------------------------------------------- -----------------------------
LinearRouter 1.82 µs/iter (1.7 µs … 2.04 µs) 1.84 µs 2.04 µs 2.04 µs
MedleyRouter 4.44 µs/iter (4.34 µs … 4.54 µs) 4.48 µs 4.54 µs 4.54 µs
FindMyWay 60.36 µs/iter (45.5 µs … 1.9 ms) 59.88 µs 78.13 µs 82.92 µs
KoaTreeRouter 3.81 µs/iter (3.73 µs … 3.87 µs) 3.84 µs 3.87 µs 3.87 µs
TrekRouter 5.84 µs/iter (5.75 µs … 6.04 µs) 5.86 µs 6.04 µs 6.04 µs
summary for GET /user/lookup/username/hey
LinearRouter
2.1x faster than KoaTreeRouter
2.45x faster than MedleyRouter
3.21x faster than TrekRouter
33.24x faster than FindMyWay
And according to this comment, it will be 40% faster on Fastly Compute@Edge.
PatternRouter
PatternRouter is "tiny". By default, Hono uses SmartRouter with RegExpRouter and TrieRouter. Although not the fastest, we made it even smaller.
If you need to reduce size for resource-limited environments, you can use PatternRouter.
An application using only PatternRouter is about 12KB in size.
yusuke $ esbuild --outdir=dist --bundle --minify ./src/index.ts
dist/index.js 11.9kb
⚡ Done in 9ms
Presets: hono/tiny
, hono/quick
Hono has several routers, each designed for a specific purpose. You can specify the router you want to use in the Hono constructor.
Presets are provided for common use cases, so you don't have to specify the router each time. The Hono class imported from all presets is the same, the only difference being the router. Therefore, you can use them interchangeably.
We introduce hono/tiny
and hono/quick
today.
hono/tiny
Preset hono/tiny
means using only PatternRouter.
this.router = new PatternRouter()
To use hono/tiny
, you only have to import hono/tiny
and use Hono
as usual.
import { Hono } from 'hono/tiny'
const app = new Hono()
//...
hono/quick
Preset hono/quick
means using only LinearRouter.
this.router = new LinearRouter()
You can also use hono/quick
like other presets.
import { Hono } from 'hono/quick'
Which preset should I use?
We now offer three presets: hono
, hono/tiny
, and hono/quick
. You might be wondering, "Which preset should I use?" Please refer to the followings.
Preset | Suitable platforms |
---|---|
hono
| This is highly recommended for most use cases. Although the registration phase may be slower than hono/quick , it exhibits high performance once booted. It's ideal for long-life servers built with Deno, Bun, or Node.js. For environments such as Cloudflare Workers, Deno Deploy, Lagon, where v8 isolates are utilized, this preset is suitable too. Because the isolates persist for a certain amount of time after booting.
|
hono/quick
| This preset is designed for environments where the application is initialized for every request. Fastly Compute@Edge operates in this manner, thus this preset is recommended for use it. |
hono/tiny
| This is the smallest router package and is suitable for environments where resources are limited. |
app.mount()
By using new feature app.mount()
, you can integrate applications using other frameworks, such as itty-router, with Hono.
// Create itty-router application
const ittyRouter = IttyRouter()
// Handle `GET /itty-router/hello`
ittyRouter.get('/hello', () => new Response('Hello from itty-router!'))
// Hono application
const app = new Hono()
// Hono application
app.mount('/itty-router', ittyRouter.handle)
Also Remix:
import { Hono } from 'hono'
import { env } from 'hono/adapter'
import { serveStatic } from 'hono/cloudflare-workers'
import { createRequestHandler } from '@remix-run/cloudflare'
import * as build from './build'
// Remix application
// @ts-ignore
const handleRemixRequest = createRequestHandler(build, process.env.NODE_ENV)
// Hono application
const app = new Hono()
// Static files for Remix
app.get(
'/remix/build/*',
serveStatic({
root: './',
})
)
// Mount Remix app
app.mount('/remix', handleRemixRequest, (c) => {
return { env: env(c) }
})
This implies that we can mount applications built with any framework, such as itty-router, Remix, Qwik, or SolidJS, into our Hono application.
Ecosystem
With this implementation, we introduce two concepts: adapt and mount. Adapt refers to Hono's ability to adapt to any runtime, while mount implies that Hono can integrate with any framework. Along with middleware, these capabilities allow us to create a comprehensive ecosystem, as depicted below:
With these special features, Hono will not just be a web framework, it will be like a "Glue".
One of the greatest aspects of this concept is that the framework does not have to create individual adapters for various platforms such as Cloudflare Worker, Cloudflare Pages, Vercel, Deno, and Bun.
If your framework is based on the Web Standard API, there is no additional work required. Hono can mount it and enable your framework to run on any runtime.
Furthermore, we can use Hono's middleware for other frameworks. For example, to add Basic authentication to an application built with ittry-router, there's no need to implement it from scratch. Just add Hono's middleware.
app.use('/another-app/admin/*', basicAuth({ username, password }))
This is the ecosystem we wanted creating.
Node.js adapter server v1.0.0 has been released
The first major release of the Node.js adapter server, "v1.0.0", is now available! This version uses only the native Web Standard APIs available in Node.js v18 or higher. The size has been significantly reduced and this means we are really following to Web Standard APIs.
You can start using it right away by installing it from npm.
npm install @hono/node-server
Then, simply import the serve
function and adapt it to your Hono application.
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hono meets Node.js'))
serve(app, (info) => {
console.log(`Listening on http://localhost:${info.port}`)
})
Support for routing includes a hostname
The new getPath()
function now supports routing that includes a hostname.
const app = new Hono({
getPath: (req) => req.url.replace(/^https?:\/\//, ''),
})
app.get('www1.example.com/hello', (c) => c.text('hello www1'))
app.get('www2.example.com/hello', (c) => c.text('hello www2'))
With getPath()
, you can also handle the host header value for routing.
const app = new Hono({
getPath: (req) => req.headers.get('host') + req.url.replace(/^https?:\/\/[^\/]+/, ''),
})
app.get('www1.example.com/hello', (c) => c.text('hello www1'))
// The following request will match the route:
// new Request('http://www1.example.com/hello', {
// headers: { host: 'www1.example.com' },
// })
Support for AWS Lambda functions URLs
The AWS Lambda adapter now supports Lambda functions URLs.
Cookie Middleware
We're introducing a new Cookie Middleware.
import { getCookie, setCookie } from 'hono/cookie'
// ...
app.get('/cookie', (c) => {
const yummyCookie = getCookie(c, 'yummy_cookie')
// ...
setCookie(c, 'delicious_cookie', 'macha')
//
}
And c.req.cookie()
and c.cookie()
are deprecated and will be removed in the next major version, v4.
hono/nextjs
to hono/vercel
We've created hono/vercel
and deprecated hono/nextjs
. hono/nextjs
will be removed in v4.
Other updates
rewriteRequestPath
option for the serve-staticapp.routerName
- Support for clearing response headers
- Remove HTTP status messages from
http-status.ts
- Performance improvements
- Bug fixes
Thanks
Thank you to all our contributors!
All changes
- perf: shorten code by @yusukebe in #1051
- perf: use
===
instead ofstartsWith
andendsWith
by @yusukebe in #1053 - fix(deno): export
HTTPException
frommod.ts
by @yusukebe in #1058 - chore: update eslint by @yusukebe in #1060
- chore: move runtime tests into
runtime_tests
by @yusukebe in #1062 - feat(adapter): Added aws-handler support for APIGatewayProxyEventV2 by @schonert in #1009
- feat: Allow getPath to be replaced. by @usualoma in #1064
- feat(serve-static):
rewriteRequestPath
option for Workers/Deno/Bun by @yusukebe in #1065 - fix(jsx): fix a
jsx-runtime
bug by @yusukebe in #1070 - feat(context): clear the header with
c.header(key, undefined)
by @yusukebe in #1071 - feat: Cookie Middleware and deprecate
c.req.cookie()
/c.cookie()
by @yusukebe in #1066 - feat(adapter): add
hono/vercel
/ deprecatehono/nextjs
by @yusukebe in #1073 - fix: enable specifying router from args by @yusukebe in #1079
- fix(context): enable extending
ContextVarableMap
by @yusukebe in #1080 - feat(preset): add
hono/quick
by @yusukebe in #1074 - fix: remove
type.ts
by @yusukebe in #1082 - fix(getQueryParam): Fixed a bug in getQueryParam when a partial matching key was found. by @usualoma in #1085
- fix(context): Fix typo in charset, again. by @usualoma in #1086
- feat(adapter): AWS Lambda Adapter supports requests via Lambda Function URLs. by @watany-dev in #1076
- chore:denoify by @yusukebe in #1095
- fix(lambda): don't encode text by @yusukebe in #1091
- fix(cloudflare-workers): serveStatic
rewriteRequestPath
option by @yusukebe in #1098 - feat(app):
onError()
supports async by @yusukebe in #1090 - fix(types): set
/
for genericsbasePath
by @yusukebe in #1083 - feat(deno): export cookie middleware by @yusukebe in #1103
- fix(app): export
fire()
correctly by @yusukebe in #1106 - ci: use
setup-bun
by @yusukebe in #1108 - feat(app):
app.routerName()
by @yusukebe in #1105 - feat:
app.mount()
by @yusukebe in #1104 - fix(preset): fix constructor args by @yusukebe in #1113
- fix(router):
PatternRouter
supports a hostname, added tests by @yusukebe in #1114 - docs(readme): update by @yusukebe in #1115
- v3.2 by @yusukebe in #1117
New Contributors
- @schonert made their first contribution in #1009
- @watany-dev made their first contribution in #1076
Full Changelog: v3.1.8...v3.2.0