웹사이트 로딩 시간을 줄이는 가장 효과적인 5가지 방법
웹사이트나 앱이 처음 로딩되는 속도는 사용자 경험에 있어 매우 중요한 첫인상을 좌우합니다. 이 글에서는 초기 페이지 로딩 시간을 단축하는 효과적인 방법들을 소개합니다.
초기 로딩 시간의 중요성
사용자가 웹사이트 주소를 입력하고 콘텐츠를 보기까지 걸리는 시간은 긍정적인 첫인상을 만드는 데 결정적인 요소입니다. 단 몇 초 차이로 사용자의 만족도가 크게 달라질 수 있습니다.
Amazon의 연구에 따르면, 페이지 로딩 시간이 100밀리초 느려질 때마다 매출이 1% 감소하는 것으로 나타났습니다.
그럼에도 불구하고 많은 개발자들이 이 부분을 간과하는 경우가 많습니다. 새로운 기능을 추가할 때마다 라이브러리들이 계속해서 추가되고, 시간이 지날수록 성능은 점차 저하됩니다. 특히 로딩 속도가 느린 페이지는 사용자가 이탈하기 쉬워 전환율 감소를 감지하기 어려울 수 있습니다.
웹사이트 성능 개선은 프런트엔드와 백엔드 모두에서 적용할 수 있는 기술입니다. 중요한 것은 웹 애플리케이션이 사용자에게 빠르게 로딩되어야 한다는 점입니다.
정확한 측정의 중요성
가장 먼저 해야 할 일은 로딩 시간을 정확하게 측정하는 것입니다. 로딩 과정은 여러 단계로 이루어져 있으며, 올바른 부분을 측정하지 않으면 병목 현상이 발생하는 위치를 파악하기 어렵습니다.
다음은 로딩 과정에서 중요한 단계들을 보여줍니다.
측정 지표 | 다음 다이어그램 출처: 테라스트럭트
위 다이어그램의 각 단계를 추적하여 로딩 성능을 개선해야 합니다.
이제 측정 방법을 살펴보겠습니다.
브라우저 요청에 대한 서버 응답
서버에서 이 지표를 측정해야 합니다. API가 요청을 받고 응답을 보내는 데 걸리는 시간을 파악해야 합니다. 데이터베이스 호출 등 외부 요인에 따라 응답 시간이 크게 달라질 수 있습니다.
서버 응답 수신 시간
이 지표는 측정하기 조금 더 까다롭습니다. 서버에서 응답을 보낼 때 타임스탬프를 추가하고, 사용자 측에서 응답을 받는 즉시 현재 시간으로 측정하는 방법이 있습니다. (HTML 헤드 스크립트 태그에서 측정 가능)
콘텐츠가 포함된 첫 번째 페인트(First Contentful Paint, FCP)
콘텐츠가 포함된 첫 번째 페인트는 DOM에 첫 번째 요소가 렌더링되는 시점을 의미합니다. 텍스트나 배경, 로딩 스피너 등이 해당될 수 있습니다. Chrome 개발자 도구의 Lighthouse를 사용하여 측정할 수 있습니다.
콘텐츠가 있는 첫 번째 페인트에서 가장 큰 콘텐츠 페인트(Largest Contentful Paint, LCP)까지
가장 큰 콘텐츠 페인트는 사용자 브라우저의 뷰포트에서 가장 큰 요소가 렌더링되는 시점을 의미합니다. 이는 일반적으로 페이지 로딩의 "렌더링" 단계의 끝을 나타내며, 사용자는 화면에 채워진 콘텐츠를 보게 됩니다. Lighthouse로 측정할 수 있습니다.
가장 큰 콘텐츠 페인트에서 상호작용 시간(Time to Interactive, TTI)까지
마지막으로, 상호작용 시간은 사용자가 스크롤, 클릭, 입력 등과 같은 동작을 할 수 있게 되는 시점을 의미합니다. 렌더링된 화면이 이미 표시되어도 사용자가 상호작용할 수 없을 때 답답함을 느낄 수 있습니다. Lighthouse에서 이 지표를 측정할 수 있습니다.
코드 최적화
이제 측정 지표를 확보했으므로 성능 최적화를 시작할 수 있습니다. 최적화에는 장단점이 따르므로, 측정을 통해 어떤 개선이 필요한지 파악해야 합니다.
로딩 속도가 가장 빠른 페이지는 빈 페이지입니다. 그러나 앱에 너무 많은 코드를 추가하면 로딩 속도가 느려집니다. 종종 조금씩 코드를 추가하다 보면, 시간이 지나면서 성능 저하를 인지하지 못하게 됩니다. 따라서 주기적으로 코드 최적화가 필요합니다.
코드 최적화를 통해 얻을 수 있는 성능 향상은 다음과 같습니다.
- 앱이 네트워크를 통해 더 빠르게 전송됩니다.
- 사용자의 브라우저가 코드를 더 빨리 구문 분석합니다.
네트워크 전송 속도 향상은 상대적으로 작습니다. 요청은 압축되어 전송되므로, 1MB의 소스 코드를 줄이더라도 대역폭은 10KB 정도만 절약됩니다. 하지만 브라우저가 코드를 더 빨리 분석하게 되는 효과는 매우 큽니다. 사용자는 다양한 브라우저와 컴퓨터를 사용하므로, 모든 사용자가 개발자의 컴퓨터처럼 빠르게 코드를 분석할 수 있는 것은 아닙니다. 특히 컴퓨팅 성능이 낮은 모바일 기기에서는 더욱 그렇습니다. 이 차이는 초 단위의 로딩 시간 차이로 이어질 수 있습니다.

따라서 코드를 줄일수록 브라우저가 더 빨리 코드를 분석하고 앱을 실행할 수 있습니다. 심지어 자바스크립트로 제어되는 로딩 화면조차 해당 코드의 구문 분석이 선행되어야 합니다.
하지만 그렇다고 해서 기능을 줄이거나 코드를 삭제할 필요는 없습니다. 다행히 코드 축소, 부분 가져오기, 트리 쉐이킹 등을 통해 코드를 효율적으로 관리할 수 있습니다.
- 코드 축소(Minification): 코드 축소기는 변수 이름을 짧게 바꾸고(예: signUpDarkModeButton을 ss로 변경), 공백 문자를 제거하는 등 불필요한 부분을 제거하여 코드의 크기를 줄입니다.
- 부분 가져오기(Partial Imports): 라이브러리는 종종 불필요한 코드까지 포함하고 있습니다. 필요한 특정 기능만 가져오는 방식으로 라이브러리 사용을 최적화할 수 있습니다.
- 트리 쉐이킹(Tree Shaking): 때로는 디버깅을 위해 남겨둔 코드나 사용되지 않는 기능을 정리하지 않아 소스 코드에는 있지만 실행되지 않는 코드가 존재할 수 있습니다. Webpack과 같은 JavaScript 도구는 이러한 데드 코드(Dead Code)나 사용하지 않는 종속성을 감지하여 프로덕션 빌드에서 자동으로 제거해 줍니다.

코드 청크 분할
전체 앱의 코드 크기를 가능한 한 줄인 후에는, 초기 로딩에 필요한 코드만 로딩하는 방법에 대해 생각해 볼 수 있습니다. 이는 코드 청크 분할을 통해 가능합니다.
예를 들어 앱 코드의 20%가 사용자가 몇 번의 클릭 후에만 사용할 수 있는 기능이라면, 로딩 화면이 표시되기 전에 해당 코드를 브라우저가 분석하는 것은 불필요한 시간 낭비입니다. 코드를 청크로 분할하면 상호작용 시간을 크게 줄일 수 있습니다.
모든 JavaScript 파일의 복잡하게 얽힌 종속성 그래프 대신, 쉽게 분리할 수 있는 영역을 파악해야 합니다. 예를 들어, 어떤 컴포넌트가 무거운 라이브러리를 로드한다면, 해당 컴포넌트를 별도의 파일로 분리한 다음 사용자가 해당 컴포넌트와 상호작용할 준비가 되었을 때만 로드할 수 있습니다.

사용하는 프레임워크에 따라 지연 로딩을 위한 다양한 라이브러리를 사용할 수 있습니다. 초기 로딩 속도를 높이기 위해 모든 컴포넌트를 분리할 필요는 없습니다. 분할할 수 있는 가장 큰 부분을 먼저 찾고, 소스 코드를 분할하는 것이 좋습니다.
서버 측 렌더링 (Server-Side Rendering, SSR)
브라우저가 코드를 분석하고 컴파일하는 데 많은 시간이 걸린다는 점을 고려할 때, 로딩 시간을 줄이는 방법 중 하나는 서버에서 이러한 작업을 일부 처리하도록 하는 것입니다. 일반적으로 대부분의 단일 페이지 앱은 빈 페이지를 제공한 후 JavaScript를 사용하여 모든 콘텐츠를 채웁니다. 그러나 서버 측 렌더링은 서버(일반적으로 Node.js)에서 JavaScript 엔진을 실행하여 가능한 한 많은 데이터를 채울 수 있게 합니다.

사용자의 브라우저보다 서버가 훨씬 빠르고 예측 가능합니다. 앱이 상호작용하려면 여전히 JavaScript 코드를 분석해야 하지만, 서버 측 렌더링을 통해 초기 콘텐츠를 미리 채워 사용자가 페이지를 열었을 때 최소한 로딩 화면이나 진행률 표시줄을 볼 수 있게 할 수 있습니다.
또한 초기 화면에 필요한 데이터가 있다면, 클라이언트에서 데이터를 가져오기 위해 별도의 요청을 할 필요 없이 앱에서 미리 수화된 데이터를 사용할 수 있습니다.
리소스 압축
리소스는 페이지를 풍부하게 만들고, 리소스 렌더링이 완료될 때까지 페이지가 완전히 로딩된 것처럼 느껴지지 않습니다. 배경 이미지, 사용자 인터페이스 아이콘, 사용자 프로필 사진, 로딩 스피너 등이 이에 해당합니다. 리소스는 종종 레이아웃을 변경할 수 있으며, 사용자가 무언가와 상호 작용하려고 할 때 리소스가 로딩되는 동안 페이지가 계속 이동할 수 있습니다. 때로는 이러한 리소스가 가장 큰 콘텐츠 페인트가 될 수 있습니다.
하지만 리소스는 앱에서 가장 큰 부분을 차지할 수도 있습니다. 이미지는 몇 메가바이트에 달할 수 있으며, 많은 아이콘을 로드하면 브라우저의 최대 동시 네트워크 요청 제한을 초과하여 로딩 지연이 발생할 수 있습니다.
인터넷에서 이미지를 다운로드한 후 앱에서 참조하는 것은 권장하지 않습니다. 이미지는 표시되는 크기에 맞게 조정해야 합니다. 예를 들어, 50px x 50px 요소에 사용자 프로필 사진을 표시하는 경우, 원본 이미지가 매우 큰 경우(마치 데스크탑 배경화면처럼 선명한 이미지) 브라우저는 큰 이미지를 다운로드한 다음, 다시 작은 크기로 조정해야 합니다. 이는 불필요한 시간 낭비입니다.
둘째, 이미지는 형식에 따라 압축할 수 있습니다. 요즘에는 WebP 형식이 선호되지만, 웹 압축 기술은 지속적으로 발전하고 있으며 새로운 형식들이 계속해서 등장하고 있습니다. 그러나 새로운 형식은 일부 구형 브라우저에서 지원하지 않을 수 있습니다. 다행히 브라우저 기술은 사용자의 브라우저가 지원하는 형식으로 리소스를 로드할 수 있도록 합니다.
따라서 최신 형식으로 압축하되, 구형 형식을 유지하고 폴백 형식을 지원하는 이미지 및 비디오 요소를 사용하는 것이 좋습니다.
결론
위에서 소개한 다섯 가지 기술은 사용자에게 앱을 빠르게 로딩하는 데 효과적입니다. 빠른 로딩 속도는 SEO에도 긍정적인 영향을 주어 전환율, 사용자 만족도, 검색 순위를 높여줍니다. 테라스트럭트는 이러한 기술들을 활용하여 이 문서에서 본 다이어그램을 사용자가 가능한 한 빨리 보고 사용할 수 있도록 지원합니다.