Skip to content
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

Tips for rpc perf #490

Merged
merged 6 commits into from
Sep 17, 2024
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions docs/guides/rpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,91 @@ export type AppType = typeof routes
```

You can now create a new client using the registered AppType and use it as you would normally.

## Known issues
### IDE performance
When using RPC, the more routes you have, the slower your IDE will become. One of the main reasons for this is that massive amounts of type instantiations are executed to infer the type of your app.

For example, suppose your app has a route like this:

```ts
// index.ts
const app = new Hono()
.get('foo/:id', (c) => c.json({ ok: true }, 200))

export default app
```

Hono will infer the type as follows:

```ts
const app = Hono<BlankEnv, BlankSchema, "/">()
.get<
"foo/:id",
"foo/:id",
JSONRespondReturn<{ ok: boolean }, 200>,
BlankInput,
BlankEnv
>('foo/:id', (c) => c.json({ ok: true }, 200))
```

This is a type instantiation for a single route. While the user doesn't need to write these type arguments manually, which is a good thing, it's known that type instantiation takes much time. `tsserver` does this time consuming task every time you use the app. If you have a lot of routes, this can slow down your IDE significantly.

However, we have some tips to mitigate this issue.

#### compile your app before using it (recommended)
Copy link
Member

@yusukebe yusukebe Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write the specific instructions for using d.ts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

`d.ts` for `index.ts` is like this:

```ts
// index.d.ts
import { Hono } from 'hono';
declare const app: Hono<import("hono/types").BlankEnv, {
"foo/:id": {
$get: {
input: {
param: {
id: string;
};
};
output: {
ok: boolean;
};
outputFormat: "json";
status: 200;
};
};
}, "/">;
export default app;
```

Now `tsserver` doesn't instantiate type arguments of `app` every time you use it because it's already done. It will make your IDE a lot faster!

#### specify type arguments manually
This is a bit cumbersome, but you can specify type arguments manually to avoid type instantiation.

```ts
const app = new Hono()
.get<'foo/:id'>('foo/:id', (c) => c.json({ ok: true }, 200))
```

Specifying just single type argument make a difference in performance, while it may take you a lot of time and effort if you have a lot of routes.

#### split your app and client into multiple files
As described in [Using RPC with larger applications](#using-rpc-with-larger-applications), you can split your app into multiple apps. You can also create a client for each app:

```ts
// authors-cli.ts
import { app as authorsApp } from './authors'
import { hc } from 'hono/client'

const authorsClient = hc<typeof authorsApp>('/authors')

// books-cli.ts
import { app as booksApp } from './books'
import { hc } from 'hono/client'

const booksClient = hc<typeof booksApp>('/books')
```

This way, `tsserver` doesn't need to instantiate types for all routes at once.