한준호

스타트업 주니어 프론트엔드 개발자의 브라우저 렌더링 최적화 본문

Frontend/Vue js

스타트업 주니어 프론트엔드 개발자의 브라우저 렌더링 최적화

igoman2 2021. 10. 1. 18:32
728x90

회사 서비스 YalliYalli의 브라우저 렌더링 속도가 느려지기 시작했습니다.

브라우저 사용 중 99%의 사용자 경험은 네트워크 속도에 의존한다고 하지만 1%에 해당하는 0.0몇초의 성능 차이가 좋은 서비스와 나쁜 서비스의 차이라고 생각합니다.

 

프론트엔드에서 바라보는 성능 최적화는 여러 가지 관점에서 바라볼 수 있습니다.

번들링 파일 최적화, lazy loading, dynamic import, css 스프라이트, 리플로우/리페인팅 분석 ...

저는 그 중에서

1. 번들링 파일 최적화

2. lazy loading, dynamic import

을 적극 활용하였습니다.

 

*성능 측정은 차이를 극명하게 보여주기 위해 로컬 개발 환경을 기준으로 하였습니다.

 

1. 번들링 파일 최적화

webpack-bundle-analyzer 를 활용하여 번들링된 파일의 크기를 분석할 수 있습니다.

npm i wepback-bundle-analyzer -D

package.json

 

설치가 완료되었으면 vue.config.js를 세팅해주어야 합니다.

아래 코드를 작성해줍니다.

const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;
module.exports = {
  configureWebpack: {
    plugins: [new BundleAnalyzerPlugin()],
  },
};

이제 npm run build를 하면 자동으로 브라우저에 화면을 띄워줍니다.

번들링된 파일과 크기를 시각적으로 볼 수 있습니다.

 

"18.46MB"

빌드 후 생성된 파일의 크기가 무려 18.46MB입니다.

첫 페이지에서 18.46MB에 해당하는 리소스를 받기엔(물론 모두 받진 않지만) 부담스러운 크기입니다.

 

자세히 살펴보니 가장 큰 용량을 차지하고 있는 aws-sdk에 해당하는 js파일이 2개가 있습니다.

번들링된 이후에도 4~5MB가 되는게 중복으로 2개나 있으니 압도적인 크기를 차지합니다.

프로젝트에서 동일한 aws-sdk 라이브러리를 import하는 컴포넌트가 상당히 많습니다. 이를 개선해야 빌드 파일의 크기를 줄일 수 있어 보입니다.

 

■ Modular import 

검색해보니 aws-sdk 라이브러리 크기에 관한 게시글이 역시나 굉장히 많았습니다.

 

On October 19th, 2020, we published the Release Candidate (RC) of the AWS SDK for JavaScript, version 3 (v3). One of the major changes in the JavaScript SDK v3 is modularized packages. This blog post explains why we decided to publish modular packages, and gives an example of performance improvement due to bundle size reduction.

aws 문서에 있는 내용입니다. 번들 사이즈를 줄이기 위해 modular import를 제공한다고 합니다.

import AWS from "aws-sdk/clients/s3";

모든 컴포넌트에서 s3에 파일을 업로드 하는 기능을 사용중이었으므로 위와 같이 s3 모듈만 가져올 수 있습니다.

 

그런데 문제가 있습니다.

aws-sdk를 import하다가 s3 모듈만 가져오니 AWS 환경 세팅을 하는 메소드에서 undefined 에러가 뜹니다.

AWS.config.update({
  accessKeyId:
  secretAccessKey:
  region:
});

const s3 = new AWS.S3();

 

 

이유는 기존에 AWS를 세팅하던 방식 때문입니다.

aws-sdk를 import하고 AWS.config의 update를 사용하여 세팅을 해주었지만 s3 모듈에서 Import한 AWS 객체는 config.update()를 가지고 있지 않습니다.

 

따라서 다음과 같이 방법을 바꿔서 세팅을 해주었습니다.

const s3 = new AWS({
  accessKeyId: 
  secretAccessKey: 
  region: 
});

 

이제 모든 기능이 정상적으로 작동합니다.

 

하지만 한가지 고민이 더 있습니다.

모든 컴포넌트에서 또다시 위와 같은 초기화를 중복하여 진행하는 것은 명백한 낭비입니다.

따라서 js파일 안에 AWS 환경을 세팅한 s3 객체를 선언해놓고 ES6의 모듈을 활용하기로 했습니다.

import AWS from "aws-sdk/clients/s3";

