회사에서 진행한 새 프로젝트가 배포가 된 후 시간이 흐르고 약간의 여유가 생겼습니다.
마감 기한을 지켜야만 했기에 동작하는 것을 우선시하여 개발하다 보니 개선해야 함에도 넘어갈 수 밖에 없었던 부분이 있어서 아쉬움이 컸었습니다.
그래서 여유가 생긴 김에 그때의 아쉬움을 달래고자 산재되어 있던 여러 개선점을 파악해 개선해보고자 합니다.
관심사에 따른 코드 분리, ESLint 재 적용, any로 적어두고 개발을 하다 미처 수정하지 못한 나의 유산, 비즈니스 로직과 UI 로직 분리 등 다양한 부분이 있었지만 현재 서비스가 되고 있기 때문에 우선은 UX를 개선해보고자 합니다.
UX를 개선하는 여러 방법 중에서도 지표로 나타나는 웹 메트릭 지표 개선을 해보도록 하겠습니다!
먼저 로그인 페이지에 대한 성능 측정 결과는 아래와 같이 나왔습니다.
결과를 보게 되면 Accessibility(a11y), SEO 점수를 개선할 필요가 있어 보입니다.
접근성과 SEO 점수를 개선은 모두 html 태그를 수정 및 추가 하는 방식으로 진행했습니다.
meta viewport tag 수정
기존 메타 뷰포트 태그의 content 속성의 값을 수정해줬습니다.
// 기존
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' charSet='utf-8' />
// 수정 후
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes' charSet='utf-8' />
메타 뷰포트 태그란 뷰포트의 크기와 초기 확대/축소 배율 등을 설정하는 태그입니다. 일반적으로 모바일 기기에 최적화된 웹사이트를 만들 때 사용됩니다. content 속성의 값으로 뷰포트의 너비(width), 초기 확대/축소 배율(initial-scale), 최대 확대/축소 배율(maximum-scale), 사용자가 확대/축소할 수 있는지 여부(user-scalable) 등을 설정할 수 있습니다.
light house에서 제안하는 방법을 사용해 최대 확대/축소 배율을 늘려주었고 user-scalable
값을 yes로 수정하여 유저가 핀치를 통해 화면을 확대/축소할 수 있는 기능을 허용해주었습니다.
lang 속성 추가
html
태그에 lang
속성 값을 추가
title tag 추가
title
태그를 통해 페이지의 타이틀을 설정
title
태그를 추가하니 기존에 존재하는 a11y 점수와 SEO 점수가 개선되는 효과가 나타났습니다.
meta description tag 추가
기존에는 존재하지 않던 meta description tag를 추가했습니다.
<meta name='description' content='웹 페이지에 대한 간단한 요약' />
두 번째 페이지에 대한 성능 측정 결과는 아래와 같이 나왔습니다.
이 페이지는 앞선 작업을 통해 접근성과 SEO 점수를 개선했기 때문에 Performance 점수를 개선하는 것을 목표로 했습니다.
저는 next/script
의 strategy
속성을 이용해 페이지에 사용되는 스크립트 파일의 로드 시점을 조절했습니다.
Next.js에서 스크립트 태그를 추가하는 방법은 아래와 같습니다.
Page Script
특정 경로에서 Script를 사용하게 되면 해당 경로의 페이지가 브라우저에 로드되고 난 후에 script를 불러오고 실행합니다.
Application Script
이 방식은 _document.js
파일 내에서 스크립트 태그를 사용하여 애플리케이션의 어떠한 경로에 접근하더라고 로드되고 실행됩니다. 유저가 여러 페이지를 이동한다고 하더라도 Next.js는 오직 한 번만 스크립트 태그를 로드하는 것을 보증합니다.
참고로 공식 문서는 Page Script 방식을 추천하고 있습니다.
Strategy
Script 컴포넌트의 strategy
속성은 스크립트가 어떻게 로드되는지 제어하는 데 사용됩니다.
strategy
속성은 다음과 같은 3가지 값 중 하나를 가질 수 있습니다.
lazyOnload
: 스크립트가 페이지 로드 후에 로드됩니다. 사용자가 페이지를 보는 동안 추가로 스크립트가 로드될 수 있으므로 초기 로딩 속도가 빨라집니다.beforeInteractive
: 스크립트가 페이지의 <head>
섹션에 있는 다른 스크립트보다 빠르게 로드됩니다. 이 옵션은 <head>
에 적용되며, lazyOnload
옵션보다 더 빠른 로딩을 제공합니다. 그러나 스크립트가 완전히 로드되기 전에 페이지를 렌더링할 수 있으므로, 스크립트에 따라서는 렌더링 중 오류가 발생할 수도 있습니다.afterInteractive
: 스크립트가 페이지의 <body>
태그 안에 있는 다른 요소보다 빠르게 로드됩니다. 이 옵션은 <body>
에 적용되며, 페이지의 렌더링이 완료된 후에 스크립트가 로드됩니다. 이는 초기 로딩 속도가 빠르고 렌더링 오류를 방지할 수 있지만, 사용자가 페이지를 보는 동안 스크립트가 로드되는 동안 일시적인 콘텐츠 변경이 발생할 수 있습니다.LCP는 여전히 개선해야 하는 부분이지만 Script를 통해 TBT를 유의미하게 줄였다는 점은 만족스러웠습니다.
기존의 useEffect
Hook에서 Data Fetching을 하고 반환값에 따라 명령형으로 처리해주고 있었습니다.
이 부분을 선언적으로 처리하기 위해 Suspense
를 사용했고 이를 위해 react-query
를 이용했습니다.
위와 같이 수정하니 가독성 또한 훨씬 좋아졌고 불필요한 상태도 삭제 됐으며 1차 측정 때 아쉬움이 남았던 LCP 또한 훨신 개선된 것을 확인할 수 있었습니다.
추가적으로 Next.js에서 성능 분석을 도와주는 도구 중 lighthouse에서 제안한 @next/bundle-analyzer
이 궁금해서 한번 설치하고 적용해봤습니다.
@next/bundle-analyzer
는 Next.js 애플리케이션의 번들(Bundle) 구성과 크기를 분석해주는 도구입니다.
이 도구를 사용하면 애플리케이션의 코드가 어떻게 번들로 구성되는지, 각 모듈이 얼마나 많은 용량을 차지하는지, 이를 통해 불필요한 코드를 제거하고 번들의 크기를 줄일 수 있는 최적화 작업을 수행할 수 있습니다.
yarn add @next/bundle-analyzer
// npm i @next/bundle-analyzer
// 윈도우 환경을 위해 cross-env 패키지도 설치
yarn add cross-env
// npm i cross-env
패키지를 설치한 후 build
스크립트와 next.config.js
를 변경해줘야 합니다.
// package.json
{
...
"script": {
...
"build": "cross-env ANALYZE=true NODE_ENV=production next build"
}
}
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
reactStrictMode: true,
swcMinify: true
});
모든 설정을 마친 후 빌드하게 되면 빌드 파일 내에 analyze
디렉토리가 생기고 그 안에 client.html
, edge.html
, nodejs.html
파일이 생성됩니다.
이 분석 결과를 통해 어떤 페이지가 번들 크기가 큰지 어떤 라이브러리가 크기가 큰지 등에 대한 정보를 얻고 페이지의 성능을 최적화 할 수 있을 것 같습니다.