Open1

hono + pages, react-dom SSR お試し

knaka Tech-Blogknaka Tech-Blog

概要

hono で、SSRを react-dom/server使うメモになります。

  • フルスタック構成ですが、今回はSSRの内容です。

[投稿日: 2023/11/18]


環境

  • hono: 3.9.0
  • vite: 4.5.0
  • cloudflare pages
  • react-dom

作成したコード

https://github.com/kuc-arc-f/hono_vite_22react


  • package.json
{
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build && vite build --mode client",
    "preview": "wrangler pages dev dist",
    "deploy": "$npm_execpath run build && wrangler pages deploy dist"
  },
  "dependencies": {
    "hono": "^3.9.0",
    "htm": "^3.1.1",
    "marked": "^10.0.0",
    "micromodal": "^0.4.10",
    "preact": "^10.18.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@cloudflare/workers-types": "^4.20230914.0",
    "@hono/vite-cloudflare-pages": "^0.0.2",
    "@hono/vite-dev-server": "^0.0.12",
    "@preact/preset-vite": "^2.6.0",
    "@types/react": "^18.2.37",
    "@types/react-dom": "^18.2.15",
    "autoprefixer": "^10.4.16",
    "postcss": "^8.4.31",
    "tailwindcss": "^3.3.5",
    "vite": "^4.5.0",
    "wrangler": "^3.14.0"
  }
}


  • tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "lib": [
      "ESNext"
    ],
    "types": [
      "@cloudflare/workers-types",
      "vite/client"
    ],
    "jsx": "react-jsx"
  },
}

  • pages/test/App.tsx
App.tsx
import React from 'react';

//
export default function Page(props: any) {
    return (
    <div>
        <h1 className="text-4xl font-bold">Test/App.tsx</h1>
        {/* JS */}
        {import.meta.env.PROD ? (
            <script type="module" src="/static/Page2.js"></script>
        ) : (
            <script type="module" src="/src/client/Page2.ts"></script>
        )}        
    </div>
    )
}


  • index.tsx
index.tsx

import Test1 from './pages/test/App';

app.get('/test1', async (c) => { 
  return c.html(renderToString(Test1([])));
});

  • pages/test2/App.tsx: List
App.tsx
import React from 'react';
import { marked } from 'marked';

const messages = ['Good Morning', 'Good Evening', 'Good Night']
//
export default function Page(props: any) {
//console.log(props);
    //
    return (
    <div>
        <h1 className="text-4xl font-bold">Test2</h1>
        <hr className="my-2" />
        <ul>
        {messages.map((message: any, index: number) => {
            return (<li className="my-2" key={index} 
            >{message}!!</li>)
        })}
        </ul>
        <hr className="my-2" />
    </div>
    )
}

MD変換の例

  • pages/test3/App.tsx: dangerouslySetInnerHTML 使う例です
App.tsx
import React from 'react';
import { marked } from 'marked';

const testMD = `
### hoge
***
* 123
* 145
***
* CCC
`
//
export default function Page(props: any) {
    const content = marked.parse(testMD);
console.log(content);
    //
    return (
    <div>
        <h1 className="text-4xl font-bold">Test3</h1>
        <hr className="my-2" />
        <pre dangerouslySetInnerHTML={{ __html: content }} />
        <hr className="my-2" />
        {/* JS */}
        {import.meta.env.PROD ? (
            <script type="module" src="/static/Page2.js"></script>
        ) : (
            <script type="module" src="/src/client/Page2.ts"></script>
        )}        
    </div>
    )
}