Closed19

Honoでyamada-uiを動かす

Hidden comment
108えん108えん

手順
pnpm create honoする

108えん108えん

追加

client.tsx
import { UIProvider } from "@yamada-ui/react";
import { createRoot } from "react-dom/client";
import { App } from "./app"

const domNode = document.getElementById("root")!;
const root = createRoot(domNode);
root.render(
  <UIProvider>
    <App />
  </UIProvider>,
);
108えん108えん

変更
index.tsindex.tsx

index.tsx
import { Hono } from "hono"
import { renderToString } from "react-dom/server"

const app = new Hono()

app.get("*", (c) => {
  return c.html(
    renderToString(
      <html lang="ja" data-mode="light">
        <head>
          <script type="module" src="/src/client.tsx"></script>
        </head>
        <body>
          <div id="root"></div>
        </body>
      </html>,
    ),
  )
})

export default app
108えん108えん
package.json
{
+  "type": "module",
  "scripts": {
    "dev": "tsx watch src/index.ts"
  },
  "dependencies": {
    "@hono/node-server": "^1.9.0",
    "@yamada-ui/react": "^1.3.0",
    "hono": "^4.1.5",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@hono/vite-dev-server": "^0.10.0",
    "@types/node": "^20.11.17",
    "@types/react": "^18.2.73",
    "@types/react-dom": "^18.2.22",
    "tsx": "^3.12.2",
    "vite": "^5.2.6"
  }
}
108えん108えん
tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "types": [
      "node"
    ],
    "jsx": "react-jsx",
+    "jsxImportSource": "react"
-    "jsxImportSource": "hono/jsx"
  }
}
108えん108えん

ファイル追加

vite.config.ts
import devServer, { defaultOptions } from "@hono/vite-dev-server";
import { defineConfig } from "vite";

export default defineConfig(({ mode }) => {
  if (mode === "client") {
    return {
      build: {
        rollupOptions: {
          input: "./src/client.tsx",
          output: {
            entryFileNames: "static/client.js",
          },
        },
      },
      resolve: {
        alias: {
          "@": "/src",
        },
      },
    };
  } else {
    return {
      ssr: {
        external: ["react", "react-dom"],
      },
      plugins: [
        devServer({
          exclude: ["/*", ...defaultOptions.exclude],
          entry: "src/index.tsx",
        }),
      ],
      server: {
        port: 4448,
      },
      resolve: {
        alias: {
          "@": "/src",
        },
      },
    };
  }
});
108えん108えん

カラーモードとかが入る前に描画されてしまうので、cookieでとってそのままモードを格納するようにした。
(ColorModeManagerがやっていること)

index.tsx
import { ColorModeScript, ThemeSchemeScript } from "@yamada-ui/react"
import { Hono } from "hono"
import { getCookie } from "hono/cookie"
import { renderToString } from "react-dom/server"
import { config } from "./theme"

const app = new Hono()

app.get("*", (c) => {
+  const colorMode = getCookie(c, "ui-color-mode")
+  const themeScheme = getCookie(c, "ui-theme-scheme")

  return c.html(
    renderToString(
      <html lang="ja">
        <head>
          <title>Hono App - Yamada UI</title>
          <meta charSet="utf-8" />
          <meta content="width=device-width, initial-scale=1" name="viewport" />
          <link rel="icon" href="/favicon.svg" />
          <script type="module" src="/src/client.tsx"></script>
        </head>
        <body>
          <ColorModeScript
            type="cookie"
            nonce="testing"
-            initialColorMode={colorMode ?? config.initialColorMode}
+            initialColorMode={colorMode ?? config.initialColorMode}
          />
          <ThemeSchemeScript
            type="cookie"
            nonce="testing"
-            initialThemeScheme={config.initialThemeScheme}
+            initialThemeScheme={themeScheme ?? config.initialThemeScheme}
          />
          <div id="root"></div>
        </body>
      </html>,
    ),
  )
})

export default app
108えん108えん

note: index.tsxだけ先にサーバー側で生成され表示されるために、ダークモード時のフラッシュを防止するために使用しています。

このスクラップは2024/03/30にクローズされました