리액트 개발자로서 사용자에게 빠른 경험을 제공하는 것은 선택이 아닌 필수다. 특히 자바스크립트 번들을 Client 에서 부담해야하는 CSR인 리액트 애플리케이션에서는 더욱 그렇다. 따라서 Gzip이라는 것이 왜 중요한지, 어떻게 리액트 프로젝트에 적용하는지 알아둬야만 한다.
(👨🏻🏫 : "안녕하세요! 오늘은 리액트 개발자가 알아두면 좋을 Gzip에 대해 알아볼 거예요. 여러분의 리액트 앱을 야무지게 압축해서 번들 크기를 확 줄여주는 마법 같은 기술이랍니다! 배포 방식에 따라서는 이미 사용중에 있을 수도 있어요 ㅎㅎ 아마도 번들링에 대한 지식이 있고난 뒤에 보면 더 좋을 거예요!")
Encoding-Header
를 붙여줘야 한다.번들링과 Gzip 압축은 웹 개발에서 서로 다른 단계에서 발생하는 최적화 기술이지만, 상호 보완적인 관계를 가지고 있다.
번들링은 여러 개의 JavaScript 파일과 모듈을 하나 또는 여러 개의 최적화된 파일로 결합하는 과정이다. 이는 주로 Vite, Webpack, Rollup, Parcel과 같은 도구를 사용하여 수행된다.
번들링의 주요 목적:
Gzip은 번들링 이후 단계에서 만들어진 파일을 압축하는 알고리즘이다. 이는 서버에서 클라이언트로 전송되는 데이터의 크기를 줄이는 데 중점을 둔다.
Gzip의 주요 목적:
번들링과 Gzip은 상호 보완적인 관계를 가지고 있으며, 일반적으로 연속적인 과정으로 적용된다:
이 두 기술은 서로 다른 목적을 가지고 있지만, 함께 사용할 때 최상의 결과를 얻을 수 있다. 번들링만 하거나 Gzip만 사용하는 것보다 둘 다 사용하는 것이 훨씬 효과적이다.
(👨🏻🏫 : "번들링과 Gzip은 마치 짝꿍 같은 존재예요! 번들링으로 파일 수를 줄이고, Gzip으로 최종적으로 파일 크기를 줄이는 거죠. 둘 다 사용해야 최고의 성능을 얻을 수 있답니다! 그런데 의문이 하나 드는 게 우리는 zip 파일로 보통 압축을 하면 이를 다시 풀어야 하잖아요? 이를 다시 풀어야 하는 것도 고려해야하지 않을까요?")
"No, there is no downside on the decompression side when using the maximum compression level. In fact, there is a slight upside, in that better-compressed data takes less time to transfer over the network."
“최대 압축 수준을 사용할 때에도, 압축 해제 측면에서는 단점이 없습니다. 실제로는 약간의 이점이 있는데, 더 잘 압축된 데이터는 네트워크를 통한 전송 시간이 적게 걸립니다.”
(👨🏻🏫 : "실제로, 압축 레벨 9로 압축된 콘텐츠의 압축 해제 속도는, 압축 레벨 6보다 약 0.9% 더 빠르다는 테스트 결과도 있습니다. 이는 다소 놀라운 결과입니다. 즉 압축의 단계에 거의 차이가 없다는 소리죠. 이처럼 압축 해제에 많은 시간이 안 들어서, 압축 해제에 필요한 시간보다 네트워크 전송에서 얻는 이점이 훨씬 더 커요. 따라서 저희는 줄어드는 네트워크 비용에 대해서만 이점을 가져가고, 손해는 안 보는 셈이죠! 보통은 트레이드 오프가 있는데, 이는 그것 또한 없어요 ㅎㅎ 안 쓸 이유가 없겠죠?")
Gzip은 웹에서 파일을 압축하고 전송하기 위한 파일 형식이자 소프트웨어 애플리케이션이다. 1992년에 처음 공개되었으며, GNU 프로젝트의 일환으로 개발되었다. 리액트와 같은 현대적인 자바스크립트 프레임워크에서는 특히 중요한 역할을 한다.
Gzip은 LZ77 알고리즘과 Deflate 압축 방식을 사용한다. 이 방식은 무손실 압축(lossless compression)으로, 데이터를 압축하고 해제하는 과정에서 원본 데이터가 완벽하게 보존된다.
LZ77 알고리즘 관련 블로그 해당 알고리즘에 대해선 깊게 다루진 않겠습니다..! (진짜 잘 정리해두셨어요!)
리액트 애플리케이션에서 Gzip이 작동하는 방식을 살펴보면:
npm run build
명령으로 리액트 앱을 빌드하면 JS, CSS 파일이 생성된다실제로 리액트 앱의 번들 파일은 Gzip을 통해 원래 크기의 약 30% 수준으로 압축이 가능하다. 예를 들어, 1MB의 리액트 번들이 300KB로 줄어들 수 있다.
리액트 애플리케이션에서 Gzip은 특히 중요한 역할을 한다:
(👨🏻🏫 : "리액트 앱에서는 node_modules의 수많은 패키지들이 번들링 후에 번들에 포함되죠. 이런 코드들은 반복되는 패턴이 많아서 Gzip 압축 효율이 정말 좋답니다! 위에서 본 L277 알고리즘을 조금 보시면, 같은 문자열에 한해서 몇 개 존재하는지, 어디 존재하는지 정도로 압축한답니다! 즉 다른 라이브러리라도 그 양식에 한해서는 겹치는 부분이 많으니 효율이 더 좋아져요! ")
Gzip은 리액트 애플리케이션의 성능에 직접적이고 긍정적인 영향을 미친다. 구체적으로 살펴보자.
리액트 앱에서 가장 큰 병목 중 하나는 초기 번들 로딩 시간이다. Gzip 압축은 이 문제를 해결하는 데 큰 도움이 된다:
이러한 지표들은 Google의 Core Web Vitals의 일부로, 웹사이트의 SEO에 직접적인 영향을 미친다.
(👨🏻🏫 : "Lighthouse 점수를 높이고 싶으신가요? Gzip은 거의 모든 성능 지표를 개선해주는 필수 요소예요! 우선 Gzip을 통해 한 차례 높이고, 이후에 개별적으로 점수를 신경쓰면 좋지 않을까요?")
리액트 프로젝트에 Gzip을 적용하는 방법은 여러 가지가 있다. 보통은 빌드 도구에 따라서 방법이 달라진다. 가장 일반적인 방법들을 살펴보자.
Create React App으로 만든 프로젝트는 빌드 시 자동으로 Gzip 압축을 지원하지 않는다. 다음과 같은 방법으로 적용할 수 있다:
npm install --save-dev react-app-rewired
npm install --save-dev compression-webpack-plugin
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = function override(config, env) {
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
threshold: 10240,
minRatio: 0.8,
})
);
return config;
}
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test"ㄴ
}
CRA를 eject하지 않고 webpack 설정을 변경하는 또 다른 방법은 CRACO(@craco/craco)를 사용하는 것이다:
*# 프로젝트 루트 디렉토리에서
# 설정 파일 생성*
touch craco.config.js
*# craco와 webpack 플러그인 설치*
npm install -D @craco/craco compression-webpack-plugin
*// craco.config.js*
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
webpack: {
plugins: [
new CompressionPlugin({ algorithm: 'gzip' }),
],
},
};
그리고 마찬가지로 CLI로 편하게 쓰기 위해서 package.json의 스크립트를 수정한다:
"scripts": {
"start": "react-scripts start",
"build": "craco build",
"build-cra": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
Vite는 최신 프론트엔드 빌드 도구로, React 프로젝트에서도 널리 사용된다. Vite에서 Gzip 압축을 적용하는 방법을 알아보자. ( CRA는 이제 React 에서 당분간 업데이트 하지 않는다고 했으니, Vite를 선호하는 경향이 있다.)
Vite는 기본적으로 빌드된 파일을 압축하지 않는다. 이를 위해 vite-plugin-compression 플러그인을 사용하여 Gzip 압축을 활성화할 수 있다. 이 플러그인은 빌드 과정에서 자동으로 파일을 압축해준다.
npm install vite-plugin-compression --save-dev
vite.config.js
또는 vite.config.ts
파일에 플러그인을 추가한다:import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteCompression from 'vite-plugin-compression';
export default defineConfig({
plugins: [
react(),
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz',
}),
],
});
(👨🏻🏫 : "Vite에서는 플러그인 설정이 정말 간단해요!
vite.config.js
를 통해서 관리를 해요! 몇 줄의 코드만으로 Gzip 압축을 적용할 수 있답니다. 게다가 빌드 속도도 CRA보다 훨씬 빠르죠! CRA는 이제 당분간 업데이트를 안 한다고 리엑트 팀에서 발표했으니, Vite 로 넘어와서 이참에 Gzip도 같이 써보는 게 어떨까요? ")
vite-plugin-compression 플러그인은 다양한 옵션을 제공한다:
true
로 설정하면 압축 결과를 콘솔에 출력한다.true
로 설정하면 플러그인을 비활성화한다.1025
이다..gz
이다.true
로 설정하면 압축 후 원본 파일을 삭제한다.더 나은 압축률을 위해 Gzip과 뒤에서 다룰 내용인 Brotli(구글에서 만든 압축 방식)를 동시에 적용할 수도 있다:
import { defineConfig } from "vite";
import react from '@vitejs/plugin-react';
import compression from "vite-plugin-compression";
export default defineConfig({
plugins: [
react(),
compression({ algorithm: "gzip" }),
compression({ algorithm: "brotliCompress" })
],
});
압축 적용 전후의 파일 크기 차이를 확인해보면 그 효과를 실감할 수 있다:
적용 전:
dist/assets/index.1234.js → 450 KB (원본 크기)
적용 후:
dist/assets/index.1234.js → 120 KB (Gzip 적용 후)
dist/assets/index.1234.js → 95 KB (Brotli 적용 후)
이는 Gzip으로 약 70%, Brotli로 약 80%의 크기 감소를 의미한다. 네트워크 요청에서 전송해야 할 데이터가 크게 줄어들어 로딩 속도가 훨씬 빨라진다!
npm run build
npx serve dist
content-encoding: br
또는 content-encoding: gzip
이 표시되면 정상적으로 적용된 것이다.(👨🏻🏫 : "실제로 압축 적용 후에는 개발자 도구에서 파일 크기가 확 줄어든 것을 볼 수 있어요! 특히 큰 JS 번들의 경우 그 차이가 더 극적이랍니다! br 은 브로틀리를, gzip은 gzip 방식으로 압축된 것을 의미해요! 번들링을 끝냈으면, 해당 번들 파일을 이용해서 배포를 해야겠죠? 근데, “ 빌드 당시에 Gzip을 통해 압축하고나면 이 압축을 언젠간 풀어야 하는 거 아닌가?” 싶은 생각이 들어야 합니다! 그러나 S3에는 Gzip을 해제하는 기능이 없어요. 단순히 이를 브라우저에 제공할 뿐이죠. 그럼 어떻게 이를 해제할까요? 순서는 다음과 같답니다!")
S3 자체는 파일을 압축하거나 압축을 해제하는 기능이 없다. 대신, 다음과 같은 방식으로 Gzip 압축 파일을 처리한다:
Content-Encoding: gzip
메타데이터를 설정합니다.Content-Encoding: gzip
헤더를 보고 자동으로 압축을 해제합니다.이 방식에서 S3는 단순히 압축된 파일을 저장하고 제공하는 역할만 하며, 실제 압축 해제는 클라이언트(브라우저)에서 이루어집니다.
(👨🏻🏫 : "잠시만 그러면 굳이 내가 압축을 해서 넘기는 게 아니라, AWS 에서 이를 해주는 기능이 있으면 엄청 좋지 않을까??”라고 생각했었는데, 찾아보니까 정말 있습니다… ㅎㅎ 심지어는 제가 썼었던
CloudFront
에서 설정을 통해서 적용할 수 있더라구요!! 결국엔브라우저
에서gzip 이나 br 양식
을해제
를 하니 저희는 그 전 단계에서 AWS에게 위임할 건지, 직접 Gzip 압축을 할 건지에 대해서 정하면 되겠죠?")
AWS S3에 리액트 앱을 정적 배포할 때 Gzip을 적용하는 방법은 다음과 같다:
먼저 위에서 설명한 방법(compression-webpack-plugin, Vite 플러그인, CRACO)을 사용하여 빌드 시 .gz
파일을 생성한다.
S3는 자동으로 Gzip 압축을 지원하지 않기 때문에, 파일을 업로드할 때 Content-Encoding 헤더를 설정해야 한다. AWS CLI를 사용하는 경우:
*# 압축된 JS 파일 업로드*
aws s3 cp ./build/static/js/main.chunk.js.gz s3://your-bucket-name/static/js/main.chunk.js --content-encoding gzip --content-type application/javascript
*# 압축된 CSS 파일 업로드*
aws s3 cp ./build/static/css/main.chunk.css.gz s3://your-bucket-name/static/css/main.chunk.css --content-encoding gzip --content-type text/css
S3와 CloudFront를 함께 사용하면 더 효과적인 배포가 가능하다:
CloudFront는 자동으로 특정 파일 유형(HTML, CSS, JS 등)을 Gzip으로 압축할 수 있다. 이 경우에는 S3에 미리 압축된 파일을 업로드할 필요가 없다. 즉 앞선 빌드 단계에서 Gzip 압축할 필요 없이 그냥 올리면 된다.
//설정이 영어일 때,
CloudFront 설정 > Behaviors > Edit > Compress Objects Automatically: Yes
// 한국어일때
CloudFront 설정 > 동작 > 편집 > 자동으로 객체 압축: Yes
(default로는 Yes로 설정이 되어있습니다...!)
리액트 라이브러리를 개발하고 배포할 때도 Gzip 압축을 고려해야 한다:
라이브러리 개발 시 번들 크기를 최소화하기 위한 방법:
라이브러리 문서나 README에 Gzip 압축 후 크기 정보를 제공하는 것이 좋다:
## 번들 크기
- 원본: 120KB
- Minified: 45KB
- Gzipped: 15KB
이를 자동화하기 위해 bundlesize
또는 size-limit
와 같은 도구를 사용할 수 있다:
npm install --save-dev size-limit @size-limit/preset-small-lib
package.json에 설정:
{
"size-limit": [
{
"path": "dist/index.js",
"limit": "10 KB",
"gzip": true
}
]
}
(👨🏻🏫 : "라이브러리 개발자라면 번들 크기에 더 신경 써야 해요! 동일한 기능을 하는 라이브러리가 있다고 하더라도, 이 방식이 해당 라이브러리를 택하는 이유 중에 하나가 될 수도 있고, 그게 아니더라도, 여러분의 라이브러리가 사용자 앱의 번들 크기에 직접적인 영향을 미치니까요. Gzip 압축 후 크기를 항상 체크하는 습관을 들이세요!")
리액트 앱에 Gzip이 제대로 적용되었는지 확인하는 방법을 알아보자.
Content-Encoding
헤더가 없거나 identity
값을 가지고 있다면, 해당 리소스는 압축되지 않은 상태로 전송된 것입니다여러 온라인 도구를 사용하여 웹사이트의 Gzip 상태를 확인할 수 있다:
(👨🏻🏫 : "시간이 많다면 꼭 새 웹사이트를 배포하기 전에 이런 도구들로 체크해요. 특히 GTmetrix는 정말 좋은 도구예요. Gzip뿐만 아니라 다양한 성능 지표를 한눈에 볼 수 있거든요! 허허")
리액트 앱의 Gzip 압축 효과를 포함한 전체 성능을 테스트할 수 있는 도구들:
리액트 앱의 번들 크기와 Gzip 압축 후 크기를 분석하는 도구:
npm install --save-dev webpack-bundle-analyzer
CRA에서 사용하려면 react-app-rewired와 함께 설정:
*// config-overrides.js*
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = function override(config, env) {
if (process.env.ANALYZE) {
config.plugins.push(
new BundleAnalyzerPlugin()
);
}
return config;
}
그리고 package.json에 스크립트 추가:
"scripts": {
"analyze": "ANALYZE=true react-app-rewired build"
}
이 도구들을 사용하면 리액트 앱의 어떤 부분이 가장 큰 공간을 차지하는지, Gzip 압축 후 얼마나 줄어드는지 확인할 수 있다.
(👨🏻🏫 : "webpack-bundle-analyzer는 리액트 앱을 최적화할 때 정말 유용한 도구예요! 어떤 라이브러리가 번들 크기를 많이 차지하는지 한눈에 볼 수 있고, Gzip 압축 후 크기도 확인할 수 있어요. 이를 통해 불필요한 의존성을 제거하거나 대체할 수 있죠!")
브로틀리(Brotli)는 Google이 개발한 새로운 압축 알고리즘으로, Gzip보다 더 나은 압축률을 제공한다. 주요 특징은 다음과 같다:
브로틀리와 Gzip을 비교하면:
특성 | Gzip | 브로틀리 |
---|---|---|
압축률 | 좋음 | 매우 좋음 |
압축 속도 | 빠름 | 대체로 빠르되, 높은 압축 수준에서는 낮음 |
압축 해제 속도 | 빠름 | 빠름 |
브라우저 지원 | 거의 모든 브라우저 | 대부분의 최신 브라우저 |
서버 지원 | 광범위함 | 증가 중 |
브로틀리는 Gzip을 완전히 대체하기보다는 보완하는 역할을 한다. 최신 브라우저를 사용하는 사용자에게는 브로틀리를, 오래된 브라우저를 사용하는 사용자에게는 Gzip을 제공하는 방식으로 함께 사용할 수 있다.
(👨🏻🏫 : "브로틀리는 정말 좋은 기술이에요! 하지만 아직 Gzip만큼 널리 지원되지는 않아요. 가능하다면 두 가지를 모두 제공하는 것이 가장 좋은 전략이랍니다. 브라우저가 지원하면 브로틀리를, 아니면 Gzip을 사용하도록요!")
브로틀리(Brotli)는 Google이 개발한 새로운 압축 알고리즘으로, Gzip보다 더 나은 압축률을 제공한다. 리액트 앱에 적용했을 때의 장점:
리액트 앱에 브로틀리 적용하기:
*// config-overrides.js*
const CompressionPlugin = require('compression-webpack-plugin');
const zlib = require('zlib');
module.exports = function override(config, env) {
config.plugins.push(
new CompressionPlugin({
filename: '[path].br[query]',
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/,
compressionOptions: {
level: 11,
},
threshold: 10240,
minRatio: 0.8,
})
);
return config;
}
리액트 생태계와 웹 기술은 계속 발전하고 있으며, 이에 따라 Gzip의 역할도 변화하고 있다:
(👨🏻🏫 : "리액트 생태계는 계속 발전하고 있어요! 서버 컴포넌트, Suspense for Data Fetching 등의 새로운 기능들이 번들 크기를 줄이는 데 도움을 주고 있죠. 하지만 Gzip과 같은 압축 기술은 결국엔 파일 크기를 줄여야 하기에, 여전히 중요한 역할을 할 거예요. 이는 리액트 앱의 성능 최적화는 사용자 경험을 향상시키는 핵심 요소이며, Gzip은 이를 위한 필수 도구입니다!! 번들 크기 감소, 로딩 시간 단축, 대역폭 절감 등 다양한 이점을 제공하는 Gzip을 리액트 프로젝트에 적극 활용해보는 게 어떨까요?")
🙇🏻 글 내에 틀린 점, 오탈자, 비판, 공감 등 모두 적어주셔도 됩니다. 감사합니다..! 🙇🏻
단순히 자바스크립트 번들 파일을 줄여야 한다고만 아는 것을 넘어서서, 구체적으로 어떻게 줄일 수 있는지 해결책을 제공해주신 포스팅 감사합니다!
저도 직접 적용해봐야겠네요 (˘︶˘).:*