Tech Blog

HonoX を試してみる

Static Site Generation、 ファイルベースルーティング に対応した Hono + Vite の軽量なメタフレームワーク HonoX が気になったので Bun で触ってみる

今回の環境

TL;DR

1. 環境を用意する

  // .devcontainer/devcontainer.json
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
+ // README at: https://github.com/devcontainers/templates/tree/main/src/debian
+ {
+ 	"name": "Debian",
+ 	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
+ 	"image": "mcr.microsoft.com/devcontainers/base:bullseye",
+ 	"runArgs": [ "--init", "--ulimit", "memlock=-1:-1" ],
+
+ 	// Features to add to the dev container. More info: https://containers.dev/features.
+ 	"features": {
+ 		"ghcr.io/devcontainers/features/git:1": {}
+ 	},
+
+ 	// Use 'forwardPorts' to make a list of ports inside the container available locally.
+ 	// "forwardPorts": [],
+
+ 	// Configure tool-specific properties.
+ 	// "customizations": {},
+
+ 	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ 	// "remoteUser": "root"
+
+ 	"remoteEnv": {
+ 		"EDITOR": "code --wait"
+ 	},
+
+ 	// Use 'postCreateCommand' to run commands after the container is created.
+ 	"postCreateCommand": ".devcontainer/postcreate.sh"
+ }
+
  # .devcontainer/postcreate.sh
+ #!/bin/sh
+ # vim:sw=4:ts=4:et
+
+ set -e
+
+ # set git safe directory
+ git config --global --add safe.directory $(pwd)
+
+ curl -fsSL https://bun.sh/install | bash
+
bun --version
1.1.24

2. HonoX をインストールする

bun create hono@latest my-app
create-hono version 0.12.0
✔ Using target directory … my-app
? Which template do you want to use?
  aws-lambda
  bun
  cloudflare-pages
  cloudflare-workers
  deno
  fastly
  lambda-edge
  netlify
  nextjs
  nodejs
  vercel
❯ x-basic
✔ Cloning the template
? Do you want to install project dependencies? no
🎉 Copied project files
Get started with: cd my-app
mv -fv my-app/{.,}* .
renamed 'my-app/.gitignore' -> './.gitignore'
renamed 'my-app/app' -> './app'
renamed 'my-app/package.json' -> './package.json'
renamed 'my-app/public' -> './public'
renamed 'my-app/tsconfig.json' -> './tsconfig.json'
renamed 'my-app/vite.config.ts' -> './vite.config.ts'
renamed 'my-app/wrangler.toml' -> './wrangler.toml'
rm -rfv my-app/ wrangler.toml
removed directory 'my-app/'
removed 'wrangler.toml'
  // package.json
  {
    "name": "basic",
    "type": "module",
    "scripts": {
-     "dev": "vite",
+     "dev": "bunx --bun vite --host"
-     "build": "vite build --mode client && vite build",
-     "preview": "wrangler pages dev",
-     "deploy": "$npm_execpath run build && wrangler pages deploy"
    },
    "private": true,
    "dependencies": {
      "hono": "^4.5.5",
      "honox": "^0.1.23"
    },
    "devDependencies": {
-     "@cloudflare/workers-types": "^4.20240529.0",
-     "@hono/vite-cloudflare-pages": "^0.4.2",
      "@hono/vite-dev-server": "^0.14.0",
-     "vite": "^5.2.12",
+     "vite": "^5.2.12"
-     "wrangler": "^3.57.2"
    }
  }
  // tsconfig.json
  {
    "compilerOptions": {
      "target": "ESNext",
      "module": "ESNext",
      "moduleResolution": "Bundler",
      "strict": true,
      "skipLibCheck": true,
      "lib": [
        "ESNext",
        "DOM"
      ],
      "types": [
-       "vite/client",
+       "vite/client"
-       "@cloudflare/workers-types/2023-07-01"
      ],
      "jsx": "react-jsx",
      "jsxImportSource": "hono/jsx"
    },
    "include": [
      "**/*.ts",
      "**/*.tsx"
    ]
  }

  // vite.config.ts
