한준호

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

Frontend/Vue js

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

igoman2 2022. 2. 28. 22:55
728x90

지난 작업 결과

 

지난 작업에서 번들 파일의 용량을 parsed 기준 18MB 에서 10MB까지 줄였다. 사실 번들 파일을 줄이는 것만으로는 큰 성능 향상을 기대하기는 힘들다. 이번엔 번들 파일 최적화와 더불어 다른 작업들도 진행하였고 그 결과

번들 파일의 크기를 4.3MB까지 감소하였고 DOMContentLoad 50% 단축, 로드 완료 시간을 1/6으로 단축하였다.

 

작업한 것은 크게 3가지이다.

 

1. 필요없는 라이브러리, asset, 컴포넌트 삭제

사용하지 않는 코드들은 웹팩의 트리셰이킹을 통해 어느정도 미연에 방지가 가능하지만 트리셰이킹도 관계가 애매한 파일에 대해서는 진행하지 않는다. 언젠가는 쓰겟지 라는 생각으로 주석처리 해놓고 남겨놨던 코드들과 여러 파일들이 시간이 지나다 보니 사용하는 것 보다 사용하지 않는게 더 많을 정도로 쌓이게 되었다. 우리는 git 이라는 형상관리 도구를 사용하기 때문에 과감히 모두 삭제하였다.

moment, quill, aws-sdk 와 같이 사이즈가 큰 라이브러리는 modular import를 적극 활용하였다.

moment.js 같은 경우 성능과 용량 문제로 deprecated 되어 많은 개발자들이 day.js로 갈아타는 추세이며 필자도 추후에 모든 moment 레거시들을 day.js로 대체할 예정이다.

 

2. webpack plugin 활용

vue-cli는 기본적으로 webpack을 활용한다. vue-cli3 버전 이상에서는 vue.config.js에서 webpack에 관한 설정들을 할 수 있다.

필자는 Compression 플러그인과 optimization 속성을 활용하였다.

plugin을 자세히 살펴보면

const path = require("path");
const webpack = require("webpack");
const CompressionWebpackPlugin = require("compression-webpack-plugin");
const productionGzipExtensions = ["js", "css"];
const BundleAnalyzerPlugin =
  require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

module.exports = {
  devServer: {
    disableHostCheck: true,
  },
  configureWebpack: {
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "./src"),
        "@i": path.resolve(__dirname, "./src/assets"),
      },
    },
    plugins: [
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // 1
      // The following is the configuration of the downloaded plug-in
      new CompressionWebpackPlugin({
        algorithm: "gzip", // 2
        test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"), // 3
        threshold: 10240, // 4
        minRatio: 0.8, // 5
      }),
      // 6
      new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 10, 
        minChunkSize: 100,
      }),
      new BundleAnalyzerPlugin({}),
    ],
    // 7
    optimization: {
      splitChunks: {
        chunks: "all",
      },
    },
  },
  css: {
    extract: { ignoreOrder: true },
  },

  transpileDependencies: ["vuetify", "swiper", "dom7"],

  publicPath: "/",

  pluginOptions: {
    i18n: {
      locale: "en",
      fallbackLocale: "en",
      localeDir: "locales",
      enableInSFC: false,
    },
  },
};

 

[1] - 빌드 시 moment.js 라이브에서 모든 locale에 대한 모듈을 다운 받지 않도록 한다. 필요한 경우 추가적인 파라매터를 통해 해당 locale에 대한 모듈만 받도록 할 수 있다.

아래 코드는 moment의 내부 구현 코드이다. name이라는 인자로 locale을 받아 require()을 통해 동적으로 해당 locale의 모듈을 가져오는데 웹팩 빌드 시점에는 name인자를 모르기 떄문에 모든 모듈을 받게 된다. 따라서 이를 방지하면 청크 파일의 용량이 감소한다.

function loadLocale(name) {
    var oldLocale = null;
    // TODO: Find a better way to register and load all the locales in Node
    if (!locales[name] && (typeof module !== 'undefined') &&
            module && module.exports) {
        try {
            oldLocale = globalLocale._abbr;
            require('./locale/' + name);
            // because defineLocale currently also sets the global locale, we
            // want to undo that for lazy loaded locales
            locale_locales__getSetGlobalLocale(oldLocale);
        } catch (e) { }
    }
    return locales[name];
}

 

[2] - gzip 으로 압축한다.

[3] - 상단에 선언한 js, css 에 해당하는 파일만 압축을 진행한다.

[4] - 청크 파일의 크기가 너무 작은 경우 압축하는데 더 시간이 들 수 있기 때문에 일정 크기 이상의 번들 파일만 압축을 하도록 값을 지정한다.

[5] - 압축을 했을 때 비율이 해당 값보다 작게 나오는 경우에만 압축을 진행한다. 효율적으로 압축을 할 수 있게 된다.

[6] - http 최대 리퀘스트 개수는 제한되어 있기 때문에 너무 많은 청크 파일이 생성되면 부하를 유발할 수 있다. 추가적으로 MinChunkSizePlugin을 활용하면 청크 파일의 최소 사이즈를 정하는 것도 가능하다.

[7] - bundle analyzer 의 청크 파일을 확인해보면 각각의 청크 파일이 동일한 라이브러리의 요소를 가지고 있을 수 있다. splitChunks를  활용하면 중복되는 요소를 하나의 chunk로 분리하며 이를 통해 중복되는 chunk 요소를 줄일 수 있다. webpack4 이상에서 지원한다.

추가적으로 TerserWebpackPlugin의 Optimization Minimize를 통해 압축하곤 했는데 webpack 5 부터는 내부적으로 지원한다. vue-cli 버전 4의 경우 webpack 5를 활용하고 있다.

청크 파일을 보면 minify, uglify가 적용된 모습이다.

npm run build 결과

3. 비동기 요청 병목

■ 1번 케이스

■ 2번 케이스

1번과 2번은 동일한 양의 리소스를 요청하지만 FCP(TTV), DOM에 부착되고 요청이 완료되는 시간이 엄청나게 차이가 나는것을 알 수 있다.

화면에 보이기 시작하는 시간은 3초 / 10 초로 3배 차이이며 모든 블로킹, 논블로킹 작용이 끝나서 로드가 되는 시점은 약 2초 / 28초로 무려 10배 이상 차이가 난다. live서버가 아닌 로컬 환경 테스트 + 캐시 유무 + 인텔맥 쓰로틀링 때문에 일관된 값이 나오지 않고 대체로 매우 느린점은 감안하여 대체로 FCP(TTV)는 2배 이상은 꾸준히 차이가 났으며 요청 완료는 5배 이상 차이 났다.

컨텐츠가 화면에 보이기 시작하는 TTV(Time To View) 관점에서는 몇 초 차이가 크게 체감되기 때문에 위 차이는 정말 어마어마한 수치라고 볼 수 있다.

 

그 원인은 바로 웹폰트였다. 1번의 경우 웹폰트를 다운로드하는 작업 상태바가 눈에 보일 정도로 동기적으로, 느리게 진행이 된 반면 2번의 경우는 사이트에 진입하면서 빠르게 폰트들을 비동기로 다운받았다.

 

놀랍게도 두 사진의 차이는 단 코드 3줄이다.

왼쪽이 1번, 오른쪽이 2번이다.

차이는 scss파일에서 @import 로 구글 웹 폰트를 가져오던 코드를 index.html에서 link태그로 대체하였다.

@import는 css파일에서 다른 css파일을 가져오는 기능으로 편리하다고 생각될 수 있지만 직렬 방식(동기)으로 다운로드 한다. 즉 엄청난 병목을 유발 할 수 있다. 특히나 SPA의 main 페이지 같이 필요한 모든 리소스를 다운 받는 과정에서 치명적으로 작용할 수 있다.

반면 link 태그는 비동기로 다운로드 하기 때문에 위와 같은 문제를 예방할 수 있다.

 

Reference

https://engineering.linecorp.com/ko/blog/improve-javascript-sdk-performance/

 

JavaScript SDK 성능개선 방법 - 압축과 최적화로 실행시간 단축하기 - LINE ENGINEERING

안녕하세요. 저는 QUICK Game Platform Dev 팀에서 게임에서 필요한 여러 기능을 제공하는 QUICK Game SDK를 개발하고 있는 이재호입니다. QUICK Game Platform이란 HTML5 기반의 게임을 서비스하기 위해 LINE에서

engineering.linecorp.com

https://www.npmjs.com/package/compression-webpack-plugin

 

compression-webpack-plugin

Prepare compressed versions of assets to serve them with Content-Encoding. Latest version: 9.2.0, last published: 2 months ago. Start using compression-webpack-plugin in your project by running `npm i compression-webpack-plugin`. There are 839 other projec

www.npmjs.com

https://helloinyong.tistory.com/307

 

[2021.05.02] 웹 성능 최적화를 위한 Webpack Bundle Size 줄이기

요즘 웹 페이지의 Build 최적화를 위해서 Bundle 사이즈를 줄이는 작업을 하는 중인데, 새롭게 알게 된 내용에 대해 정리해 보려고 한다. # Webpack Bundle Analizer Webpack Bundle Analizer를 이용하면 Build된..

helloinyong.tistory.com

https://perfectacle.github.io/2017/04/18/webpack2-optimize/

 

(Webpack 2) 최적화하기

들어가기에 앞서이 포스트들에서 말하는 내용들은 전부 배포용 파일에 적합한 작업이다.이런 압축 작업을 개발용 버전에서 매번 빌드할 때마다 실행하면 빌드 시간이 매우 느려지기 때문이다.

perfectacle.github.io

https://sustainable-dev.tistory.com/157

 

moment.js 최적화 - 불필요한 locale파일 빌드 시 제외시키기(with webpack)

현재 회사 프로젝트에서 moment.js를 사용중인데, 실제로 사용하고 있는 local 파일은 ko뿐인데 어마어마하게 많은 모든 local파일을 포함해서 빌드하는것을 발견하였다. 웹팩 번들 애널라이즈로 보

sustainable-dev.tistory.com

https://agal.tistory.com/89

 

최적화 - 웹팩 심화편 | 김정환

[출처 : https://jeonghwan-kim.github.io] 4. 최적화 코드가 많아지면 번들링된 결과물도 커지기 마련이다. 거의 메가바이트 단위로 커질수도 있는데 브라우져 성능에 영향을 줄 수 있다. 파일을 다운로

agal.tistory.com

https://webpack.kr/configuration/optimization/

 

Optimization | 웹팩

웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.

webpack.kr

 

728x90
Comments