반응 스냅을 사용하여 경로 사전 렌더링

서버 측 렌더링이 아니지만 React 사이트의 속도를 높이고 싶으신가요? 사전 렌더링을 사용해 보세요.

react-snap는 사이트의 페이지를 정적 HTML 파일로 사전 렌더링하는 서드 파티 라이브러리입니다. 이렇게 하면 애플리케이션의 첫 페인트 시간이 개선될 수 있습니다.

다음은 시뮬레이션된 3G 연결 및 휴대기기에 로드된 사전 렌더링 유무에 따른 동일한 애플리케이션의 비교입니다.

로드 비교를 나란히 표시합니다. 사전 렌더링을 사용하는 버전은 4.2초 더 빠르게 로드됩니다.

이것이 왜 유용할까요?

대규모 싱글페이지 애플리케이션의 주요 성능 문제는 사용자가 실제 콘텐츠를 볼 수 있기 전에 사이트를 구성하는 JavaScript 번들의 다운로드가 완료될 때까지 기다려야 한다는 점입니다. 번들의 크기가 클수록 사용자가 더 오래 기다려야 합니다.

이를 해결하기 위해 많은 개발자는 브라우저에서만 애플리케이션을 부팅하는 대신 서버에서 애플리케이션을 렌더링하는 접근 방식을 취합니다. 페이지/경로 전환이 있을 때마다 전체 HTML이 서버에서 생성되어 브라우저로 전송되므로 첫 번째 페인트 시간이 줄어들지만 Time to First Byte가 느려집니다.

사전 렌더링은 서버 렌더링보다 덜 복잡하지만 애플리케이션의 첫 번째 페인트 시간을 개선하는 방법도 제공하는 별도의 기법입니다. 헤드리스 브라우저 또는 사용자 인터페이스가 없는 브라우저는 빌드 시간에 모든 경로의 정적 HTML 파일을 생성하는 데 사용됩니다. 그런 다음 이러한 파일을 애플리케이션에 필요한 JavaScript 번들과 함께 제공할 수 있습니다.

react-snap

react-snapPuppeteer를 사용하여 애플리케이션에서 다양한 경로의 사전 렌더링된 HTML 파일을 만듭니다. 시작하려면 개발 종속 항목으로 설치합니다.

npm install --save-dev react-snap

그런 다음 package.jsonpostbuild 스크립트를 추가합니다.

"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가 인라인으로 추가된 스타일 지정된 페이지가 표시됩니다.

전후 비교 후 샷은 인라인화된 중요 CSS로 인해 콘텐츠가 렌더링되고 스타일이 지정되었음을 보여줍니다.

결론

애플리케이션에서 서버 측 렌더링 경로를 사용하지 않는 경우 react-snap를 사용하여 사용자에게 정적 HTML을 사전 렌더링합니다.

  1. 개발 종속 항목으로 설치하고 기본 설정으로 시작합니다.
  2. 실험용 inlineCss 옵션을 사용하여 중요한 CSS를 인라인 처리합니다(사이트에서 작동하는 경우).
  3. 경로 내 구성요소 수준에서 코드 분할을 사용하는 경우 사용자에게 로드 상태를 미리 렌더링하지 않도록 주의하세요. react-snap 리드미에서 자세히 설명합니다.