Logo

dev-resources.site

for different kinds of informations.

Day 10: Ho-ho-hono! 🔥

Published at
12/10/2024
Categories
webdev
deno
webadvent
honojs
Author
valeriavg
Categories
4 categories in total
webdev
open
deno
open
webadvent
open
honojs
open
Author
9 person written this
valeriavg
open
Day 10: Ho-ho-hono! 🔥

This miniature framework is one of my favourite tools! Hono is a set of dev tools for building web servers on any JavaScript runtime (Deno, Node, Cloudflare, Fastly, Lambda and others), but not only!

Let me show you what it can do.

Create new app with e.g. deno init --npm hono@latest, follow the prompts and once ready start it with the command provided in README.md, e.g.:

deno task start            
# Task start deno run --allow-net main.ts
# Listening on http://0.0.0.0:8000/
Enter fullscreen mode Exit fullscreen mode

If you open http://0.0.0.0:8000/ You can enjoy Hello Hono!.
Let's make it a tad bit more sophisticated!

Create a file called HomePage.tsx with the following contents:

import { css, Style } from "hono/css";
export default function HomePage() {
  return (
    <html>
      <head>
        <title>Ho-ho-hono!</title>
        <Style />
      </head>
      <body className={style.body}>
        <main>
          <h1>Hello, Hono!</h1>
          <p>Wow! It works!</p>
          <img
            src="https://hono.dev/images/logo-small.png"
            alt="Hono logo: fire"
          />
        </main>
      </body>
    </html>
  );
}

const style = {
  body: css`
    background-color: black;
    color: white;
    display: flex;
    flex-direction: column;
    main {
      margin: 2rem auto;
      text-align: center;
    }
  `,
};
Enter fullscreen mode Exit fullscreen mode

Then, adjust main.ts to render newly created page instead of text:

import { Context, Hono } from "hono";
import HomePage from "./HomePage.tsx"; // <- import page

const app = new Hono();

app.get("/", (c: Context) => {
  return c.html(HomePage()); // <-- render html page
});

Deno.serve(app.fetch);

Enter fullscreen mode Exit fullscreen mode

You could also change main.ts to main.tsx and use JSX instead if you prefer:

app.get("/", (c: Context) => {
  return c.html(<HomePage />);
});
Enter fullscreen mode Exit fullscreen mode

Stop and start the server again and you should be able to see a fully styled html page:

Html page with header, paragraph and Hono logo - fire

If you want to keep editing and have the server restarted automatically just add --watch to the start command in deno.json:

{
  "imports": {
    "hono": "jsr:@hono/hono@^4.6.13"
  },
  "tasks": {
    "start": "deno run --allow-net --watch main.ts"
  },
  "compilerOptions": {
    "jsx": "precompile",
    "jsxImportSource": "hono/jsx"
  }
}
Enter fullscreen mode Exit fullscreen mode

Pretty cool stack right out of the box, isn't it? And what I like about Hono is that it's minimalistic: hono/jsx or hono/css are tiny (unlike e.g. React) and yet have the same interface.

But my favourite feature is Hono's modularity! Let's say you're making a complex web service, consisting of many features, e.g.:

features/
   users/
      main.ts
   posts/
      main.ts
   comments/
      main.ts
mod.ts
Enter fullscreen mode Exit fullscreen mode

Each feature/*/main.ts could have the following code:

import { Context, Hono } from "hono";

const app = new Hono();

app.get("/{:id}", (c: Context) => {
  const { id } = c.req.param();
  return c.json({
    id,
  });
});

app.post("/", async (c: Context) => {
  const payload = await c.req.json();
  return c.json({
    ...payload,
  });
});

export default app;

Enter fullscreen mode Exit fullscreen mode

And then features/mod.ts could join those three features together like so:

import { Hono } from "hono";
import users from "./users/main.ts";
import posts from "./posts/main.ts";
import comments from "./comments/main.ts";

const app = new Hono();

app.route("/users", users);
app.route("/posts", posts);
app.route("/comments", comments);

export default app;

Enter fullscreen mode Exit fullscreen mode

And finally, all these prefixed features could be added to root main.ts:

import { Context, Hono } from "hono";
import HomePage from "./HomePage.tsx";
import features from "./features/mod.ts";

const app = new Hono();

app.get("/", (c: Context) => {
  return c.html(HomePage());
});

app.route("/api", features);

Deno.serve(app.fetch);

Enter fullscreen mode Exit fullscreen mode

Load e.g. http://0.0.0.0:8000/api/users/123 and you should see the following JSON:

{
  "id": "123"
}
Enter fullscreen mode Exit fullscreen mode

Imagine the possibilities! Not only can you mix and match little apps as you want you can also easily test them!

I definitely recommend trying Hono out and checking all the helpers and utils it has to offer!

Liked the content and would love to have more of it all year long?

Buy Me A Coffee

Featured ones: