실적 통계를 구축한 방법 및 이유

Chrome 102의 DevTools에서 새로운 실험용 패널인 성능 통계를 확인할 수 있습니다. 이 게시물에서는 새 패널을 편성한 이유뿐 아니라 당면한 기술적 과제와 그 과정에서 내린 결정에 대해서도 이야기합니다.

ALT_TEXT_HERE

다른 패널을 만들어야 하는 이유

(아직 실적 통계 패널을 만들어야 하는 이유와 이 패널을 통해 웹사이트 실적에 대한 활용 가능한 분석 정보를 얻는 방법에 대한 동영상을 게시했습니다.)

기존 실적 패널은 웹사이트에 대한 모든 데이터를 한곳에서 확인하고자 하는 경우 활용할 수 있는 훌륭한 리소스이지만, 이 작업은 다소 번거로울 수 있다고 생각합니다. 성능 전문가가 아니라면 무엇을 찾아야 하고 녹화 파일에서 어떤 부분이 관련이 있는지 정확히 알기가 어렵습니다.

Insights(유용한 정보) 패널로 이동하면 여전히 트레이스 타임라인을 보고 데이터를 검사할 수 있을 뿐만 아니라 DevTools에서 살펴볼 만한 주요 '통계'로 간주되는 항목 목록을 간편하게 확인할 수 있습니다. 통계에서 렌더링 차단 요청, 레이아웃 변경, 장기 작업 등의 문제를 파악할 수 있습니다. 이러한 문제는 모두 웹사이트의 페이지 로드 성능, 특히 사이트의 코어 웹 바이탈 (CWV) 점수에 부정적인 영향을 미칠 수 있습니다. 실적 통계는 문제 신고와 함께 CWV 점수를 개선하기 위한 실행 가능한 제안과 추가 리소스 및 문서 링크를 제공합니다.

패널의 의견 링크

이 패널은 실험 단계에 있으며 의견을 보내주세요. 버그가 발생하거나 사이트 실적을 개선하는 데 도움이 될 것 같은 기능 요청이 있으면 알려주시기 바랍니다.

성능 통계를 구축한 방법

나머지 DevTools와 마찬가지로 성능 통계를 TypeScript로 빌드하고 lit-html로 뒷받침되는 웹 구성요소를 사용하여 사용자 인터페이스를 구축했습니다. 성능 통계의 차이점은 기본 UI 인터페이스가 HTML canvas 요소이고 타임라인이 이 캔버스에 그려진다는 점입니다. 이 캔버스를 관리하면 많은 복잡성이 발생합니다. 적절한 위치에 적절한 세부정보를 그릴 뿐만 아니라 마우스 이벤트 (예: 사용자가 캔버스의 위치를 클릭했나요?) 사용자가 우리가 그린 이벤트를 클릭했는가?) 그리고 캔버스가 효과적으로 다시 렌더링되는지 확인합니다.

하나의 캔버스에 여러 트랙이 있음

특정 웹사이트에 대해 렌더링할 여러 '트랙'이 있으며, 각 트랙은 서로 다른 데이터 카테고리를 나타냅니다. 예를 들어 통계 패널에는 기본적으로 3가지 트랙이 표시됩니다.

또한 계속해서 패널에 기능을 추가하면서 더 많은 트랙이 추가될 예정입니다.

처음에 생각한 것은 이러한 각 트랙이 자체 <canvas>를 렌더링하여 기본 뷰가 세로로 쌓인 여러 캔버스 요소가 되도록 하는 것이었습니다. 이렇게 하면 각 트랙이 개별적으로 렌더링될 수 있고 경계 밖에서 트랙을 렌더링할 위험이 없으므로 트랙 수준에서 렌더링이 간소화됩니다. 하지만 안타깝게도 이 접근 방식에는 두 가지 주요 문제가 있습니다.

canvas 요소는 (재)렌더링하는 비용이 많이 듭니다. 캔버스가 더 크더라도 캔버스를 여러 개 사용하는 것보다 비용이 많이 듭니다. 여러 트랙에 걸쳐 있는 모든 오버레이를 렌더링하는 것 (예: FCP 시간과 같은 이벤트를 표시하기 위한 수직선)은 복잡합니다. 여러 캔버스에 렌더링하고 모든 캔버스가 함께 렌더링되고 적절하게 정렬되는지 확인해야 합니다.

전체 UI에 하나의 canvas를 사용하면 각 트랙이 올바른 좌표에서 렌더링되고 다른 트랙으로 오버플로되지 않도록 하는 방법을 파악해야 했습니다. 예를 들어 특정 트랙의 높이가 100px인 경우, 해당 트랙이 120px 높이의 항목을 렌더링하고 그 아래의 트랙에 블리드되는 것을 허용할 수 없습니다. 이 문제를 해결하기 위해 clip를 사용할 수 있습니다. 각 트랙을 렌더링하기 전에 표시된 트랙 창을 나타내는 직사각형을 그립니다. 이렇게 하면 이 경계 외부에 그려진 경로가 캔버스에 의해 잘립니다.

