서버 측 렌더링이 아니지만 React 사이트의 속도를 높이고 싶으신가요? 사전 렌더링을 사용해 보세요.
react-snap
는 사이트의 페이지를 정적 HTML 파일로 사전 렌더링하는 서드 파티 라이브러리입니다. 이렇게 하면 애플리케이션의 첫 페인트 시간이 개선될 수 있습니다.
다음은 시뮬레이션된 3G 연결 및 휴대기기에 로드된 사전 렌더링 유무에 따른 동일한 애플리케이션의 비교입니다.
이것이 왜 유용할까요?
대규모 싱글페이지 애플리케이션의 주요 성능 문제는 사용자가 실제 콘텐츠를 볼 수 있기 전에 사이트를 구성하는 JavaScript 번들의 다운로드가 완료될 때까지 기다려야 한다는 점입니다. 번들 크기가 클수록 사용자가 더 오래 기다려야 합니다.
이를 해결하기 위해 많은 개발자는 브라우저에서만 애플리케이션을 부팅하는 대신 서버에서 애플리케이션을 렌더링하는 접근 방식을 취합니다. 페이지/경로 전환이 있을 때마다 전체 HTML이 서버에서 생성되어 브라우저로 전송되므로 첫 페인트 시간이 줄어들지만 Time to First Byte가 느려집니다.
사전 렌더링은 서버 렌더링보다 덜 복잡하지만 애플리케이션의 첫 번째 페인트 시간을 개선하는 방법도 제공하는 별도의 기법입니다. 헤드리스 브라우저 또는 사용자 인터페이스가 없는 브라우저는 빌드 시간에 모든 경로의 정적 HTML 파일을 생성하는 데 사용됩니다. 그런 다음 이러한 파일을 애플리케이션에 필요한 JavaScript 번들과 함께 제공할 수 있습니다.
react-snap
react-snap
는 Puppeteer를 사용하여 애플리케이션의 여러 경로에 대해 사전 렌더링된 HTML 파일을 만듭니다. 시작하려면 개발 종속 항목으로 설치합니다.
npm install --save-dev react-snap
그런 다음 package.json
에 postbuild
스크립트를 추가합니다.
"scripts": {
//...
"postbuild": "react-snap"
}
이렇게 하면 애플리케이션의 새 빌드가 생성될 때마다 react-snap
명령어가 자동으로 실행됩니다 (npm build
).
마지막으로 애플리케이션 부팅 방식을 변경해야 합니다.
src/index.js
파일을 다음과 같이 변경합니다.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
ReactDOM.hydrate(<App />, rootElement);
} else {
ReactDOM.render(<App />, rootElement);
}
ReactDOM.render
만 사용하여 루트 React 요소를 DOM에 직접 렌더링하는 대신, 이 메서드는 하위 노드가 이미 있는지 확인하여 HTML 콘텐츠가 사전 렌더링되었는지 (또는 서버에서 렌더링되었는지) 확인합니다. 이 경우 ReactDOM.hydrate
이 대신 사용되어 이벤트 리스너를 새로 만드는 대신 이미 생성된 HTML에 연결합니다.
이제 애플리케이션을 빌드하면 크롤링되는 각 경로의 페이로드로 정적 HTML 파일이 생성됩니다. HTML 요청의 URL을 클릭한 다음 Chrome DevTools 내에서 미리보기 탭을 클릭하여 HTML 페이로드가 어떻게 표시되는지 확인할 수 있습니다.
스타일이 지정되지 않은 콘텐츠가 깜박임
이제 정적 HTML이 거의 즉시 렌더링되지만 기본적으로 스타일이 지정되지 않은 상태로 유지되므로 '스타일이 지정되지 않은 콘텐츠 플래시' (FOUC)가 표시되는 문제가 발생할 수 있습니다. 이는 CSS-in-JS 라이브러리를 사용하여 선택기를 생성하는 경우 특히 두드러집니다. 스타일을 적용하려면 JavaScript 번들의 실행이 완료되어야 하기 때문입니다.
이를 방지하려면 중요 CSS 또는 초기 페이지 렌더링에 필요한 최소 CSS를 HTML 문서의 <head>
에 직접 인라인으로 추가할 수 있습니다. react-snap
는 내부적으로 다른 서드 파티 라이브러리인 minimalcss
를 사용하여 여러 경로의 중요한 CSS를 추출합니다. package.json
파일에 다음을 지정하여 사용 설정할 수 있습니다.
"reactSnap": {
"inlineCss": true
}
이제 Chrome DevTools의 응답 미리보기를 보면 중요한 CSS가 인라인으로 추가된 스타일 지정된 페이지가 표시됩니다.
결론
애플리케이션에서 서버 측 렌더링 경로를 사용하지 않는 경우 react-snap
를 사용하여 사용자에게 정적 HTML을 사전 렌더링합니다.
- 개발 종속 항목으로 설치하고 기본 설정으로 시작합니다.
- 실험용
inlineCss
옵션을 사용하여 중요한 CSS를 인라인 처리합니다(사이트에서 작동하는 경우). - 경로 내 구성요소 수준에서 코드 분할을 사용하는 경우 사용자에게 로드 상태를 미리 렌더링하지 않도록 주의하세요.
react-snap
리드미에서 자세히 설명합니다.