honojs / hono

Web framework built on Web Standards
https://hono.dev
MIT License
18.63k stars 523 forks source link

JSX middleware #300

Closed yusukebe closed 2 years ago

yusukebe commented 2 years ago

We want to have JSX middleware. This was discussed in this issue #289 .

I want to make the following:

Code example:

import { Hono } from 'hono'
import { jsx } from 'hono/jsx'
import { Header, Footer } from './component'

const app = new Hono()

const Layout = (props) => {
  <html>
    <body>{props.children}</body>
  </html>
}

type Props = {
  message: string
}

const Top = <Props>(props) => {
  return (
    <Layout>
      <Header />
        <h1>{ props.message }</h1>
      <Footer />
    </Layout>
  )
}

app.get('/', (c) => {
  const message = 'Hello Hono!'
  return c.render(<Top message={message} />)
})

app.fire()
metrue commented 2 years ago

Maybe we can check this project https://github.com/flareact/flareact

yusukebe commented 2 years ago

I know the Flareact. It seems to be a good framework like Next.js for Cloudflare Workers. And now, there is Remix that works in Cloudflare Workers. If I build a large website, I'll use one of these frameworks.

But, if I build a few small HTML pages, it's cumbersome to use these React-based frameworks. In the case of Hono, I want a tiny function to make HTML. It should not be React and having Virtual Dom. But, JSX is easy to write. So, I want a middleware that outputs HTML strings with JSX syntax.

And.. isn't it pretty cool that we can use JSX in Hono:)

usualoma commented 2 years ago

@yusukebe I have an idea for a (ultra?) fast JSX engine implementation specifically for SSR.

Summary

The implementation of this branch is short and beautiful, I love it. https://github.com/honojs/hono/tree/feat/jsx

However, I think that it would be more optimized if it were dedicated to SSR.

Idea

At the first rendering, the static and dynamic parts are separated and serialized into an array.

https://github.com/honojs/hono/compare/feat/jsx...usualoma:poc-feat-jsx-with-jit

[
  '<html><head><title data-xxx="',
  [Function: lazy],
  '">Handle &lt;&gt; Event</title><meta name="description" content="',
  [Function: lazy],
  '"></meta><head prefix="og: http://ogp.me/ns#"></head><meta property="og:type" content="article"></meta><meta property="og:title" content="',
  [Function: lazy],
  '"></meta><meta property="og:site_name" content="家系ラーメン食べたい!"></meta><meta property="og:image" content="',
  [Function: lazy],
  '"></meta></head><body>',
  [Function: lazy] { map: [Function (anonymous)] },
  '</body></html>'
]

The following benchmark results were obtained in my environment. The current branch is a POC, so the results may change as we fix bugs and add features, but generally the results will be similar to this. Also, as the number of HTML elements increases, the performance difference becomes greater. Not all use cases can take advantage of this optimization, but many cases can be covered for small applications.

jsx x 46,519 ops/sec ±1.54% (87 runs sampled)
jsx - with jit x 84,935 ops/sec ±1.36% (88 runs sampled)
jsx - nano-jsx x 34,598 ops/sec ±1.00% (93 runs sampled)
Fastest is jsx - with jit
usualoma commented 2 years ago

( Oops, I forgot to push some of the commits, so I updated poc-feat-jsx-with-jit branch. )

usualoma commented 2 years ago

With b59c828

jsx x 48,007 ops/sec ±2.35% (82 runs sampled)
jsx - with jit x 100,372 ops/sec ±1.10% (91 runs sampled)
jsx - nano-jsx x 34,042 ops/sec ±1.51% (89 runs sampled)
Fastest is jsx - with jit
usualoma commented 2 years ago

But, well, also I think it is a good option to keep JSX implementation simple in the Hono, and if we want to do more optimization, we create another repository.

yusukebe commented 2 years ago

Hi @usualoma !

It's really ultrafast! And, your implementation is great!

However, as you point out, I think it's important to keep it simple. The main parts of Hono such as routers, compose, or context should be tuned, but I want to make the middleware simple.

if we want to do more optimization, we create another repository.

That's a good idea! There is no JSX library that is optimized for SSR. People are believing JSX is just for React things. But, we know JSX is just syntax.

So, I will keep implementing the JSX middleware in the branch, we should add more tests and add other features ( have to make dangerouslySetInnerHTML??). Please don't stop helping.

PS. The coupling of JSX SSR and Hotwire is interesting. Because Hono+JSX is more like Rails that React framework. Hotwire will be a good match. Don't you think so?

https://twitter.com/yusukebe/status/1532872756466855936

usualoma commented 2 years ago

So, I will keep implementing the JSX middleware in the branch, we should add more tests and add other features ( have to make dangerouslySetInnerHTML??). Please don't stop helping.

👌

JSX SSR and Hotwire

I too think it's great to be able to use JSX SSR and Hotwire to generate HTML strings and still improve the UX without the development costs!