Rendertron을 사용한 동적 렌더링

2019년 1월 31일 목요일

많은 프런트엔드 프레임워크에서 콘텐츠를 표시할 때 자바스크립트를 사용합니다. 즉, Google에서 콘텐츠의 색인을 생성하거나 색인이 생성된 콘텐츠를 업데이트하는 데 시간이 걸릴 수 있습니다.

올해 Google I/O에서 논의된 해결 방법동적 렌더링입니다. 이를 구현하는 방법은 다양합니다. 이 블로그 게시물에서는 헤드리스 Chromium을 바탕으로 하는 오픈소스 솔루션인 Rendertron을 사용하는 동적 렌더링 구현 예를 보여줍니다.

어떤 사이트에서 동적 렌더링을 고려해야 하나요?

웹사이트를 방문하는 모든 검색엔진 또는 소셜 미디어 봇이 자바스크립트를 실행하는 것은 아닙니다. 예를 들면 Googlebot은 자바스크립트를 실행하는 데 시간이 걸릴 수 있으며 몇 가지 제약이 있습니다.

동적 렌더링은 자주 변경되며 자바스크립트가 표시되어야 하는 콘텐츠에 유용합니다. Angular Universal과 같은 하이브리드 렌더링을 사용하면 사이트의 사용자 환경(특히 유의미한 첫 페인트 시간)에 도움이 될 수 있습니다.

동적 렌더링 작동 방식

동적 렌더링 작동 방식

동적 렌더링이란 특정 사용자 에이전트를 위해 클라이언트 측에서 렌더링된 콘텐츠와 사전에 렌더링된 콘텐츠를 전환하는 것을 의미합니다.

자바스크립트를 실행하고 정적 HTML을 생성하려면 렌더러가 필요합니다. Rendertron은 headless Chromium을 사용하여 렌더링하는 오픈소스 프로젝트입니다. 단일 페이지 앱은 백그라운드에서 데이터를 로드하거나 콘텐츠 렌더링 작업을 지연시키는 경우가 많습니다. Rendertron에는 웹사이트 렌더링이 완료되는 시기를 결정하는 메커니즘이 있습니다. 모든 네트워크 요청이 완료되고 미해결된 작업이 없을 때까지 기다립니다.

이 게시물에서 다루는 내용은 다음과 같습니다.

  1. 샘플 웹 앱 살펴보기
  2. 웹 앱을 게재할 소규모 express.js 서버 설정
  3. Rendertron 설치 및 동적 렌더링에 사용할 미들웨어로 구성

샘플 웹 앱

'고양이 골목' 웹 앱은 자바스크립트를 사용하여 API에서 다양한 고양이 이미지를 로드하고 그리드 형식으로 표시합니다.

귀여운 고양이 이미지를 그리드 형식으로 표시하고 버튼도 한 개 있습니다. 그야말로 완벽한 웹 앱이죠!

자바스크립트는 다음과 같이 구성됩니다.

const apiUrl = 'https://api.thecatapi.com/v1/images/search?limit=50';
   const tpl = document.querySelector('template').content;
   const container = document.querySelector('ul');
   function init () {
     fetch(apiUrl)
     .then(response => response.json())
     .then(cats => {
       container.innerHTML = '';
       cats
         .map(cat => { const li = document.importNode(tpl, true); li.querySelector('img').src = cat.url; return li;
         }).forEach(li => container.appendChild(li));
     })
   }
   init();
   document.querySelector('button').addEventListener('click', init);

이 웹 앱은 최신 자바스크립트(ES6)를 사용하는데, Googlebot에서는 아직 지원되지 않습니다. 모바일 친화성 테스트를 사용하여 Googlebot이 이 콘텐츠를 볼 수 있는지 확인할 수 있습니다.

모바일 친화성 테스트 결과 페이지는 모바일 친화적인 것으로 나타났지만, 스크린샷을 보면 모든 고양이가 사라져 있습니다. 헤드라인과 버튼은 표시되지만 고양이 사진이 전혀 없습니다.

이 문제는 간단하게 해결할 수 있습니다. 하지만 여기에서는 동적 렌더링을 설정하는 방법을 익히는 것이 좋습니다. 동적 렌더링을 사용하면 웹 앱의 코드를 변경하지 않아도 Googlebot이 고양이 사진을 볼 수 있게 할 수 있습니다.

서버 설정

웹 애플리케이션을 게재하려면 node.js 라이브러리인 express를 사용하여 웹 서버를 빌드하세요.

서버 코드는 다음과 같습니다. 전체 프로젝트의 소스 코드를 확인하세요.

const express = require('express');
const app = express();
const DIST_FOLDER = process.cwd() + '/docs';
const PORT = process.env.PORT || 8080;
// Serve static assets (images, css, etc.)
app.get('*.*', express.static(DIST_FOLDER));
// Point all other URLs to index.html for our single page app
app.get('*', (req, res) => {
  res.sendFile(DIST_FOLDER + '/index.html');
});
// Start Express Server
app.listen(PORT, () => {
  console.log(`Node Express server listening on https://localhost:${PORT} from ${DIST_FOLDER}`);
});

최신 브라우저를 사용하고 있다면 실시간 예시를 사용해 보세요. 고양이 사진이 잔뜩 표시됩니다. 컴퓨터에서 프로젝트를 실행하려면 node.js에서 다음 명령어를 실행해야 합니다.

