-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3c41d4b
commit 7bd6b65
Showing
61 changed files
with
175 additions
and
2,399 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
3 changes: 3 additions & 0 deletions
3
exercises/05.middle/01.problem.middle/server/register-rsc-loader.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { register } from 'node:module' | ||
|
||
register('./rsc-loader.js', import.meta.url) |
23 changes: 23 additions & 0 deletions
23
exercises/05.middle/01.problem.middle/server/rsc-loader.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { resolve, load as reactLoad } from 'react-server-dom-esm/node-loader' | ||
|
||
export { resolve } | ||
|
||
async function textLoad(url, context, defaultLoad) { | ||
const result = await defaultLoad(url, context, defaultLoad) | ||
if (result.format === 'module') { | ||
if (typeof result.source === 'string') { | ||
return result | ||
} | ||
return { | ||
source: Buffer.from(result.source).toString('utf8'), | ||
format: 'module', | ||
} | ||
} | ||
return result | ||
} | ||
|
||
export async function load(url, context, defaultLoad) { | ||
return await reactLoad(url, context, (u, c) => { | ||
return textLoad(u, c, defaultLoad) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ import express from 'express' | |
import { createElement as h, use } from 'react' | ||
import { renderToPipeableStream } from 'react-dom/server' | ||
import { createFromNodeStream } from 'react-server-dom-esm/client' | ||
import { RouterContext } from '../src/router.js' | ||
|
||
const moduleBasePath = new URL('../src', import.meta.url).href | ||
|
||
|
@@ -34,7 +35,20 @@ app.head('/', async (req, res) => { | |
res.status(200).end() | ||
}) | ||
|
||
app.all('/', async function (req, res) { | ||
app.use(express.static('public')) | ||
app.use('/js/src', express.static('src')) | ||
app.use('/js/react-server-dom-esm/client', (req, res) => { | ||
const require = createRequire(import.meta.url) | ||
const pkgPath = require.resolve('react-server-dom-esm') | ||
const modulePath = path.join( | ||
path.dirname(pkgPath), | ||
'esm', | ||
'react-server-dom-esm-client.browser.development.js', | ||
) | ||
res.sendFile(modulePath) | ||
}) | ||
|
||
app.all('/:shipId?', async function (req, res) { | ||
// Proxy the request to the rsc server. | ||
const proxiedHeaders = { | ||
'X-Forwarded-Host': req.hostname, | ||
|
@@ -57,31 +71,86 @@ app.all('/', async function (req, res) { | |
req, | ||
) | ||
|
||
try { | ||
const rscResponse = await promiseForData | ||
const moduleBaseURL = '/js/src' | ||
if (req.accepts('text/html')) { | ||
try { | ||
const rscResponse = await promiseForData | ||
const moduleBaseURL = '/js/src' | ||
|
||
// For HTML, we're a "client" emulator that runs the client code, | ||
// so we start by consuming the RSC payload. This needs the local file path | ||
// to load the source files from as well as the URL path for preloads. | ||
// For HTML, we're a "client" emulator that runs the client code, | ||
// so we start by consuming the RSC payload. This needs the local file path | ||
// to load the source files from as well as the URL path for preloads. | ||
|
||
let rootPromise | ||
function Root() { | ||
rootPromise ??= createFromNodeStream( | ||
rscResponse, | ||
moduleBasePath, | ||
moduleBaseURL, | ||
let contentPromise | ||
function Root() { | ||
contentPromise ??= createFromNodeStream( | ||
rscResponse, | ||
moduleBasePath, | ||
moduleBaseURL, | ||
) | ||
const content = use(contentPromise) | ||
return content.root | ||
} | ||
const location = req.url | ||
const navigate = () => { | ||
throw new Error('navigate cannot be called on the server') | ||
} | ||
const isPending = false | ||
const routerValue = { | ||
location, | ||
nextLocation: location, | ||
navigate, | ||
isPending, | ||
} | ||
const { pipe } = renderToPipeableStream( | ||
h(RouterContext.Provider, { value: routerValue }, h(Root)), | ||
{ | ||
bootstrapModules: ['/js/src/index.js'], | ||
importMap: { | ||
imports: { | ||
react: | ||
'https://esm.sh/[email protected]?pin=v126&dev', | ||
'react-dom': | ||
'https://esm.sh/[email protected]?pin=v126&dev', | ||
'react-dom/': | ||
'https://esm.sh/[email protected]&pin=v126&dev/', | ||
'react-error-boundary': | ||
'https://esm.sh/[email protected]?pin=126&dev', | ||
'react-server-dom-esm/client': '/js/react-server-dom-esm/client', | ||
}, | ||
}, | ||
}, | ||
) | ||
const root = use(rootPromise) | ||
return root | ||
pipe(res) | ||
} catch (e) { | ||
console.error(`Failed to SSR: ${e.stack}`) | ||
res.statusCode = 500 | ||
res.end(`Failed to SSR: ${e.stack}`) | ||
} | ||
} else { | ||
try { | ||
const rscResponse = await promiseForData | ||
|
||
// Forward all headers from the RSC response to the client response | ||
Object.entries(rscResponse.headers).forEach(([header, value]) => { | ||
res.set(header, value) | ||
}) | ||
|
||
if (req.get('rsc-action')) { | ||
res.set('Content-type', 'text/x-component') | ||
} | ||
|
||
rscResponse.on('data', data => { | ||
res.write(data) | ||
res.flush() | ||
}) | ||
rscResponse.on('end', () => { | ||
res.end() | ||
}) | ||
} catch (e) { | ||
console.error(`Failed to proxy request: ${e.stack}`) | ||
res.statusCode = 500 | ||
res.end(`Failed to proxy request: ${e.stack}`) | ||
} | ||
res.set('Content-type', 'text/html') | ||
const { pipe } = renderToPipeableStream(h(Root)) | ||
pipe(res) | ||
} catch (e) { | ||
console.error(`Failed to SSR: ${e.stack}`) | ||
res.statusCode = 500 | ||
res.end(`Failed to SSR: ${e.stack}`) | ||
} | ||
}) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.