퀴즈 프로젝트를 일단락 마무리하여 이제 성능 최적화 작업을 해보려합니다.
여태까지 성능최적화 작업을 해보지 않아 무엇부터 해야할지 갈피를 잡지 못했는데요.
할 수 있는 작업들이 여러가지 있지만 우선 크롬 개발자 도구 Lighthouse와 Performane를 사용하여 측정하고 개선해보려고 합니다.
Lighthouse가 전반적인 성능을 측정하기 적절한 도구라고 합니다.
Performance 도구는 특정 작업이나 상호작용에 따른 성능을 세부적으로 분석하기 위해 사용하구요.
그렇다면 Lighthouse를 통해 저의 웹페이지의 성능 측정하고 부족한 부분을 개선해보겠습니다.
Lighthouse는 웹페이지 품질을 개선하는 데 도움이 되는 오픈소스 자동화 도구입니다. 성능, 접근성, 프로그레시브 웹 앱, 검색엔진 최적화 등을 측정할 수 있습니다.
그렇다면 저의 웹사이트의 모든 페이지들을 데스크탑,모바일 별도로 lighthouse 옵션값을 설정하여 검사해보겠습니다.
화면은 다음과 같습니다.
데스크탑
모바일
우선 데스크탑과 모바일 각각을 측정해보겠습니다.
데스크탑과 모바일 각각을 측정해봤을 때, FCP/LCP/SI가 모바일이 시간이 더 걸리는 것을 확인할 수 있습니다.
왜 차이가 날까요?
결론적으로 각각의 네트워크 환경과 CPU 성능이 다르게 설정되어 측정되기 때문입니다.
모바일 환경이 데스크탑에 비해 더 좋지 않은 네트워크나 CPU를 사용하여 측정하기 때문에 위와 같은 결과가 나오는 것이지요.
데스크톱은 측정하는 PC의 성능을 그대로 사용한다고 합니다. 그래서 고사양 컴퓨터일수록 웹 페이지의 성능은 좋게 측정된다고 하네요.
throughput
특정 시간 동안 네트워크를 통해 전송될 수 있는 최대 데이터 양
데스크탑에서는 throughput이 초당 1MB정도 하는 것 같고 CPU도 컴퓨터 그대로 사양을 사용하는 것 같습니다.
반면,모바일은 느린 네트워크로 인해 리소스 로딩이 더 오래 걸립니다.
throughput이 1000KB로 데스크탑보다 10배는 더 느립니다.
CPU 또한 성능을 4배 느리게 시뮬레이션합니다. 때문에 성능이 저하된 상태를 기준으로 측정하는 것입니다.
위와 같은 네트워크와 디바이스 성능으로 측정 결과가 데스크탑보다 더 느리게 나온 것이네요.
이는 아마 모바일 기기의 한정된 처리 성능을 반영하기 위함이 아닐까 합니다.
이것을 감안하고 측정 결과를 살펴봐야할 것 같습니다.
페이지에 내용이 없어서 그런지 측정 결과가 좋게 나온 것 같군요.
좋게 나오긴 하였지만 어떤 부분을 기준으로 측정하였는지 살펴볼게요
성능,접근성,권장사항,검색엔진 최적화 순으로 차례로 살펴볼게요.
성능 측정항목으로써는
위와 같은 항목이 있고 친절히 요약설명까지 해주고 있네요.
문서를 바탕으로 확인해보면
저의 경우에는 FCP가 0.3초 걸렸어요.
문서를 확인해보면 다음과 같이 시간에 따른 등급을 녹색,주황색,빨간색 색깔순으로 평가하고 있네요.
그러면 첫 번째 DOM 콘텐츠를 어떻게 확인할 수 있을까요?
lighthouse에서는 자세히 나오지 않아 성능(Performance) 탭 가서 확인을 해봤어요.
하지만 성능 탭에서 FCP 근처 paint 시점을 확인해봤는데 document 라고만 뜨더군요.
그러면 도대체 어디서 확인할 수 있나 했더니 개발자 도구 레이어(Layer)라는 도구가 있더군요.
개발자 도구 우측 점 세개 버튼을 클릭하면 아래와 같이 드롭다운이 나옵니다.
레이어 도구를 추가해줍니다.
레이어 탭으로 이동하면 다음과 같이 화면이 나올텐데, 저의 경우 ,#document를 누르고 페인트 프로파일러를 눌렀습니다.
그러면 이제 스크롤하면서 페인트 타임라인을 확인할 수 있습니다.
저의 페이지 경우, 첫 번째 콘텐츠는 Link로 감싸진 버튼이었습니다.
import HomeDescription from "@/app/_home_components/homeDescription";
import HomeInnerContainer from "@/app/_home_components/homeInnerContainer";
import HomeLink from "@/app/_home_components/homeLink";
import HomeOuterContainer from "@/app/_home_components/homeOuterContainer";
import HomeTitle from "@/app/_home_components/homeTitle";
/**
* 메인 페이지
* SSG
*/
export const dynamic = 'force-static'
export default function Home() {
return (
<HomeOuterContainer>
{/* 내부 카피 컨텐츠 */}
<HomeInnerContainer>
{/* 메인 타이틀 */}
<HomeTitle
title={"개발자들의 아지트, 코아"}
/>
{/* 메인 설명 */}
<HomeDescription
description={"퀴즈로 실력을 키우고, 함께 성장하세요."}
/>
{/* 메인 링크 */}
<HomeLink/>
</HomeInnerContainer>
</HomeOuterContainer>
);
}
...
import PrimaryButton from "@/app/_components/button/primaryButton";
import Link from "next/link";
import React from 'react';
// 메인 링크
function HomeLink() {
return (
<Link href={"/quiz"}>
<PrimaryButton text={"퀴즈 풀어보기"} color={"primary"} className={"!w-[130px] !h-[42px]"}/>
</Link>
);
}
export default HomeLink;
텍스트가 먼저 나타날 줄 알았는데, 링크가 먼저 나타났네요.
그 다음으로 버튼 위 텍스트 -> 헤더 순으로 페인트 되었습니다.
진단 항목을 보면 렌더링 차단 리소스 제거하기라는 항목이 있어요.
특정 리소스가 FCP를 방해하고 있나보네요.
자세히보니 css 파일이 렌더링 차단 리소스인 것 같아요.
문서에서 확인을 해보면 기본적으로 CSS는 렌더링 차단 리소스로 취급된다고 합니다.
즉, CSSOM이 생성될 때까지 브라우저는 처리된 콘텐츠를 렌더링하지 않습니다. CSS를 간단하게 유지하고 가능한 한 빨리 제공하는게 중요하다고 하네요. 그래야 얼렁 콘텐츠를 렌더링할 수 있을테니깐요.
성능 도구 탭에서도 보면 Rendering blocking이라고 나와있어요.
위 css 내용을 살펴보니 tailwind css 관련 파일 같습니다.
빌드를 하면 tailwind className들을 하나의 css 파일에 빌드하는 것 같아요.
프로젝트의 모든 css 정보를 담고 있는 파일이니 중요한 파일입니다.
이는 페이지 요청시 같이 css 파일을 요청합니다.
페이지 요소 탐색으로 보면 다음과 같이 위에서 발견한 css 파일이 link 태그로 로드되는 것을 확인할 수 있어요.
그렇다면 프로젝트에서 모든 css 정보를 가진 이 파일이 렌더링 차단 리소스라는 것인데 어떻게 제거할 수 있을까요?
문서에서는 인라인 처리를 하라고 말하고 있습니다.
인라이닝을 적용하면 처음 방문하는 방문자가 겪는 초기 다운로드 지연을 제거하여 css가 렌더링하는데 방해가 되지 않도록 할 수 있는 것 같아요.
그렇다면 인라인 처리가 무엇이고 Nextjs에서는 어떻게 할 수 있을까요?
빌드될때 자동으로 생성되는 위 css 파일을 어떻게 인라인 처리를 할 수 있을까요?
인라인화란 스타일(CSS)이나 스크립트(JavaScript)를 외부 파일로 로드하지 않고, HTML 문서 내부에 직접 포함하는 것을 말합니다. 이 방식은 브라우저가 외부 파일을 추가로 요청하지 않아도 되기 때문에, 초기 렌더링 시간을 줄이는 데 유리합니다.
<head>
<style>
body {
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
h1 {
color: #333;
}
</style>
</head>
이런 저런 방법을 찾아보다, nextjs 오픈 소스에서 다음과 같은 이슈와 토론을 발견했습니다.
https://github.com/vercel/next.js/issues/57634
https://github.com/vercel/next.js/discussions/59989
2023년 10월쯤에 올라온 이슈인데 살펴보면 적절한 방법이 올라오지 않은 듯 합니다.
저는 nextjs 14버전을 사용하고 있는데 위에서 말한것처럼 이 버전에서는 모든 css를 하나의 파일로 모아 가져옵니다.
nextjs 개발자들은 이에 대한 업데이트를 14버전에서는 해결하지 않은 듯 해요.
따라서 다시 문서로 가서 찾아봤습니다.
15버전 문서에 제가 찾던 내용이 있더군요.
아직 실험적 단계라고 하고 실제 production에서는 사용하지 않는 것을 권장하고 있습니다.
Next 문서에서 확인해보면 next.config.js에서 옵션값을 설정하면 css를 inline 형식으로 사용할 수 있다고 하네요.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
inlineCss: true,
},
}
export default nextConfig
우선 확인을 위해 15버전으로 업데이트를 하고 lighthouse로 다시 측정해보겠습니다.
15 버전으로 업데이트 후 lighthouse로 다시 측정해보았습니다.
Before
이전 결과구요.
적용 후, 0.1초 감소했네요.
성능탭에서 측정을 해보면 네트워크에서 css 파일에 대한 요청이 보이지 않습니다.
네트워크 탭 또한 css 파일에 대한 요청이 보이지 않아요.
css 관련한 코드들이 어디로 갔나보면 다음과 같이 인라인 스타일로 싹 들어갔어요.
위와 같이 next.config.mjs에서 inlineCss 옵션을 설정하면 css를 인라인 방식으로 사용할 수 있지만 문서에서는 권장하지는 않으니 일단 사용하지 않는 게 좋을 것 같네요.