Skip to content

v3.6.0

Compare
Choose a tag to compare
@yusukebe yusukebe released this 10 Sep 23:41
· 1005 commits to main since this release

Hono v3.6.0 is now available! Let's take a look at the new features.

Introduce c.render()

We introduce c.render() and c.setRenderer() functions.
These functions enhance Hono's response handling, allowing for more flexible and modular response structures, especially useful for defining common parts of responses, like HTML layouts.

You can set a layout using c.setRenderer() within a custom middleware, as shown below:

app.use('*', async (c, next) => {
  c.setRenderer((content) => {
    return c.html(
      <html>
        <body>
          <p>{content}</p>
        </body>
      </html>
    )
  })
  await next()
})

Then, you can utilize c.render() to create responses within this layout:

app.get('/', (c) => {
  return c.render('Hello!')
})

The output of which will be:

<html><body><p>Hello!</p></body></html>

Additionally, this feature offers the flexibility to customize arguments. To ensure type safety, types can be defined as:

declare module 'hono' {
  interface ContextRenderer {
    (content: string, head: { title: string }): Response
  }
}

Here's an example of how you can use this:

app.use('/pages/*', async (c, next) => {
  c.setRenderer((content, head) => {
    return c.html(
      <html>
        <head>
          <title>{head.title}</title>
        </head>
        <body>
          <header>{head.title}</header>
          <p>{content}</p>
        </body>
      </html>
    )
  })
  await next()
})

app.get('/pages/my-favorite', (c) => {
  return c.render(<p>Ramen and Sushi</p>, {
    title: 'My favorite',
  })
})

app.get('/pages/my-hobbies', (c) => {
  return c.render(<p>Watching baseball</p>, {
    title: 'My hobbies',
  })
})

Using c.render() with JSX and html middleware, you can create HTML pages more easily!

Introduce c.var

The next feature we're introducing is c.var.

Before this release, to access the actual value of a variable, you had to use c.get():

const client = c.get('client')

Now, with c.var, a more intuitive syntax is available:

const result = c.var.client.oneMethod()
Screenshot 2023-09-04 at 22 54 18

For instance, you can set an instance of the client for accessing an API with a middleware and then retrieve it using c.var.client:

const app = new Hono<{
  Variables: {
    client: Client
  }
}>()

app.use('*', async (c, next) => {
  c.set('client', new ApiClient())
  await next()
})

app.get('/', (c) => {
  const books = c.var.client.getBooks()
  //...
})

FC for JSX

The type FC is exported from hono/jsx. You can use it to specify types for your function components.

import type { FC } from 'hono/jsx'

const Layout: FC<{ title: string }> = (props) => {
  return (
    <html>
      <head>
        <title>{props.title}</title>
      </head>
      <body>{props.children}</body>
    </html>
  )
}

const Top = (
  <Layout title='Home page'>
    <h1>Hono</h1>
    <p>Hono is great</p>
  </Layout>
)

$url() in Hono Client

You can get a URL object for accessing the the endpoint by using $url().

const route = app.get('/api/foo/bar', (c) => c.jsonT({ foo: 'bar' }))

const client = hc<typeof route>('http://localhost:8787/')
const url = client.api.foo.bar.$url()
console.log(url.pathname) // `/api/foo/bar`

Thanks @renzor-fist !

Factory helper

Now, Hono offers a middleware factory method to create a middleware handler.

import { middleware } from 'hono/factory'

const mw = (message: string) =>
  middleware(async (c, next) => {
    await next()
    c.header('X-Message', message)
  })

By defining your middleware with middleware, the appropriate types will be added.

Vite dev-server for Hono

Now, we introduce a new Vite Plugin to enhance developing your Hono application.

@hono/vite-dev-server is a Vite Plugin that provides a custom dev-server for fetch-based web applications like those using Hono.
You can develop your application with Vite. It's fast.

Features

  • Support any fetch-based applications.
  • Hono applications run on.
  • Fast by Vite.
  • HMR.
  • Supporting Cloudflare Bindings.
  • Also runs on Bun.

Demo

Screen.Recording.2023-09-07.at.15.05.25.mov

Usage

Installation

You can install vite and @hono/vite-dev-server via npm.

npm i -D vite @hono/vite-dev-server

Or you can install them with Bun.

bun add vite @hono/vite-dev-server

Settings

Add "type": "module" to your package.json. Then, create vite.config.ts and edit it.

import { defineConfig } from 'vite'
import devServer from '@hono/vite-dev-server'

export default defineConfig({
  plugins: [
    devServer({
      entry: 'src/index.ts', // The file path of your application.
    }),
  ],
})

Development

Just run vite.

npm exec vite

Or

bunx --bun vite

See more details

Visit the GitHub project: https://github.com/honojs/vite-plugins/tree/main/packages/dev-server

Deprecate some properties in HonoRequest

These properties in the HonoRequest have been deprecated.

  • headers()
  • body()
  • bodyUsed()
  • integrity()
  • keepalive()
  • referrer()
  • signal()

For instance, if you want to use headers, please use c.req.raw.headers().

Replaced Jest with Vitest

This might not be a new feature, but it's a significant change.

We've switched the test framework used in Hono's core project from Jest to Vitest! It's fast!

Screenshot 2023-09-11 at 7 49 07

Thanks @ThatOneBro for the great work!

All Updates

New Contributors

Full Changelog: v3.5.8...v3.6.0