본문으로 바로가기

Compression Javascript

category software engineering/frontend 2023. 3. 4. 21:47
728x90
  1. Next.js는 기본적으로 Gzip 압축을 제공하지만 Nginx와 같은 HTTP 프록시에서 사용하는 것이 좋다.
  2. Webpack을 사용하여 코드를 번들링하는 경우 Gzip 압축에 CompressionPlugin을 사용하거나 Brotli 압축에 BrotliWebpackPlugin을 사용할 수 있다. (vite-plugin-compression2)
  3. Oyo는 Gzip 대신 Brotli 압축으로 전환한 후 파일 크기가 15-20%, Wix는 21-25% 감소했다.
  4. compress(a + b) <= compress(a) + compress(b) - 여러 개의 작은 번들보다 하나의 큰 번들의 압축률이 더 낫다. 이로 인해 중복 제거와 캐싱이 브라우저 성능 및 압축과 상충되는 세분화된 트레이드오프가 발생한다. 세분화된 청킹은 이러한 트레이드오프를 처리하는 데 도움이 될 수 있다.
  5. Gzip 및 Brotli는 JavaScript를 압축하는 가장 일반적인 방법이며 많은 최신 브라우저에서 지원한다.
  6. Brotli는 유사한 압축 수준에서 더 나은 압축 비율을 제공한다.

 

HTTP

손실 압축은 압축-압축 해제 주기가 사용성을 유지하면서 문서를 약간 변경하는 것을 의미한다. 최종 사용자는 변경 사항을 대부분 감지할 수 없다. 손실 압축의 가장 일반적인 예시는 이미지에 대한 JPEG 압축이다.

무손실 압축을 사용하면 압축 및 압축 해제 후 복구된 데이터가 원본과 정확하게 일치한다. 무손실 압축의 예시로는 PNG 이미지가 있다. 무손실 압축은 텍스트 전송과 관련이 있으며 HTML, CSS, JavaScript와 같은 텍스트 기반 형식에 적용해야 한다.

브라우저에서 전부 유효한 JavaScript 코드를 위해 무손실 압축 알고리즘을 사용해야 한다. 

 

Minification

최소화는 JavaScript 및 CSS 최적화를 위한 표준 관행이다. JavaScript 라이브러리 개발자는 일반적으로 프로덕션 배포를 위해 min.js 확장자로 표시되는 축소된 파일을 제공한다. (예: jquery.js 및 jquery.min.js)

HTML, CSS 및 JavaScript 리소스 최소화를 위해 다양한 툴이 제공된다. Webpack v4에는 최소화된 빌드 파일을 만들기 위한 라이브러리용 플러그인이 기본으로 제공된다.

// webpack
new webpack.optimize.MinChunkSizePlugin({
  minChunkSize: 512000 // 50kb
})

https://vitejs.dev/config/build-options.html

 

압축 알고리즘

Gzip과 Brotli는 HTTP 데이터를 압축하기위해 쓰이는 요즘 가장 인기있는 알고리즘이다. Brotli은 NetlifyAWSVercel을 포함한 호스팅 프로바이더나 미들웨어에서도 쉽게 이용할 수 있다. 대량의 트래픽을 처리해야 하는 OYOWix와 같은 웹 사이트들은 Gzip을 Brotli로 변경하여 성능을 향상시킬 수 있다.

  • Gzip 9 레벨은 가장 좋은 압축 비율과 속도를 제공한다. 9 레벨을 사용할 것을 추천한다.
  • Brotli을 사용할 때에는 6-11 레벨을 고려하자. Gzip과 비교하여 조금 더 압축되며 빠르다.
  • 전반적인 크기는 Brotli 9-11 레벨이 Gzip보다 훨씬 좋으나, 속도가 느리다.
  • 번들이 클 수록 더 나은 압축 비율과 속도가 나온다.
  • 알고리즘간의 비교 결과는 모든 번들 크기에서 유사하게 나왔다 (예를 들어 Brotli 7 은 모든 번들 크기에서 Gzip 9 보다 나았고. Gzip 9는 모든 번들 크기에서 Brotli 5 보다 빨랐다)

Next.js는 기본적으로 Gzip압축을 지원하지만. HTTP 프록시에서 따로 활성화해주는 것을 추천하고 있다. Vercel 플랫폼에서는 proxy 레벨에서 Gzip, Brotli모두 지원하고 있다.

더보기
차이점은 Webpack 압축은 빌드 실행 중에 파일을 한 번만 압축한다는 것입니다. 압축된 버전은 디스크에 저장됩니다.

반면에 Express 플러그인은 요청 시점에 파일을 압축합니다 . 특정 패키지 에는 캐싱이 내장되어 성능 저하가 한 번만(또는 드물게) 발생할 수 있지만 일반적으로 차이점은 HTTP 요청에 응답하는 시점에 발생한다는 것입니다.

실시간 압축의 경우 일반적으로 업스트림 프록시(예: Nginx)가 gzip 및 캐싱을 처리하도록 하는 것이 성능이 더 좋습니다. 왜냐하면 그들은 이를 위해 특별히 구축되었고 노드 런타임의 오버헤드를 겪지 않기 때문입니다(대부분 C로 작성됨). ).