npm install --save express rendertron-middleware
node server.js

그런 다음 브라우저를 https://localhost:8080으로 가리킵니다. 이제 동적 렌더링을 설정할 차례입니다.

Rendertron 인스턴스 배포

Rendertron은 URL을 가져와 헤드리스 Chromium을 사용하여 URL에 정적 HTML을 반환하는 서버를 실행합니다. Google에서는 Rendertron 프로젝트의 권고사항을 따르고 Google Cloud Platform을 사용합니다.

새 Google Cloud Platform 프로젝트를 만드는 양식입니다.

무료로 사용 가능한 사용 등급으로 시작할 수 있습니다. 프로덕션에서 이 설정을 사용하면 Google Cloud Platform 가격 책정 방식에 따라 비용이 발생할 수 있습니다.

  1. Google Cloud Console에서 새 프로젝트를 만듭니다. 입력란 아래의 '프로젝트 ID'를 기록해 두세요.
  2. 문서에 설명된 대로 Google Cloud SDK를 설치하고 로그인합니다.
  3. 다음을 사용하여 GitHub에서 Rendertron 저장소를 복제합니다.
    git clone https://github.com/GoogleChrome/rendertron.git
    cd rendertron
  4. 다음 명령어를 실행하여 컴퓨터에 종속 항목을 설치하고 Rendertron을 빌드합니다.
    npm install && npm run build
  5. 다음과 같은 내용으로 rendertron 디렉터리에 config.json이라는 새 파일을 만들어 Rendertron 캐시를 사용 설정합니다.
    { "datastoreCache": true }
  6. rendertron 디렉터리에서 다음 명령어를 실행합니다. YOUR_PROJECT_ID를 1단계의 프로젝트 ID로 대체합니다.
    gcloud app deploy app.yaml --project YOUR_PROJECT_ID
  7. 원하는 지역을 선택하고 배포를 확인합니다. 완료될 때까지 기다립니다.
  8. URL YOUR_PROJECT_ID.appspot.com을 입력합니다. 입력란과 버튼 몇 개가 있는 Rendertron의 인터페이스가 표시됩니다.
Google Cloud Platform에 배포한 후 표시되는 Rendertron UI

Rendertron 웹 인터페이스가 표시되면 나만의 Rendertron 인스턴스를 성공적으로 배포한 것입니다. 프로젝트 URL(YOUR_PROJECT_ID.appspot.com)은 프로세스의 다음 부분에서 필요하므로 기록해 둡니다.

서버에 Rendertron 추가

웹 서버는 express.js를 사용하고 Rendertron에는 express.js 미들웨어가 있습니다. server.js 파일의 디렉터리에서 다음 명령어를 실행합니다.

npm install --save rendertron-middleware

이 명령어는 서버에 추가할 수 있도록 npm의 rendertron-middleware를 설치합니다.

const express = require('express');
const app = express();
const rendertron = require('rendertron-middleware');

봇 목록 구성

Rendertron은 user-agent HTTP 헤더를 사용하여 요청의 출처가 봇 또는 사용자의 브라우저인지 확인합니다. 비교할 수 있는 잘 관리된 봇 사용자 에이전트 목록이 있습니다. Googlebot은 자바스크립트를 실행할 수 있으므로 기본적으로 이 목록에는 Googlebot이 포함되어 있지 않습니다. Rendertron도 Googlebot 요청을 렌더링하도록 하려면 사용자 에이전트 목록에 Googlebot을 추가합니다.

const BOTS = rendertron.botUserAgents.concat('googlebot');
const BOT_UA_PATTERN = new RegExp(BOTS.join('|'), 'i');

Rendertron은 나중에 user-agent 헤더를 이 정규 표현식과 비교합니다.

미들웨어 추가

Rendertron 인스턴스에 봇 요청을 보내려면 express.js 서버에 미들웨어를 추가해야 합니다. 미들웨어는 요청하는 사용자 에이전트를 확인하고 알려진 봇의 요청을 Rendertron 인스턴스로 전달합니다. 다음 코드를 server.js에 추가합니다. 이때 YOUR_PROJECT_ID를 Google Cloud Platform 프로젝트 ID로 바꿔야 합니다.

app.use(rendertron.makeMiddleware({
  proxyUrl: 'https://YOUR_PROJECT_ID.appspot.com/render',
  userAgentPattern: BOT_UA_PATTERN
}));

샘플 웹사이트를 요청하는 봇은 Rendertron으로부터 정적 HTML을 수신하므로 봇이 콘텐츠를 표시하기 위해 자바스크립트를 실행하지 않아도 됩니다.

설정 테스트

Rendertron 설정이 성공했는지 테스트하기 위해 모바일 친화성 테스트를 다시 실행합니다.

모바일 친화성 테스트 결과 페이지가 모바일 친화적으로 표시되며 사라졌던 고양이들이 모두 스크린샷에 돌아왔습니다!

첫 번째 테스트와 달리 고양이 사진이 표시됩니다. HTML 탭에서 자바스크립트 코드가 생성한 모든 HTML을 확인할 수 있으며 Rendertron을 사용하면 자바스크립트를 통해 콘텐츠를 표시하지 않아도 됩니다.

결론

웹 앱을 전혀 변경하지 않고도 동적 렌더링 설정을 만들었습니다. 이러한 변경사항을 통해 크롤러에 웹 앱의 정적 HTML 버전을 제공할 수 있습니다.