Created
July 14, 2023 10:32
-
-
Save mizchi/a60c92a080c3c228f021cef527aa10de to your computer and use it in GitHub Desktop.
Run RSC without next
This file contains hidden or 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
{ | |
"private": true, | |
"type": "module", | |
"scripts": { | |
"start": "tsm --conditions react-server run-rsc.tsx" | |
}, | |
"license": "MIT", | |
"devDependencies": { | |
"@types/react": "^18.0.25", | |
"@types/react-dom": "^18.0.9", | |
"react": "0.0.0-experimental-546fe4681-20230713", | |
"react-dom": "0.0.0-experimental-546fe4681-20230713", | |
"react-server-dom-webpack": "0.0.0-experimental-546fe4681-20230713", | |
"tsm": "^2.3.0", | |
"typescript": "^5.1.6", | |
"webpack": "^5.86.0" | |
} | |
} |
This file contains hidden or 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
/** | |
* Copyright (c) Meta Platforms, Inc. and affiliates. | |
* | |
* This source code is licensed under the MIT license found in the | |
* LICENSE file in the root directory of this source tree. | |
* | |
* @emails react-core | |
*/ | |
// from https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js | |
import Stream from "node:stream"; | |
import assert from 'node:assert'; | |
import * as WebpackMock from "./webpackMock"; | |
import React from "react"; | |
import ReactDOMServer from 'react-dom/server.node'; | |
import ReactServerDOMServer from 'react-server-dom-webpack/server.node'; | |
import ReactServerDOMClient from 'react-server-dom-webpack/client.node'; | |
const clientExports = WebpackMock.clientExports; | |
const webpackMap = WebpackMock.webpackMap; | |
const webpackModules = WebpackMock.webpackModules; | |
// @ts-expect-error | |
const use = React.use; | |
function ClientComponent() { | |
return <span>Client Component</span>; | |
} | |
// The Client build may not have the same IDs as the Server bundles for the same | |
// component. | |
const ClientComponentOnTheClient = clientExports(ClientComponent) as unknown as typeof ClientComponent; | |
const ClientComponentOnTheServer = clientExports(ClientComponent) as unknown as typeof ClientComponent | |
// In the SSR bundle this module won't exist. We simulate this by deleting it. | |
// @ts-expect-error; | |
const clientId = webpackMap[ClientComponentOnTheClient.$$id].id; | |
delete webpackModules[clientId]; | |
// Instead, we have to provide a translation from the client meta data to the SSR | |
// meta data. | |
// @ts-expect-error | |
const ssrMetadata = webpackMap[ClientComponentOnTheServer.$$id]; | |
const translationMap = { | |
[clientId]: { | |
'*': ssrMetadata, | |
}, | |
}; | |
function App() { | |
return <ClientComponentOnTheClient />; | |
} | |
const stream = ReactServerDOMServer.renderToPipeableStream( | |
<App />, | |
webpackMap, | |
); | |
const readable = new Stream.PassThrough(); | |
const response = ReactServerDOMClient.createFromNodeStream( | |
readable, | |
translationMap, | |
); | |
stream.pipe(readable); | |
function ClientRoot() { | |
return use(response); | |
} | |
const ssrStream = await ReactDOMServer.renderToPipeableStream( | |
<ClientRoot />, | |
); | |
function readResult(stream: Stream.Readable) { | |
return new Promise((resolve, reject) => { | |
let buffer = ''; | |
const writable = new Stream.PassThrough(); | |
writable.setEncoding('utf8'); | |
writable.on('data', chunk => { | |
buffer += chunk; | |
}); | |
writable.on('error', error => { | |
reject(error); | |
}); | |
writable.on('end', () => { | |
resolve(buffer); | |
}); | |
stream.pipe(writable); | |
}); | |
} | |
const result = await readResult(ssrStream); | |
assert.equal(result, '<span>Client Component</span>'); |
This file contains hidden or 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
/** | |
* Copyright (c) Meta Platforms, Inc. and affiliates. | |
* | |
* This source code is licensed under the MIT license found in the | |
* LICENSE file in the root directory of this source tree. | |
*/ | |
// from https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js | |
import url from "node:url"; | |
import Module from "node:module"; | |
let webpackModuleIdx = 0; | |
const webpackServerModules = {}; | |
const webpackClientModules = {}; | |
const webpackErroredModules = {}; | |
const webpackServerMap = {}; | |
const webpackClientMap = {}; | |
globalThis.__webpack_require__ = (id: string) => { | |
if (webpackErroredModules[id]) { | |
throw webpackErroredModules[id]; | |
} | |
return webpackClientModules[id] || webpackServerModules[id]; | |
}; | |
// @ts-expect-error | |
const previousCompile = Module.prototype._compile; | |
import register from "react-server-dom-webpack/node-register"; | |
register(); | |
// @ts-expect-error | |
const nodeCompile = Module.prototype._compile; | |
if (previousCompile === nodeCompile) { | |
throw new Error( | |
'Expected the Node loader to register the _compile extension', | |
); | |
} | |
// @ts-expect-error | |
Module.prototype._compile = previousCompile; | |
export function clientModuleError(moduleError: any) { | |
const idx = '' + webpackModuleIdx++; | |
webpackErroredModules[idx] = moduleError; | |
const path = url.pathToFileURL(idx).href; | |
webpackClientMap[path] = { | |
id: idx, | |
chunks: [], | |
name: '*', | |
}; | |
const mod = {exports: {}}; | |
nodeCompile.call(mod, '"use client"', idx); | |
return mod.exports; | |
}; | |
export function clientExports(moduleExports: any) { | |
const idx = '' + webpackModuleIdx++; | |
webpackClientModules[idx] = moduleExports; | |
const path = url.pathToFileURL(idx).href; | |
webpackClientMap[path] = { | |
id: idx, | |
chunks: [], | |
name: '*', | |
}; | |
// We only add this if this test is testing ESM compat. | |
if ('__esModule' in moduleExports) { | |
webpackClientMap[path + '#'] = { | |
id: idx, | |
chunks: [], | |
name: '', | |
}; | |
} | |
if (typeof moduleExports.then === 'function') { | |
moduleExports.then( | |
asyncModuleExports => { | |
for (const name in asyncModuleExports) { | |
webpackClientMap[path + '#' + name] = { | |
id: idx, | |
chunks: [], | |
name: name, | |
}; | |
} | |
}, | |
() => {}, | |
); | |
} | |
if ('split' in moduleExports) { | |
// If we're testing module splitting, we encode this name in a separate module id. | |
const splitIdx = '' + webpackModuleIdx++; | |
webpackClientModules[splitIdx] = { | |
s: moduleExports.split, | |
}; | |
webpackClientMap[path + '#split'] = { | |
id: splitIdx, | |
chunks: [], | |
name: 's', | |
}; | |
} | |
const mod = {exports: {}}; | |
nodeCompile.call(mod, '"use client"', idx); | |
return mod.exports; | |
}; | |
// This tests server to server references. There's another case of client to server references. | |
export function serverExports(moduleExports: any) { | |
const idx = '' + webpackModuleIdx++; | |
webpackServerModules[idx] = moduleExports; | |
const path = url.pathToFileURL(idx).href; | |
webpackServerMap[path] = { | |
id: idx, | |
chunks: [], | |
name: '*', | |
}; | |
// We only add this if this test is testing ESM compat. | |
if ('__esModule' in moduleExports) { | |
webpackServerMap[path + '#'] = { | |
id: idx, | |
chunks: [], | |
name: '', | |
}; | |
} | |
if ('split' in moduleExports) { | |
// If we're testing module splitting, we encode this name in a separate module id. | |
const splitIdx = '' + webpackModuleIdx++; | |
webpackServerModules[splitIdx] = { | |
s: moduleExports.split, | |
}; | |
webpackServerMap[path + '#split'] = { | |
id: splitIdx, | |
chunks: [], | |
name: 's', | |
}; | |
} | |
const mod = {exports: moduleExports}; | |
nodeCompile.call(mod, '"use server"', idx); | |
return mod.exports; | |
}; | |
export { | |
webpackClientMap as webpackMap, | |
webpackClientModules as webpackModules, | |
webpackServerMap, | |
webpackClientMap, | |
webpackClientModules, | |
webpackServerModules | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
No webpackMock version