canvasContext.beginPath();
canvasContext.rect(
    trackVisibleWindow.x, trackVisibleWindow.y, trackVisibleWindow.width, trackVisibleWindow.height);
canvasContext.clip();

또한 각 트랙이 세로로 위치를 알 필요가 없도록 했습니다. 각 트랙은 마치 (0, 0)에서 렌더링되는 것처럼 자체적으로 렌더링되어야 하며 전체 트랙 위치를 관리하는 상위 수준 구성요소 (TrackManager이라고 함)가 있습니다. 지정된 (x, y) 위치로 캔버스를 변환하는 translate를 사용하면 됩니다. 예를 들면 다음과 같습니다.

canvasContext.translate(0, 10); // Translate by 10px in the y direction
canvasContext.rect(0, 0, 10, 10); // draw a rectangle at (0, 0) that’s 10px high and wide

rect 코드에서 0, 0를 위치로 설정하더라도 전체 변환이 적용되면 0, 10에서 직사각형이 렌더링됩니다. 이렇게 하면 (0, 0에서 렌더링하는 것처럼) 트랙 기반으로 작업할 수 있고, 트랙 관리자가 각 트랙을 렌더링하는 동안 변환하여 각 트랙이 이전 트랙보다 올바르게 렌더링되도록 할 수 있습니다.

트랙 및 하이라이트를 위한 화면 밖 캔버스

캔버스 렌더링은 상대적으로 비용이 많이 들기 때문에 통계 패널이 부드럽고 원활하게 작동하도록 하는 것이 좋습니다. 때로는 전체 캔버스를 다시 렌더링해야 할 수도 있습니다. 예를 들어 확대/축소 수준을 변경하면 모든 것을 다시 시작하여 다시 렌더링해야 합니다. 캔버스 다시 렌더링은 작은 부분만 다시 렌더링할 수 없기 때문에 특히 비용이 많이 듭니다. 캔버스 전체를 지우고 다시 그려야 합니다. 이는 도구가 필요한 최소한의 작업만 계산하고 모든 부분을 삭제한 후 다시 시작하지 않을 수 있는 DOM 재렌더링과는 다릅니다.

시각적인 문제가 발생한 부분 중 하나는 강조표시였습니다. 창에서 측정항목 위로 마우스를 가져가면 타임라인에서 해당 측정항목이 강조표시됩니다. 마찬가지로 특정 이벤트의 통계 위로 마우스를 가져가면 이벤트 주위에 파란색 테두리가 그려집니다.

이 기능은 하이라이트를 트리거하는 요소 위로 마우스를 이동하는 것을 감지한 다음 하이라이트를 기본 캔버스에 직접 그리는 방식으로 구현되었습니다. 이 문제는 강조표시를 삭제해야 할 때 발생합니다. 모든 것을 다시 그리는 것이 유일한 옵션입니다. 큰 구조적 변화가 있는 것이 아니라 하이라이트가 있던 영역을 다시 그릴 수는 없지만, 하나의 항목 주위의 파란색 테두리를 제거하려고 하기 때문에 전체 캔버스를 다시 그리는 것은 지나치게 커다란 느낌이 들 수 있습니다. 또한 여러 하이라이트를 연달아 트리거하기 위해 여러 항목 위로 마우스를 빠르게 이동할 때도 시각적으로 지연됩니다.

이 문제를 해결하기 위해 UI를 두 개의 화면 밖 캔버스, 즉 트랙이 렌더링되는 '기본' 캔버스와 밝은톤이 그려지는 '강조표시' 캔버스로 분할했습니다. 그런 다음 해당 캔버스를 화면에 사용자에게 표시되는 단일 캔버스에 복사하여 렌더링합니다. 캔버스 컨텍스트에서 drawImage 메서드를 사용하여 다른 캔버스를 소스로 사용할 수 있습니다.

이렇게 하면 강조표시를 삭제해도 기본 캔버스가 다시 그려지지 않습니다. 대신 화면의 캔버스를 지운 다음 표시되는 캔버스에 기본 캔버스를 복사할 수 있습니다. 캔버스를 복사하는 작업은 비용이 적게 들며, 비용이 많이 듭니다. 따라서 강조표시를 별도의 캔버스로 이동하면 강조표시를 켜거나 끌 때 이러한 비용이 발생하지 않습니다.

종합적으로 테스트된 trace 파싱

새 기능을 처음부터 빌드하는 경우의 이점 중 하나는 이전에 선택한 기술적 선택을 돌아보고 개선할 수 있다는 것입니다. 우리가 개선하고 싶었던 점 중 하나는 코드를 명시적으로 거의 완전히 별개의 두 부분으로 분할한 것이었습니다.

트레이스 파일을 파싱하고 필요한 데이터를 가져옵니다. 트랙 세트를 렌더링합니다.

