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

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

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

다음은 시뮬레이션된 3G 연결 및 휴대기기에 로드된 사전 렌더링이 적용된 앱과 그렇지 않은 애플리케이션을 비교한 것입니다.

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

이것이 왜 유용할까요?

큰 단일 페이지 애플리케이션의 주요 성능 문제는 사용자가 실제 콘텐츠를 보려면 사이트를 구성하는 JavaScript 번들이 다운로드가 완료될 때까지 기다려야 한다는 것입니다. 번들이 클수록 사용자가 기다려야 하는 시간이 늘어납니다.

이 문제를 해결하기 위해 많은 개발자는 브라우저에서만 애플리케이션을 부팅하는 대신 서버에서 애플리케이션을 렌더링하는 방식을 사용합니다. 각 페이지/경로를 전환할 때마다 전체 HTML이 서버에서 생성되고 브라우저로 전송되므로 첫 페인트 시간은 줄지만 첫 바이트까지의 시간이 느려집니다.

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

반응-스냅하기

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

npm install --save-dev react-snap

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

"scripts": {
  //...
  "postbuild": "react-snap"
}

이렇게 하면 애플리케이션을 새로 빌드 (npm build)할 때마다 react-snap 명령어가 자동으로 실행됩니다.

마지막으로 해야 할 일은 애플리케이션 부팅 방식을 변경하는 것입니다. 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 리드미를 참고하세요.