const s3 = new AWS({
  accessKeyId:
  secretAccessKey:
  region:
});

export default s3;

aws.js에 위와 같이 선언한 후 export하면 다른 컴포넌트에서 import하여 사용할 수 있습니다.

 

aws-sdk뿐만 아니라 moment와 같이 크기가 큰 라이브러리는 modular import를 통해 번들 사이즈를 줄일 수 있습니다.

예를 들어 moment.js 라이브러리는 시간 관련한 작업을 할때 쓰이는 라이브러리인데, 용량이 매우 크기 때문에 한국 기준으로의 연산만 필요한 경우 locale이 한국으로 설정된 일부 기능만 라이브러리에서 가져올 수 있습니다.

 

 

 

2. lazy loading

두번째는 lazy loading을 적용하는 것입니다.

제가 적용할 lazy loading은 두 가지입니다.

  • 컴포넌트 lazy loading
  • 이미지 lazy loading

lazy loading은 필요한 리소스를 미리 가져오지 말고 필요할 때 가져오는 기능입니다.

즉 필요없는 컴포넌트와 이미지들을 처음부터 가져오지 않고 화면에 보여질 때 가져오도록 하여 리퀘스트의 부담을 줄이는 것입니다.

 

a. 컴포넌트 lazy loading

굉장히 쉽습니다.

어쩌면 이 글을 보고 계시는 분들도 무의식적으로 쓰고 계셨을 수도 있습니다.

내용은 이전 포스트에 올렸으니 https://igoman2.tistory.com/53 에서 보시면 됩니다.

 

Vue lazy loading을 활용한 렌더링 최적화

spa의 가장 큰 단점은 웹에 진입할 때 번들링한 리소스를 한번에 받는 것이다. 따라서 초기 진입 속도가 느릴 수 밖에 없다. 이를 개선하기 위해 웹팩의 코드 스플리팅을 통한 chunck를 활용하여 초

igoman2.tistory.com

프로젝트 내 라우터와 컴포넌트 안에 있는 모든 컴포넌트 import를 webpack의 code splitting을 활용하도록 dynamic import로 변경하였습니다.

b. 이미지 lazy loading

vuetify의 v-img태그는 lazy-loading 기능을 제공하고 있습니다.

https://vuetifyjs.com/en/components/images/#usagE

 

Image component

The image component provides a flexible interface for displaying different types of images.

vuetifyjs.com

 

위 문서에서 보이듯이 기존에 src 속성에만 파일을 넣어주던 것을 lazy-src 속성을 활용하면 됩니다.

메인 페이지 상단 부분의 이미지를 제외한 모든 이미지에 lazy loading 속성을 적용하였습니다.

 

조금 더 막강한 lazy loading을 구현하려면 IntersectionObserver API를 활용하면 됩니다.

IntersectionObserver API는 드래그 하여 해당 viewport에 진입하였을 때를 판단하여 액션을 취하는 식으로 많이 사용됩니다.

즉, 보이지 않던 컴포넌트 영역에 사용자가 도달하면 그때 컴포넌트나 이미지를 로딩하게 만들 수 있습니다.

 

 

추가적으로 

console.log 코드 제거, 주석 제거, 불필요한 컴포넌트, 코드 제거 등을 진행하였고 그 결과는 다음과 같습니다.

 

 

 

결과

1. 번들 사이즈

번들 사이즈가 10.28MB 로 거의 절반 가량 감소하였습니다. 위 사진처럼 aws-sdk가 중복으로 잡히던 것이 해결된 것을 볼 수 있습니다.

10.28MB는 여전히 부담스러운 수치이지만 번들 사이즈가 45%나 감소시킬 수 있었습니다.

 

2. 빌드 속도

125초 -> 100초     20% 감소

 

 

3. 초기 리퀘스트

- 이전

 

- 이후

메인 페이지 로딩 시 초기 리퀘스트 요청 역시 141 -> 125건으로 12.5% 감소,

리소스 크기는 5.0MB -> 4.2MB로 16% 감소하였습니다.

 

 

 

매번 새로운 기능을 만들고 화면 제작을 하다가 이번 기회에 성능과 관련된 이슈들을 처음으로 다뤄보았습니다.

webpack이 무엇인지, 번들링이 어떻게 일어나는지, 렌더링 순서는 어떻게 되는지 등 새로운 정보들을 많이 배울 수 있었고 앞으로 개발을 어떻게 해야할지에 대한 가치관도 정립되었습니다.

 

728x90
Comments