-
-
Notifications
You must be signed in to change notification settings - Fork 621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
v5: hono/build
#3659
Comments
Quick response. Rather than AOT, it would be nice to have a build script or bundler that writes out an optimal application "file" that includes the |
I forgot, but we discussed this issue - creating a build script or bundler - in this project Issue or PR with @usualoma. |
I have seen And you as said, it currently depends on Function, so it won't work with Cloudflare workers, etc. |
I’ve also been considering a feature like this for Hono, and I agree with @yusukebe on incorporating a build script. I recall we previously discussed this topic while comparing the speeds of Hono and Elysia with AOT compilation. Rather than embedding this directly into the router, integrating it into something like Honox might be more effective. The code/logic is already modularized with nested routes, allowing us to implement a script that merges these routes into a single, optimized Hono app. This approach could enhance performance across different runtimes. The key question now is which specific optimizations we could include in the build script to maximize efficiency. Thoughts? |
Even if we choice to build, we need the logic of code generation for optimization, so we will work on new PreparedRouter({
preparedMatch: () => {
...
} // precompiled
}) It should be able to be utilized when build. |
I don't know if that's possible, but if we can make good use of Parcel's macros, the prepared router will seem to make sense. The macros also work with Vite etc. |
But, IMO, we don't have to implement the |
I'm also interested in this area, and it's worth considering if there is a good approach. I'm also interested in macros. The reasons I considered this with "honox" before are as follows.
It isn't easy to prepare for apps that don't use static routing (use variables). I think that apps that use variables are in the minority, but I think it's inevitable that there will be conditions that determine whether or not they can be applied. There are currently |
What do you think about anything other than routing? For example, define a schema for the incoming JSON. After building the app, an optimized JSON parser is written in the build script. The parsing is then much faster than normally using |
some initial ideas -
|
Haha, topics are getting bigger! But I have the most fun when we talk about these things. |
It is why elysia is fast. I want Hono to implement it. And my personal opinion, build-time building is better than run-time building. Outputting code can reduce build size. |
Yes, exactly (though I don't want to fight with Elysia). |
|
In the future it may depend external package such as TypeScript compiler API and babel. So I think it should be in hono/middleware or other repo, and create |
+1 |
Most of the work has been completed. I will only write a brief description when school is over. |
Precompiled Prepared Router (Example)new function(){let t=function t(e,n,r,u,l,[i]){let o=l[n];if(o){let a=o[e]||o.ALL;if(a)return[a]}let f=u[n],p=f&&(f[e]||f.ALL)||[];Object.create(null);let c=n.split("/");if("GET"===e&&"bar"===c[1]&&3===c.length&&!0==!!c[2]){let h=new r;h.id=c[2],p.push([i,h,1])}return p.length>1&&p.sort((t,e)=>t[2]-e[2]),[p.map(([t,e])=>[t,e])]},e=Object.create(null),n=(()=>{let t=function(){};return t.prototype=e,t})(),r={"/baz/baz":{ALL:[]}},u={"/foo":{GET:[]}},l=[];return{name:"PreparedRouter",add:function(t,n,i){t in(r[n]||e)?r[n][t].push([i,e]):t in(u[n]||e)?u[n][t].push([i,e]):l.push(i)},match:function(e,i){return t(e,i,n,r,u,l)}}}; router.add('GET', '/foo', 'foo')
router.add('GET', '/bar/:id', 'bar + :id')
router.add('ALL', '/baz/baz', 'baz + baz')
function anonymous(method, path, createParams, staticHandlers, preparedHandlers, {
handler1,
handler2,
handler3,
handler4,
handler5,
handler6,
handler7
}) {
const preparedMethods = preparedHandlers[path];
const preparedResult = preparedMethods?.[method]
if (preparedResult) {
return preparedResult;
}
const matchResult = [];
const emptyParams = new createParams();
const pathParts = path.split('/');
if (method === 'GET') {
if (!!pathParts[2] === true) {
if (pathParts[1] === 'event') {
if (pathParts.length === 3) {
const params = new createParams();
params.id = pathParts[2];
matchResult.push({
handler: handler3,
params: params,
order: 5
})
} else if (pathParts.length === 4) {
if (pathParts[3] === 'comments') {
const params = new createParams();
params.id = pathParts[2];
matchResult.push({
handler: handler4,
params: params,
order: 6
})
}
}
} else if (pathParts[1] === 'map') {
if (pathParts.length === 4) {
if (pathParts[3] === 'events') {
const params = new createParams();
params.location = pathParts[2];
matchResult.push({
handler: handler6,
params: params,
order: 8
})
}
}
}
}
if (pathParts[1] === 'user') {
if (pathParts[2] === 'lookup') {
if (pathParts.length === 5) {
if (!!pathParts[4] === true) {
if (pathParts[3] === 'username') {
const params = new createParams();
params.username = pathParts[4];
matchResult.push({
handler: handler1,
params: params,
order: 3
})
} else if (pathParts[3] === 'email') {
const params = new createParams();
params.address = pathParts[4];
matchResult.push({
handler: handler2,
params: params,
order: 4
})
}
}
}
}
} else if (pathParts[1] === 'static') {
if (pathParts.length >= 2) {
matchResult.push({
handler: handler7,
params: emptyParams,
order: 11
})
}
}
} else if (method === 'POST') {
if (pathParts[1] === 'event') {
if (!!pathParts[2] === true) {
if (pathParts.length === 4) {
if (pathParts[3] === 'comment') {
const params = new createParams();
params.id = pathParts[2];
matchResult.push({
handler: handler5,
params: params,
order: 7
})
}
}
}
}
}
if (matchResult.length > 1) {
matchResult.sort((a, b) => a.order - b.order);
}
return [matchResult.map(({
handler,
params
}) => [handler, params])];
};
Initialization is as fast as And it generates matchers as smartly as By introducing the concept of precompilation, I will make the slides about this later. summary for all together
Hono RegExpRouter
1.21x faster than Memoirist
1.29x faster than Hono PreparedRouter
1.41x faster than koa-tree-router
1.57x faster than @medley/router
1.72x faster than rou3
1.87x faster than radix3
2.39x faster than trek-router
3.04x faster than find-my-way
4.04x faster than Hono PatternRouter
5.11x faster than koa-router
12.22x faster than Hono TrieRouter
16.09x faster than express (WARNING: includes handling)
(Deno v2) // 1
summary for all together
Memoirist
1.09x faster than Hono RegExpRouter
1.23x faster than Hono PreparedRouter
1.26x faster than @medley/router
2.13x faster than radix3
2.28x faster than rou3
2.9x faster than find-my-way
3.01x faster than koa-tree-router
4.06x faster than Hono PatternRouter
4.7x faster than trek-router
5.28x faster than koa-router
10.92x faster than Hono TrieRouter
14.45x faster than express (WARNING: includes handling)
// 2
summary for all together
Memoirist
1.14x faster than Hono RegExpRouter
1.3x faster than @medley/router
1.4x faster than Hono PreparedRouter
2.11x faster than radix3
2.35x faster than rou3
2.45x faster than koa-tree-router
2.95x faster than find-my-way
4.06x faster than trek-router
4.22x faster than Hono PatternRouter
5.55x faster than koa-router
10.22x faster than Hono TrieRouter
12.91x faster than express (WARNING: includes handling)
// 3
summary for all together
Memoirist
1.07x faster than Hono PreparedRouter
1.11x faster than Hono RegExpRouter
1.33x faster than @medley/router
2.08x faster than radix3
2.36x faster than rou3
2.85x faster than koa-tree-router
2.91x faster than find-my-way
3.96x faster than Hono PatternRouter
4.35x faster than trek-router
5.25x faster than koa-router
11.09x faster than Hono TrieRouter
12.83x faster than express (WARNING: includes handling)
(Bun)
When precompile is performed, it speeds up the process, perhaps due to optimization. |
Since then, several optimizations have been made, |
summary for all together
Hono PreparedRouter (precompiled)
1.05x faster than Memoirist
1.09x faster than Hono PreparedRouter
1.12x faster than Hono RegExpRouter
1.37x faster than @medley/router
2.05x faster than radix3
2.09x faster than rou3
2.34x faster than koa-tree-router
3.24x faster than find-my-way
4.34x faster than Hono PatternRouter
4.56x faster than trek-router
5.43x faster than koa-router
10.23x faster than Hono TrieRouter
10.7x faster than express (WARNING: includes handling)
24.23x faster than Hono LinearRouter Fastest in Bun. |
I think we've gone fast spped enough, so we can move on to the next step. const app = new Hono({
router: new PreparedRouter()
}) after build const app = new Hono({
router: new (function() {...})()
}) I think it is fast enough without building on runtimes other than edge. |
I would like to hear your opinions. |
I'm creating a new router named "PreparedRouter" using AOT.
This issue is a thread to solicit opinions on concerns.
The text was updated successfully, but these errors were encountered: