Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Oct 21, 2023
1 parent 8989ece commit 2101635
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 58 deletions.
6 changes: 3 additions & 3 deletions src/app/index.client.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as ReactDOM from 'react-dom/client'
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
import { routes } from './routes.js'
import { routesObjects } from './routes.js'
import { hydrateLazyRoutes } from './utils.js'

hydrate()

async function hydrate() {
await hydrateLazyRoutes(routes)
const router = createBrowserRouter(routes)
await hydrateLazyRoutes(routesObjects)
const router = createBrowserRouter(routesObjects)
ReactDOM.hydrateRoot(document.getElementById('app')!, <RouterProvider router={router} />)
}
27 changes: 4 additions & 23 deletions src/app/index.server.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Request } from '@tinyhttp/app'
import * as ReactDOMServer from 'react-dom/server'
import { Helmet } from 'react-helmet'
import { Route, Routes } from 'react-router-dom'
import { Routes } from 'react-router-dom'
import {
type StaticHandlerContext,
StaticRouter,
Expand All @@ -10,35 +10,21 @@ import {
createStaticRouter,
} from 'react-router-dom/server.js'

import { routes } from './routes.js'
import { routesElements, routesObjects } from './routes.js'
import { createFetchRequest } from './utils.js'

export async function prerender(location: string) {
const unwrappedRoutes = await Promise.all(
routes.map(async (route) => {
const lazyRoute = await route.lazy()
return {
path: route.path,
element: lazyRoute.element,
}
}),
)

const body = ReactDOMServer.renderToString(
<StaticRouter location={location}>
<Routes>
{unwrappedRoutes.map((route) => (
<Route key={route.path} path={route.path} element={route.element} />
))}
</Routes>
<Routes>{routesElements}</Routes>
</StaticRouter>,
)

return { head: head(), body }
}

export async function render(req: Request) {
const { query, dataRoutes } = createStaticHandler(routes)
const { query, dataRoutes } = createStaticHandler(routesObjects)
const fetchRequest = createFetchRequest(req)
const context = (await query(fetchRequest)) as StaticHandlerContext

Expand All @@ -55,16 +41,11 @@ export async function render(req: Request) {

function head() {
const helmet = Helmet.renderStatic()

const themeKey = 'vocs.theme'
const themeScript = `<script>(function(){"use strict";function n(){const e=typeof localStorage<"u"?localStorage.getItem("${themeKey}"):null,m=typeof window<"u"?window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark":null;return{storageTheme:e,systemTheme:m}}const o=window.matchMedia("(prefers-color-scheme: dark)"),{storageTheme:t,systemTheme:a}=n(),d=t||a||"dark";document.documentElement.classList.add(d),t||o.addEventListener("change",({matches:e})=>{document.documentElement.classList.add(e?"dark":"light");document.documentElement.classList.replace(e?"light":"dark",e?"dark":"light")})})();</script>`

return `
${helmet.title.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
${helmet.style.toString()}
${helmet.script.toString()}
${themeScript}
`
}
11 changes: 0 additions & 11 deletions src/app/main.tsx

This file was deleted.

7 changes: 7 additions & 0 deletions src/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type ReactNode } from 'react'
import { useApplyCssTransition } from './hooks/useApplyCssTransition.js'

export function Root({ children }: { children: ReactNode }) {
useApplyCssTransition()
return <div className="vocs">{children}</div>
}
56 changes: 36 additions & 20 deletions src/app/routes.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { MDXComponents } from 'mdx/types.js'
import { Helmet } from 'react-helmet'
import { type RouteObject } from 'react-router-dom'
import { Outlet, Route, type RouteObject, createRoutesFromElements } from 'react-router-dom'
import { routes as routes_virtual } from 'virtual:routes'

import { A } from './components/A.js'
import { CodeGroup } from './components/CodeGroup.js'
import { FrontmatterHead } from './components/FrontmatterHead.js'
import { Main } from './main.js'
import { Root } from './root.js'

const components: MDXComponents = {
a: A,
Expand All @@ -16,21 +16,37 @@ const components: MDXComponents = {
},
}

export const routes = routes_virtual.map((route_virtual) => ({
path: route_virtual.path,
lazy: async () => {
const { frontmatter, head, ...route } = await route_virtual.lazy()
return {
...route,
element: (
<>
{head && <Helmet>{head}</Helmet>}
{frontmatter && <FrontmatterHead frontmatter={frontmatter} />}
<Main>
<route.default components={components} />
</Main>
</>
),
} satisfies RouteObject
},
}))
export const routesElements = (
<Route
path="/"
element={
<Root>
<Outlet />
</Root>
}
>
{routes_virtual.map((route_virtual) => (
<Route
key={route_virtual.path}
path={route_virtual.path}
lazy={async () => {
const { frontmatter, head, ...route } = await route_virtual.lazy()
return {
...route,
element: (
<>
{head && <Helmet>{head}</Helmet>}
{frontmatter && <FrontmatterHead frontmatter={frontmatter} />}
<article>
<route.default components={components} />
</article>
</>
),
} satisfies RouteObject
}}
/>
))}
</Route>
)

export const routesObjects = createRoutesFromElements(routesElements)
13 changes: 13 additions & 0 deletions src/app/utils/initialize-theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')

const storedTheme = localStorage.getItem('vocs.theme')
const theme = storedTheme || 'dark'

if (theme === 'dark') document.documentElement.classList.add('dark')

if (!storedTheme)
// Update the theme if the user changes their OS preference
darkModeMediaQuery.addEventListener('change', ({ matches: isDark }) => {
if (isDark) document.documentElement.classList.add('dark')
else document.documentElement.classList.remove('dark')
})
15 changes: 15 additions & 0 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,19 @@ export async function build({ outDir = 'dist', ssr = false }: BuildParameters =
},
root: __dirname,
})

// initialize theme script
await vite.build({
build: {
lib: {
formats: ['iife'],
name: 'theme',
entry: [resolve(__dirname, './app/utils/initialize-theme.ts')],
},
minify: true,
outDir: resolve(outDir, ssr ? 'client' : ''),
emptyOutDir: false,
},
configFile: undefined,
})
}
1 change: 1 addition & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="/app/utils/initialize-theme.ts"></script>
<link href="/styles/index.css" rel="stylesheet">
<!--head-->
</head>
Expand Down
5 changes: 4 additions & 1 deletion src/prerender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export async function prerender(args: PrerenderParameters = {}) {
// Prerender each route.
for (const route of routes) {
const { head, body } = await mod.prerender(route)
const html = template.replace('<!--body-->', body).replace('<!--head-->', head)
const html = template
.replace('<!--body-->', body)
.replace('<!--head-->', head)
.replace('/app/utils/initialize-theme.ts', '/initialize-theme.iife.js')
const filePath = `${route.endsWith('/') ? `${route}index` : route}.html`.replace(/^\//, '')
const path = resolve(outDir_resolved, filePath)
const pathDir = dirname(path)
Expand Down

0 comments on commit 2101635

Please sign in to comment.