---
title: prerenderToNodeStream
---
`prerenderToNodeStream`은 [Node.js Stream](https://nodejs.org/api/stream.html)을 사용하여 React 트리를 정적 HTML 문자열로 렌더링합니다.
```js
const {prelude} = await prerenderToNodeStream(reactNode, options?)
```
이 API는 Node.js 전용입니다. Deno나 최신 엣지 런타임처럼 [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)를 지원하는 환경에서는 [`prerender`](/reference/react-dom/static/prerender)를 사용해야 합니다.
---
## 레퍼런스 {/*reference*/}
### `prerenderToNodeStream(reactNode, options?)` {/*prerender*/}
`prerenderToNodeStream`을 호출해 앱을 정적 HTML로 렌더링합니다.
```js
import { prerenderToNodeStream } from 'react-dom/static';
// 라우트 핸들러 문법은 사용하는 백엔드 프레임워크에 따라 다릅니다.
app.use('/', async (request, response) => {
const { prelude } = await prerenderToNodeStream(, {
bootstrapScripts: ['/main.js'],
});
response.setHeader('Content-Type', 'text/plain');
prelude.pipe(response);
});
```
클라이언트에서 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출해 서버에서 생성된 HTML을 인터랙티브하게 만듭니다.
[아래에서 더 많은 예시를 확인하세요.](#usage)
#### 매개변수 {/*parameters*/}
* `reactNode`: HTML로 렌더링할 React 노드입니다. 예를 들어 ``과 같은 JSX 노드가 해당됩니다. 전체 문서를 나타내야 하므로, App 컴포넌트는 `` 태그를 렌더링해야 합니다.
* **optional** `options`: 정적 생성 옵션을 가진 객체입니다.
* **optional** `bootstrapScriptContent`: 지정될 경우, 이 문자열이 인라인 `
```
클라이언트에서 부트스트랩 스크립트는 [`hydrateRoot`를 호출해 `document` 전체를 hydrate해야 합니다.](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
```js [[1, 4, ""]]
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, );
```
이는 정적 서버 생성 HTML에 이벤트 리스너를 연결해 인터랙티브하게 만듭니다.
#### 빌드 출력에서 CSS 및 JS 에셋 경로 읽기 {/*reading-css-and-js-asset-paths-from-the-build-output*/}
최종 에셋 URL(예: JavaScript와 CSS 파일)은 빌드 후 종종 해시Hash가 추가됩니다. 예를 들어 `styles.css` 대신 `styles.123456.css`와 같은 파일명이 될 수 있습니다. 정적 에셋 파일명에 해시를 추가하면 동일한 에셋이라도 빌드마다 다른 파일명을 갖게 됩니다. 이는 정적 에셋에 대해 장기 캐싱을 안전하게 활성화할 수 있게 해줍니다. 특정 이름을 가진 파일은 그 내용이 절대 변경되지 않기 때문입니다.
그러나 빌드가 끝난 후에야 에셋 URL을 알 수 있다면, 이를 소스 코드에 넣을 방법이 없습니다. 예를 들어 앞서처럼 JSX에 `"/styles.css"`를 하드코딩하면 동작하지 않습니다. 소스 코드에 에셋 경로를 넣지 않으려면, 루트 컴포넌트가 Prop으로 전달된 맵에서 실제 파일명을 읽어올 수 있습니다.
```js {1,6}
export default function App({ assetMap }) {
return (
My app
...
);
}
```
서버에서 ``을 렌더링하고 에셋 URL이 포함된 `assetMap`을 전달합니다.
```js {1-5,8,9}
// 이 JSON은 빌드 도구에서 가져와야 합니다. 예를 들어 빌드 출력에서 읽어올 수 있습니다.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
};
app.use('/', async (request, response) => {
const { prelude } = await prerenderToNodeStream(, {
bootstrapScripts: [assetMap['/main.js']]
});
response.setHeader('Content-Type', 'text/html');
prelude.pipe(response);
});
```
서버에서 ``을 렌더링하고 있으므로, Hydration 오류를 피하려면 클라이언트에서도 `assetMap`과 함께 렌더링해야 합니다. 다음과 같이 `assetMap`을 직렬화해 클라이언트로 전달할 수 있습니다.
```js {9-10}
// 이 JSON은 빌드 도구에서 가져와야 합니다.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
};
app.use('/', async (request, response) => {
const { prelude } = await prerenderToNodeStream(, {
// 주의: 이 데이터는 사용자가 생성한 것이 아니므로 `stringify()`해도 안전합니다.
bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`,
bootstrapScripts: [assetMap['/main.js']],
});
response.setHeader('Content-Type', 'text/html');
prelude.pipe(response);
});
```
위 예시에서 `bootstrapScriptContent` 옵션은 클라이언트에서 전역 변수 `window.assetMap`을 설정하는 인라인 `