파싱(1부)을 UI 작업과 별도로 유지하여 견고한 파싱 시스템을 빌드할 수 있었습니다. 각 트레이스는 다양한 문제를 담당하는 일련의 핸들러를 통해 실행됩니다. LayoutShiftHandler는 레이아웃 이동에 필요한 모든 정보를 계산하고 NetworkRequestsHandler는 네트워크 요청 가져오기만 처리합니다. 트레이스의 여러 부분을 담당하는 여러 핸들러가 있는 명시적인 파싱 단계를 만드는 것도 도움이 됩니다. 트레이스 파싱이 매우 복잡해질 수 있으므로 한 번에 하나의 문제에 집중할 수 있습니다.

또한 DevTools에서 기록을 가져와서 저장한 다음 테스트 모음의 일부로 로드하여 트레이스 파싱을 포괄적으로 테스트할 수 있었습니다. 실제 트레이스로 테스트할 수 있고 더 이상 사용되지 않을 가짜 트레이스 데이터를 엄청나게 많이 쌓지 않을 수 있어 매우 유용합니다.

캔버스 UI의 스크린샷 테스트

테스트 주제에 집중하면서, 일반적으로 프런트엔드 구성요소를 브라우저로 렌더링하고 예상대로 작동하는지 확인하여 프런트엔드 구성요소를 테스트합니다. 클릭 이벤트를 전달하여 업데이트를 트리거하고 구성요소가 생성하는 DOM이 올바른지 어설션할 수 있습니다. 이 접근 방식은 효과적이지만 캔버스로의 렌더링을 고려할 때 떨어집니다. 캔버스를 검사하고 그곳에 그려진 내용을 확인할 방법은 없습니다. 따라서 렌더링 후 쿼리에 대한 일반적인 접근 방식은 적절하지 않습니다.

테스트 범위를 넓히기 위해 스크린샷 테스트로 전환했습니다. 각 테스트에서 캔버스를 실행하고 테스트할 트랙을 렌더링한 다음 캔버스 요소의 스크린샷을 찍습니다. 이 스크린샷은 코드베이스에 저장되며, 이후 테스트 실행에서는 저장된 스크린샷과 생성하는 스크린샷을 비교합니다. 스크린샷이 다르면 테스트가 실패합니다. 의도적으로 렌더링을 변경했고 테스트를 업데이트해야 하는 경우 테스트를 실행하고 스크린샷 업데이트를 강제하는 플래그도 제공합니다.

스크린샷 테스트는 완벽하지 않고 약간 흐릿합니다. 더 구체적인 어설션이 아니라 전체 구성요소가 예상대로 렌더링되는지만 테스트할 수 있으며, 처음에는 모든 단일 구성요소 (HTML 또는 캔버스)가 올바르게 렌더링되도록 하기 위해 이러한 테스트를 과도하게 사용할 수밖에 없었습니다. 이로 인해 테스트 도구 모음이 크게 느려졌고, 관련성이 거의 없는 사소한 UI 변경 (미묘한 색상 변경, 항목 사이에 여백 추가 등)으로 인해 여러 스크린샷에 실패하고 업데이트가 필요한 문제가 발생했습니다. 이제 스크린샷 사용을 줄여 캔버스 기반 구성요소에만 사용했으며, 이 균형은 지금까지 잘 맞았습니다.

결론

새로운 실적 통계 패널 빌드는 팀원들에게 매우 즐겁고 유익한 경험이 되었습니다. 트레이스 파일, 캔버스 작업 등에 관해 많은 내용을 배웠습니다. 새로운 패널을 유용하게 활용하시기 바라며, 여러분의 소중한 의견을 기다리겠습니다.

실적 통계 패널에 대해 자세히 알아보려면 실적 통계: 웹사이트 실적에 대한 활용 가능한 분석 정보 얻기를 참고하세요.

미리보기 채널 다운로드

Chrome Canary, 개발자 또는 베타를 기본 개발 브라우저로 사용하는 것이 좋습니다. 이러한 Preview 채널을 통해 개발자는 최신 DevTools 기능에 액세스하고 최첨단 웹 플랫폼 API를 테스트하며 다른 사용자보다 먼저 사이트에서 문제를 찾을 수 있습니다.

Chrome DevTools팀에 문의하기

게시물에서 새로운 기능과 변경사항 또는 DevTools와 관련된 다른 항목에 대해 논의하려면 다음 옵션을 사용하세요.

  • crbug.com을 통해 제안 또는 의견을 제출하세요.
  • DevTools에서 옵션 더보기   더보기   > 도움말 > DevTools 문제 신고를 사용하여 DevTools 문제를 신고합니다.
  • @ChromeDevTools로 트윗을 보냅니다.
  • DevTools의 새로운 기능 YouTube 동영상 또는 DevTools 팁 YouTube 동영상에 댓글을 남겨주세요.