또 다른 해결책은 Webpack이 파일을 압축하고 압축되지 않은 파일의 .gz 버전을 생성하도록 하는 것입니다. 그러면 express-static-gzip 과 같은 패키지가 미리 컴파일된 버전을 제공할 수 있으므로 요청 시 gzip으로 인해 성능이 저하되지 않습니다. 이는 Node.js가 HTTP 요청에 직접 응답하고 업스트림 프록시/로드 밸런서를 사용하지 않는 경우에 유용합니다.
 
Webpack을 사용하는 이점은 빌드 프로세스에서 몇 초의 추가 시간을 신경쓰지 않을 수 있기 때문에 최대 압축 설정(또는 파일을 처리하는 데 더 오래 걸리는 알고리즘)을 사용할 수 있다는 것입니다. 보다 복잡한 압축을 활성화하여 HTTP 방문자가 더 큰 문제가 될 것입니다.
 

 

또 Node.js를 포함한 웹 서버에서도 동적 무손실 압축을 적용할 수 있다. 브라우저는 요청 헤더의 Accept-Encoding 을 통해 지원하는 알고리즘 정보를 서버에 보낸다.

Accept-Encoding: gzip, br

 

Brotli은 다른 알고리즘에 비해 더 많이 압축되기때문에 사용하길 추천한다. 브라우저가 Brotli을 지원하지 않는 경우를 위해 Gzip을 폴백으로 사용할 수 있다. 서버에 정상적으로 세팅되어 있다면 서버는 Content-Encoding 응답 헤더를 통해 리소스가 어떤 알고리즘으로 압축되었는지를 알려준다.

Content-Encoding: br

 

const CompressionPlugin = require("compression-webpack-plugin");
// ...
// plugins에 아래 플러그인 추가
new CompressionPlugin({
  asset: "[path].gz[query]",
  algorithm: "gzip",
  test: /\.(js|html)$/,
  threshold: 10240, // 10kb
  minRatio: 0.8
})

파일 크기가 너무 작으면 압축을 해제하는데 더 큰 시간을 소모하므로 threshold를 잘 지정해주자.

 

JavaScript 압축 및 로드 세분성

청크 세분화의 트레이드오프

  1. 다운로드 속도 향상: 이전 섹션에서 보았듯이 압축을 통해 다운로드 속도를 개선할 수 있다. 다만 여러 작은 청크를 압축하는 것 보다 하나의 큰 코드를 압축하는 것이 더 좋은 결과를 보인다.
  2. 캐시 히트 및 캐시 효율 향상: 작은 크기의 의 번들은 JS를 점진적으로 로드하는 앱에서 더 나은 캐시 효율을 보인다.
  3. 빠른 실행 속도: 코드가 빨리 실행되려면 다음의 요구사항을 만족해야 한다.
    • 모든 종속 모듈이 빠르게 사용가능해야 한다 - 해당 종속 모듈들은 함께 묶여 다운로드되거나 캐시히트된다. 이는 관련된 코드를 모두 하나의 큰 청크로 묶어야 함을 의미한다.
    • 페이지 혹은 라우팅 경로상에서 필요로 하는 코드만을 실행해야 한다. 작은 청크 크기를 위해 코드 중복을 최소화 해야 한다.
    • 메인 스레드에서 롱 태스크로 오랫동안 블록하는 경우 작은 청크로 나누어야 한다.

 

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      ...,
    }
}

웹 팩에서 다음과 같은 트레이드 오프를 고려하여 성능 개선을 만들어 내보자.

 

MTU가 1500정도이므로 임계값을 1400으로 설정해주고 실제로 성능 개선을 이뤄 낸 사례가 있는데 찾아본 두 사례의 임계값이 10배 차이나다보니 실제 내가 원하는 프로젝트에는 이거저거 테스트를 해봐야할거 같다.

 

Nextjs는 SplitChunksPlugin을 채택하여 다음과 같은 청크 세분화 전략을 사용해 위에서 언급했던 세분성 트레이드오프를 해결하는 청크들을 생성한다.

  • 160KB 보다 큰 서드 파티 모듈은 개별 청크로 분리함
  • react, react-dom과 같은 프레임워크 의존 모듈을 위한 별도의 청크 생성
  • 최대 25개 까지의 공유 청크가 생성됨
  • 청크로 만들어지는 모듈의 최소 크기가 20KB로 변경됨

 

https://patterns-dev-kr.github.io/performance-patterns/compressing-javascript/

 

Compressing JavaScript

네트워크를 통해 스크립트를 받는 시간을 최소화한다 - 최적의 성능을 위해 JavaScript를 압축하고 청크의 크기를 관리해야 한다. 지나친 JavaScript…

patterns-dev-kr.github.io

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

 

(Webpack 2) 최적화하기

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

perfectacle.github.io

https://velog.io/@greeeedy/%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0

 

캐싱과 gzip으로 페이지 성능 개선하기

문제 인식 공동 편집과 화상회의가 가능해 팀 단위로 알고리즘 문제 풀이가 가능한 학습 플랫폼을 프로젝트로 진행 하고 있습니다.

velog.io