diff --git a/packages/docs-new/package.json b/packages/docs-new/package.json index f1cc707..6522c0b 100644 --- a/packages/docs-new/package.json +++ b/packages/docs-new/package.json @@ -15,6 +15,7 @@ "@tinyhttp/app": "^2.0.15", "@tinyhttp/logger": "^1.3.0", "clsx": "^1.1.1", + "esbuild": "^0.14.10", "express": "^4.17.2", "gray-matter": "^4.0.3", "http-terminator": "^3.0.4", diff --git a/packages/docs-new/src/components/main-navigation-mobile-menu.tsx b/packages/docs-new/src/components/main-navigation-mobile-menu.tsx new file mode 100644 index 0000000..40e104a --- /dev/null +++ b/packages/docs-new/src/components/main-navigation-mobile-menu.tsx @@ -0,0 +1,23 @@ +import * as React from "react" +import { mainLinks } from "../data/main-links" +import type { AppLinkProps } from "./app-link" +import { AppLink } from "./app-link" +import { PopoverMenu } from "./popover-menu" + +export type MainNavigationMobileMenuData = { + guideLinks: AppLinkProps[] +} + +export function render(data: MainNavigationMobileMenuData) { + return ( + + {mainLinks.map((link) => ( + + ))} +
+ {data.guideLinks.map((link) => ( + + ))} +
+ ) +} diff --git a/packages/docs-new/src/components/main-navigation.client.tsx b/packages/docs-new/src/components/main-navigation.client.tsx deleted file mode 100644 index be42d13..0000000 --- a/packages/docs-new/src/components/main-navigation.client.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from "react" -import { createRoot } from "react-dom" -import { mainLinks } from "../data/main-links" -import { AppLink } from "./app-link" -import type { MainNavigationClientData } from "./main-navigation" -import { PopoverMenu } from "./popover-menu" - -const dataScript = document.querySelector("#main-navigation-popover-data")! -const data: MainNavigationClientData = JSON.parse(dataScript.innerHTML) - -createRoot(document.querySelector("#main-navigation-popover")!).render( - - {mainLinks.map((link) => ( - - ))} -
- {data.guideLinks.map((link) => ( - - ))} -
, -) diff --git a/packages/docs-new/src/components/main-navigation.tsx b/packages/docs-new/src/components/main-navigation.tsx index 6672154..7b6001d 100644 --- a/packages/docs-new/src/components/main-navigation.tsx +++ b/packages/docs-new/src/components/main-navigation.tsx @@ -1,38 +1,14 @@ -import { build } from "esbuild" -import { readFile } from "node:fs/promises" -import { dirname } from "node:path" import React from "react" import { guideLinks } from "../data/guide-links" import { mainLinks } from "../data/main-links" +import { createHydrater } from "../helpers/hydration" import { linkClass } from "../styles/components" -import type { AppLinkProps } from "./app-link" import { AppLink } from "./app-link" -import { PopoverMenu } from "./popover-menu" -import { Script } from "./script" +import type { MainNavigationMobileMenuData } from "./main-navigation-mobile-menu" -const clientSourcePath = new URL( - "./main-navigation.client.tsx", - import.meta.url, -).pathname - -const clientOutput = await build({ - bundle: true, - stdin: { - contents: await readFile(clientSourcePath, "utf-8"), - sourcefile: clientSourcePath, - loader: "tsx", - resolveDir: dirname(clientSourcePath), - }, - target: ["chrome89", "firefox89"], - format: "esm", - write: false, -}) - -export type MainNavigationClientData = { - guideLinks: AppLinkProps[] -} - -const data: MainNavigationClientData = { guideLinks } +const MenuHydrater = await createHydrater( + new URL("./main-navigation-mobile-menu.tsx", import.meta.url).pathname, +) export function MainNavigation() { return ( @@ -46,28 +22,8 @@ export function MainNavigation() { ))} - - ) } diff --git a/packages/docs-new/src/helpers/hydration.tsx b/packages/docs-new/src/helpers/hydration.tsx new file mode 100644 index 0000000..8521060 --- /dev/null +++ b/packages/docs-new/src/helpers/hydration.tsx @@ -0,0 +1,51 @@ +import { build } from "esbuild" +import { readFile } from "node:fs/promises" +import { dirname } from "node:path" +import React from "react" +import { Script } from "../components/script" + +let nextId = 0 + +export async function createHydrater(scriptFilePath: string) { + const id = `hydrate-root-${nextId}` + nextId += 1 + + const scriptSource = await readFile(scriptFilePath, "utf-8") + + const scriptBuild = await build({ + bundle: true, + stdin: { + contents: [scriptSource, clientBootstrap(id)].join(";\n"), + sourcefile: scriptFilePath, + loader: "tsx", + resolveDir: dirname(scriptFilePath), + }, + target: ["chrome89", "firefox89"], + format: "esm", + write: false, + }) + + const serverModule = await import(scriptFilePath) + + return function Hydrater({ data }: { data: Data }) { + return ( + <> +
+ {serverModule.render(data)} +
+ + + ) + } +} + +function clientBootstrap(id: string) { + return /* ts */ ` + import { createRoot } from "react-dom" + + const rootElement = document.querySelector("#${id}") + const data = JSON.parse(rootElement.dataset.serverData) + + createRoot(rootElement).render(render(data)) + ` +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 97606f5..7dd7333 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -133,6 +133,7 @@ importers: clsx: ^1.1.1 compression: ^1.7.4 debounce-fn: ^5.1.0 + esbuild: ^0.14.10 esno: ^0.13.0 execa: ^6.0.0 express: ^4.17.2 @@ -182,6 +183,7 @@ importers: '@tinyhttp/app': 2.0.15 '@tinyhttp/logger': 1.3.0 clsx: 1.1.1 + esbuild: 0.14.10 express: 4.17.2 gray-matter: 4.0.3 http-terminator: 3.0.4 @@ -3826,7 +3828,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: true optional: true /esbuild-darwin-64/0.14.10: @@ -3834,7 +3835,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: true optional: true /esbuild-darwin-arm64/0.14.10: @@ -3842,7 +3842,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: true optional: true /esbuild-freebsd-64/0.14.10: @@ -3850,7 +3849,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: true optional: true /esbuild-freebsd-arm64/0.14.10: @@ -3858,7 +3856,6 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true - dev: true optional: true /esbuild-jest/0.5.0_esbuild@0.14.10: @@ -3879,7 +3876,6 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true - dev: true optional: true /esbuild-linux-64/0.14.10: @@ -3887,7 +3883,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /esbuild-linux-arm/0.14.10: @@ -3895,7 +3890,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: true optional: true /esbuild-linux-arm64/0.14.10: @@ -3903,7 +3897,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /esbuild-linux-mips64le/0.14.10: @@ -3911,7 +3904,6 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true - dev: true optional: true /esbuild-linux-ppc64le/0.14.10: @@ -3919,7 +3911,6 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true - dev: true optional: true /esbuild-linux-s390x/0.14.10: @@ -3927,7 +3918,6 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true - dev: true optional: true /esbuild-netbsd-64/0.14.10: @@ -3935,7 +3925,6 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true - dev: true optional: true /esbuild-node-loader/0.6.3_typescript@4.5.4: @@ -3952,7 +3941,6 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true - dev: true optional: true /esbuild-register/3.3.1_esbuild@0.14.10: @@ -3968,7 +3956,6 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true - dev: true optional: true /esbuild-windows-32/0.14.10: @@ -3976,7 +3963,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: true optional: true /esbuild-windows-64/0.14.10: @@ -3984,7 +3970,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: true optional: true /esbuild-windows-arm64/0.14.10: @@ -3992,7 +3977,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: true optional: true /esbuild/0.14.10: @@ -4018,7 +4002,6 @@ packages: esbuild-windows-32: 0.14.10 esbuild-windows-64: 0.14.10 esbuild-windows-arm64: 0.14.10 - dev: true /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}