diff --git a/app/entry.client.tsx b/app/entry.client.tsx index 72fee3d..3fe091c 100644 --- a/app/entry.client.tsx +++ b/app/entry.client.tsx @@ -1,4 +1,4 @@ import {RemixBrowser} from '@remix-run/react'; import {hydrateRoot} from 'react-dom/client'; -hydrateRoot(document, ); +hydrateRoot(document.getElementById('root')!, ); diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 5b7ffb7..fe7a38b 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -1,6 +1,18 @@ import type {EntryContext} from '@shopify/remix-oxygen'; import {RemixServer} from '@remix-run/react'; import {renderToReadableStream} from 'react-dom/server'; +import {renderHeadToString} from 'remix-island'; +import {Head} from './root'; + +const readableString = (value: string) => { + const te = new TextEncoder(); + return new ReadableStream({ + start(controller) { + controller.enqueue(te.encode(value)); + controller.close(); + }, + }); +}; export default async function handleRequest( request: Request, @@ -8,13 +20,28 @@ export default async function handleRequest( responseHeaders: Headers, remixContext: EntryContext, ) { + const {readable, writable} = new TransformStream(); + const head = readableString( + `${renderHeadToString({ + request, + remixContext, + Head, + })}
`, + ); + const end = readableString(`
`); + const body = await renderToReadableStream( , ); + Promise.resolve() + .then(() => head.pipeTo(writable, {preventClose: true})) + .then(() => body.pipeTo(writable, {preventClose: true})) + .then(() => end.pipeTo(writable)); + responseHeaders.set('Content-Type', 'text/html'); - return new Response(body, { + return new Response(readable, { status: responseStatusCode, headers: responseHeaders, }); diff --git a/app/root.tsx b/app/root.tsx index 8acd08f..f04a1d8 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -14,6 +14,7 @@ import { import type {Shop} from '@shopify/hydrogen/storefront-api-types'; import styles from './styles/app.css'; import favicon from '../public/favicon.svg'; +import {createHead} from 'remix-island'; export const links: LinksFunction = () => { return [ @@ -40,17 +41,21 @@ export async function loader({context}: LoaderArgs) { return {layout}; } +export const Head = createHead(() => ( + <> + + + +)); + export default function App() { const data = useLoaderData(); const {name} = data.layout.shop; return ( - - - - - + <> +

Hello, {name}

This is a custom storefront powered by Hydrogen

@@ -58,7 +63,7 @@ export default function App() { - + ); } diff --git a/package-lock.json b/package-lock.json index 04efc0e..7c33dde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,8 @@ "graphql": "^16.6.0", "graphql-tag": "^2.12.6", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "remix-island": "^0.1.2" }, "devDependencies": { "@remix-run/dev": "1.12.0", @@ -13186,6 +13187,17 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remix-island": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/remix-island/-/remix-island-0.1.2.tgz", + "integrity": "sha512-1vXF56y7ZKb8caUduCKdkbxObAxZnTO+arQ94QlwKK6a7wVozGCfiOOk3lr919rm7cy54eeqOVI0hud3cfHlLg==", + "peerDependencies": { + "@remix-run/react": ">= 1", + "@remix-run/server-runtime": ">= 1", + "react": ">= 16.8", + "react-dom": ">= 16.8" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", diff --git a/package.json b/package.json index 92ddecf..4083505 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "graphql": "^16.6.0", "graphql-tag": "^2.12.6", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "remix-island": "^0.1.2" }, "devDependencies": { "@remix-run/dev": "1.12.0",