- import pages from '@hono/vite-cloudflare-pages'
- import adapter from '@hono/vite-dev-server/cloudflare'
  import honox from 'honox/vite'
  import { defineConfig } from 'vite'

  export default defineConfig({
-   plugins: [honox({ devServer: { adapter } }), pages()]
+   plugins: [honox()]
  })

bun install
bun install v1.1.24 (85a32991)

+ @hono/vite-dev-server@0.14.0
+ vite@5.4.1
+ hono@4.5.5
+ honox@0.1.24

137 packages installed [5.10s]
bun run dev
$ bunx --bun vite --host

  VITE v5.4.1  ready in 999 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: http://172.17.0.3:5173/
  ➜  press h + enter to show help
(!) Could not auto-determine entry point from rollupOptions or html files and there are no explicit optimizeDeps.include patterns. Skipping dependency pre-bundling.

my-app

3. SSG 対応

bun add --dev @hono/vite-ssg
bun install v1.1.24 (85a32991)

 installed @hono/vite-ssg@0.1.0

 1 package installed [1.96s]
  // vite.config.ts
+ import ssg from '@hono/vite-ssg'
  import honox from 'honox/vite'
  import { defineConfig } from 'vite'

+ const entry = './app/server.ts'

  export default defineConfig({
-   plugins: [honox()]
+   plugins: [honox(), ssg({ entry })]
  })

bunx --bun vite build
vite v5.4.1 building for production...
✓ 1 modules transformed.
rendering chunks (1)...GET  /
dist/index.html  0.43 kB │ gzip: 0.29 kB
✓ built in 246ms
ls -la dist/
drwxr-xr-x  5 vscode vscode   128 Aug 15 23:58 .
drwxr-xr-x 13 vscode vscode   416 Aug 16 00:00 ..
-rw-r--r--  1 vscode vscode 15406 Aug 15 23:58 favicon.ico
-rw-r--r--  1 vscode vscode   474 Aug 15 23:58 index.html

4. MDX 対応

bun add --dev @mdx-js/rollup remark-frontmatter remark-mdx-frontmatter
bun install v1.1.24 (85a32991)

 installed @mdx-js/rollup@3.0.1
 installed remark-frontmatter@5.0.0
 installed remark-mdx-frontmatter@5.0.0

 120 packages installed [4.38s]
  // vite.config.ts
+ import mdx from '@mdx-js/rollup'
  import honox from 'honox/vite'
+ import remarkFrontmatter from 'remark-frontmatter'
+ import remarkMdxFrontmatter from 'remark-mdx-frontmatter'
  import { defineConfig } from 'vite'

  export default defineConfig({
-   plugins: [honox()]
+   plugins: [
+     honox(),
+     mdx({
+       jsxImportSource: 'hono/jsx',
+       remarkPlugins: [remarkFrontmatter, remarkMdxFrontmatter],
+     }),
+   ]
  })

  // app/routes/_renderer.tsx
  import { Style } from 'hono/css'
  import { jsxRenderer } from 'hono/jsx-renderer'
- import { Script } from 'honox/server'

- export default jsxRenderer(({ children, title }) => {
+ export default jsxRenderer(({ children, frontmatter }) => {
    return (
      <html lang="en">
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-         <title>{title}</title>
+         <title>{frontmatter.title}</title>
          <link rel="icon" href="/favicon.ico" />
-         <Script src="/app/client.ts" async />
          <Style />
        </head>
        <body>{children}</body>
      </html>
    )
  })

rm -fv app/routes/index.tsx
removed 'app/routes/index.tsx'
  // app/routes/index.mdx
+ ---
+ title: Hello World
+ ---
+
+ ## Hollo World
+
+ This is a test
+
bunx --bun vite build
vite v5.4.1 building for production...
✓ 1 modules transformed.
rendering chunks (1)...GET  /
dist/index.html  0.14 kB │ gzip: 0.12 kB
✓ built in 266ms
bunx --bun vite preview --host
  ➜  Local:   http://localhost:4173/
  ➜  Network: http://172.17.0.3:4173/
  ➜  press h + enter to show help

Hello World

参考にしたページ