dynamic meta

This commit is contained in:
MapleLeaf
2021-12-31 13:16:00 -06:00
committed by Darius
parent ba6f9b1698
commit 6e18aac5bd
7 changed files with 52 additions and 45 deletions

View File

@@ -12,6 +12,7 @@
"reacord": "workspace:*", "reacord": "workspace:*",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-head": "^3.4.0",
"react-router": "^6.2.1", "react-router": "^6.2.1",
"react-router-dom": "^6.2.1" "react-router-dom": "^6.2.1"
}, },

View File

@@ -1,14 +1,18 @@
import { description } from "reacord/package.json"
import { Meta, Title } from "react-head"
import { Route, Routes } from "react-router" import { Route, Routes } from "react-router"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import { DocumentPage } from "./document-page" import { DocumentPage } from "./document-page"
import { LandingPage } from "./landing-page" import { LandingPage } from "./landing-page"
export function AppRoutes() { export function App() {
return ( return (
<> <>
<Title>Reacord</Title>
<Meta name="description" content={description} />
<nav> <nav>
<Link to="/">Home</Link> <Link to="/">Home</Link>{" "}
<Link to="docs/getting-started">Getting Started</Link> <Link to="docs/getting-started">Getting Started</Link>{" "}
<Link to="docs/api">API Reference</Link> <Link to="docs/api">API Reference</Link>
</nav> </nav>
<Routes> <Routes>

View File

@@ -1,13 +1,13 @@
import { hydrate } from "react-dom" import { hydrate } from "react-dom"
import { HeadProvider } from "react-head"
import { BrowserRouter } from "react-router-dom" import { BrowserRouter } from "react-router-dom"
import { Root } from "./root" import { App } from "./app"
import { AppRoutes } from "./routes"
hydrate( hydrate(
<Root>
<BrowserRouter> <BrowserRouter>
<AppRoutes /> <HeadProvider>
</BrowserRouter> <App />
</Root>, </HeadProvider>
document, </BrowserRouter>,
document.body,
) )

View File

@@ -1,13 +1,26 @@
import { renderToString } from "react-dom/server"
import { HeadProvider } from "react-head"
import { StaticRouter } from "react-router-dom/server" import { StaticRouter } from "react-router-dom/server"
import { Root } from "./root" import { App } from "./app"
import { AppRoutes } from "./routes"
export async function render(url: string) { export async function render(url: string) {
return ( const headTags: React.ReactElement[] = []
<Root>
const app = renderToString(
<StaticRouter location={url}> <StaticRouter location={url}>
<AppRoutes /> <HeadProvider headTags={headTags}>
</StaticRouter> <App />
</Root> </HeadProvider>
</StaticRouter>,
) )
return /* HTML */ `
<!DOCTYPE html>
<head>
${renderToString(<>{headTags}</>)}
</head>
<body>
${app}
</body>
`
} }

View File

@@ -1,20 +0,0 @@
export function Root({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="UTF-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="test description" />
<title>Reacord</title>
<script
type="module"
src={
import.meta.env.PROD ? "/entry.client.js" : "/src/entry.client.tsx"
}
/>
</head>
<body>{children}</body>
</html>
)
}

View File

@@ -1,7 +1,6 @@
import compression from "compression" import compression from "compression"
import express, { Router } from "express" import express, { Router } from "express"
import { resolve } from "node:path" import { resolve } from "node:path"
import { renderToString } from "react-dom/server"
import { createServer as createViteServer } from "vite" import { createServer as createViteServer } from "vite"
import type * as entryModule from "./entry.server" import type * as entryModule from "./entry.server"
@@ -20,10 +19,7 @@ async function createDevelopmentRouter() {
"/src/entry.server.tsx", "/src/entry.server.tsx",
)) as typeof entryModule )) as typeof entryModule
const html = await vite.transformIndexHtml( const html = await vite.transformIndexHtml(url, await render(url))
url,
renderToString(await render(url)),
)
res.status(200).set({ "Content-Type": "text/html" }).end(html) res.status(200).set({ "Content-Type": "text/html" }).end(html)
} catch (error: any) { } catch (error: any) {
@@ -47,7 +43,7 @@ function createProductionRouter() {
res res
.status(200) .status(200)
.set({ "Content-Type": "text/html" }) .set({ "Content-Type": "text/html" })
.end(renderToString(await render(req.originalUrl))) .end(await render(req.originalUrl))
} catch (error: any) { } catch (error: any) {
console.error(error) console.error(error)
res.status(500).end(error.stack || error.message) res.status(500).end(error.stack || error.message)

13
pnpm-lock.yaml generated
View File

@@ -124,6 +124,7 @@ importers:
reacord: workspace:* reacord: workspace:*
react: ^17.0.2 react: ^17.0.2
react-dom: ^17.0.2 react-dom: ^17.0.2
react-head: ^3.4.0
react-router: ^6.2.1 react-router: ^6.2.1
react-router-dom: ^6.2.1 react-router-dom: ^6.2.1
typescript: ^4.5.4 typescript: ^4.5.4
@@ -133,6 +134,7 @@ importers:
reacord: link:../reacord reacord: link:../reacord
react: 17.0.2 react: 17.0.2
react-dom: 17.0.2_react@17.0.2 react-dom: 17.0.2_react@17.0.2
react-head: 3.4.0_react-dom@17.0.2+react@17.0.2
react-router: 6.2.1_react@17.0.2 react-router: 6.2.1_react@17.0.2
react-router-dom: 6.2.1_react-dom@17.0.2+react@17.0.2 react-router-dom: 6.2.1_react-dom@17.0.2+react@17.0.2
devDependencies: devDependencies:
@@ -7489,6 +7491,17 @@ packages:
use-sidecar: 1.0.5_react@17.0.2 use-sidecar: 1.0.5_react@17.0.2
dev: false dev: false
/react-head/3.4.0_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-T+a+WTN2lQECle3KdUBTnXMpjzOTDRFS1f2jCLP9H64XBXgayxadoLkzWSiJD793zE8IMWzQ8xKe3V573es9NQ==}
peerDependencies:
react: '>=16.3'
react-dom: '>=16.3'
dependencies:
'@babel/runtime': 7.16.5
react: 17.0.2
react-dom: 17.0.2_react@17.0.2
dev: false
/react-is/16.13.1: /react-is/16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}