
보통 우리가 next와 같은 아무 프레임워크 없이 React로 앱을 만들때는 간단하게 react
와 react-dom
을 다운로드 받은다음에
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(<>Hello World</>, document.getElementById('app'));
이런식으로 간단하게 만들면 된다.
근데 cra
로 다운로드 받은 react 탬플릿에서 index.html
파일을 자세하게 보면 <noscript />
태그가 있는데
이 <noscript />
가 하는 역할이 브라우저가 javascript 실행을 막았을 때 띄우는 것이라고 한다.
근데 조금만 더 생각해보면 여기서 React는 자바스크립트가 활성화되야지만 페이지를 보여준다라는 것을 알 수 있다.
근데 이 자바스크립트 비활성화 문제는 SSR라는 것을 사용하면 어느정도 해결할 수 있다.
이번 포스트에서는 SSR을 구현해보도록 하겠다.
#구현 - 클라이언트
먼저 화면에 띄울 페이지를 만든다.
// src/app.tsx
import React from 'react';
export default function app() {
return <>Hello World!</>;
}
그다음에 클라이언트에서 랜더링하라는 코드를 작성하면 된다.
// src/index.tsx
import React from 'react';
import { hydrateRoot } from 'react-dom/client';
import App from './app';
hydrateRoot(document.getElementById('app') as any, <App />);
공식문서에 따르면 hydrateRoot
는
hydrateRoot서버 환경에서 React에 의해 이미 렌더링된 기존 HTML에 React를 "첨부"하기 위한 호출 입니다. - 문서
라고한다. 뭐라하는지는 정확히 모르겠는데 HTML에 React를 적용한다는 것 같다.
이렇게 클라이언트 구현은 끝났다.
#구현 - 서버
// server/index.tsx
import path from 'path';
import { readFileSync } from 'fs';
import React from 'react';
import express from 'express';
import ReactDOMServer from 'react-dom/server';
import App from '../src/app';
const PORT = 3000;
const app = express();
app.get('/', (req, res) => {
const app = ReactDOMServer.renderToString(<App />);
const index = readFileSync(path.join(process.cwd(), 'build/index.html')).toString();
return res.send(index.replace('<div id="app"></div>', `<div id="app">${app}</div>`));
});
app.use(express.static('./build'));
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
renderToString()
은 리엑트 컴포넌트를 HTML으로 바꾸는 역할을 한다.
<!--build/index.html-->
<body>
<div id="app"></div>
<script src="/index.js"></script>
<!-- /src/index.tsx => /build/index.js -->
</body>
모든 준비는 끝났다.
이제 .tsx
파일들을 .js
파일로 바꿔주기만 하면 된다.
빌드파일을 작성해준다.
const build = require('esbuild');
build.build({
entryPoints: ['./src/index.tsx'],
outfile: './build/index.js',
bundle: true,
platform: 'browser',
});
build.build({
entryPoints: ['./server/index.tsx'],
outfile: './build/server.js',
bundle: true,
platform: 'node',
});
완성이다. 자바스크립트를 비활성화 시켜도 활성화한 것이랑 똑같은 결과가 나온다.
근데 참고로 자바스크립트를 비활성화시켜도 활성화시킨것처럼 모든 기능들이 작동하진 않는다. 그냥 눈에 보이는 것만 똑같은 것이다.