use suspense

This commit is contained in:
MapleLeaf
2021-12-31 17:09:09 -06:00
committed by Darius
parent 9afb8e47d2
commit d2cadb536d
8 changed files with 72 additions and 98 deletions

View File

@@ -13,6 +13,7 @@
"react": "^18.0.0-rc.0",
"react-dom": "^18.0.0-rc.0",
"react-head": "^3.4.0",
"react-router": "^6.2.1",
"react-router-dom": "^6.2.1"
},
"devDependencies": {
@@ -28,7 +29,6 @@
"compression": "^1.7.4",
"esno": "^0.13.0",
"postcss": "^8.4.5",
"react-location": "^3.3.0",
"rehype-highlight": "^5.0.2",
"remark-frontmatter": "^4.0.1",
"tailwindcss": "^3.0.8",

View File

@@ -1,12 +1,12 @@
import { description } from "reacord/package.json"
import { lazy, Suspense } from "react"
import { Meta, Title } from "react-head"
import type { ReactLocation } from "react-location"
import { Link, Outlet, Router } from "react-location"
import { routes } from "./routes"
import { Link, Route, Routes } from "react-router-dom"
import { lazyNamed } from "./helpers/lazy-named"
export function App({ location }: { location: ReactLocation }) {
export function App() {
return (
<Router location={location} routes={routes}>
<>
<Title>Reacord</Title>
<Meta name="description" content={description} />
<nav>
@@ -14,7 +14,36 @@ export function App({ location }: { location: ReactLocation }) {
<Link to="docs/getting-started">Getting Started</Link>{" "}
<Link to="docs/api">API Reference</Link>
</nav>
<Outlet />
</Router>
<Suspense fallback={<></>}>
<Routes>
<Route path="/" element={<LandingPage />} />
<Route path="docs" element={<DocumentPageLayout />}>
{docs.map(({ route, component: Component }) => (
<Route key={route} path={route} element={<Component />} />
))}
</Route>
</Routes>
</Suspense>
</>
)
}
const LandingPage = lazyNamed(
"LandingPage",
() => import("./pages/landing-page"),
)
const DocumentPageLayout = lazyNamed(
"DocumentPage",
() => import("./pages/document-page"),
)
const docs = Object.entries(import.meta.glob("./docs/*.md")).map(
([path, loadModule]) => ({
route: path.replace("./docs/", "").replace(/\.md$/, ""),
component: lazy(async () => {
const m = await loadModule()
return { default: m.default || m }
}),
}),
)

View File

@@ -1,14 +1,14 @@
import { createRoot } from "react-dom"
import { HeadProvider } from "react-head"
import { ReactLocation } from "react-location"
import { BrowserRouter } from "react-router-dom"
import { App } from "./app"
const location = new ReactLocation()
createRoot(document.querySelector("#app")!).render(
<HeadProvider>
<App location={location} />
</HeadProvider>,
<BrowserRouter>
<HeadProvider>
<App />
</HeadProvider>
</BrowserRouter>,
)
declare module "react-dom" {

View File

@@ -1,21 +1,21 @@
import { renderToString } from "react-dom/server"
import { HeadProvider } from "react-head"
import { createMemoryHistory, ReactLocation } from "react-location"
import { StaticRouter } from "react-router-dom/server"
import { App } from "./app"
export async function render(url: string) {
const headTags: React.ReactElement[] = []
const location = new ReactLocation({
history: createMemoryHistory({ initialEntries: [url] }),
})
const app = renderToString(
<HeadProvider headTags={headTags}>
<App location={location} />
</HeadProvider>,
const app = (
<StaticRouter location={url}>
<HeadProvider headTags={headTags}>
<App />
</HeadProvider>
</StaticRouter>
)
const appHtml = renderToString(app)
const scriptSource = import.meta.env.PROD
? "/entry.client.js"
: "/src/entry.client.tsx"
@@ -36,7 +36,7 @@ export async function render(url: string) {
<script type="module" src="${scriptSource}"></script>
</head>
<body>
<div id="app" style="display: contents">${app}</div>
<div id="app" style="display: contents">${appHtml}</div>
</body>
`
}

View File

@@ -0,0 +1,11 @@
import { lazy } from "react"
export function lazyNamed<
Key extends string,
Component extends React.ComponentType,
>(key: Key, loadModule: () => Promise<Record<Key, Component>>) {
return lazy<Component>(async () => {
const mod = await loadModule()
return { default: mod[key] }
})
}

View File

@@ -1,10 +1,13 @@
import { Outlet } from "react-location"
import { Suspense } from "react"
import { Outlet } from "react-router"
export function DocumentPage() {
return (
<>
<h1>Docs</h1>
<Outlet />
<Suspense fallback={<div>Loading...</div>}>
<Outlet />
</Suspense>
</>
)
}

View File

@@ -1,21 +0,0 @@
import type { Route } from "react-location"
export const routes: Route[] = [
{
path: "/",
element: () =>
import("./pages/landing-page").then((m) => <m.LandingPage />),
},
{
path: "docs",
element: () =>
import("./pages/document-page").then((m) => <m.DocumentPage />),
children: [
{
path: "*",
element: ({ params }) =>
import(`./docs/${params["*"]}.md`).then((m) => <m.default />),
},
],
},
]