회사 React 프로젝트 성능 최적화를 해보았다.
일단 처음 개발자 도구 Lighthouse를 이용해서 검사를 했다.
일단 웹 접근성은 흐린눈하기로 했다... ㅠ
웹 접근성까지 챙기기는 시간이 없다...
CRA 기반으로 만든 프로젝트라서 craco.config.js 파일에 Webpack 설정을 추가해주었다.
Webpack Bundle Analyzer를 이용해서 눈으로 트리맵을 보면서 최적화가 잘되고 있는지 확인해보겠다.
const CracoAlias = require("craco-alias");
const TerserPlugin = require("terser-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
module.exports = {
webpack: {
configure: (webpackConfig, { env }) => {
const isProduction = env === "production";
/** ✅ 1. 개발 서버(`craco start`)에서는 코드 최소화 비활성화 */
webpackConfig.optimization = {
minimize: isProduction, // 개발 서버에서는 비활성화하여 속도 개선
minimizer: isProduction
? [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // 프로덕션에서는 console.log 제거
drop_debugger: true,
},
format: {
comments: false, // 주석 제거
},
},
extractComments: false, // 별도 주석 파일 제거
}),
]
: [], // 개발 환경에서는 압축 플러그인 제거
splitChunks: isProduction
? {
chunks: "all",
minSize: 20000,
maxSize: 250000,
maxAsyncRequests: 30,
maxInitialRequests: 30,
automaticNameDelimiter: "-",
}
: false, // 개발 환경에서는 코드 스플리팅 비활성화하여 빠르게 로드
runtimeChunk: isProduction ? "single" : false,
};
/** ✅ 2. gzip 압축 (배포에서만 활성화) */
if (isProduction) {
webpackConfig.plugins.push(
new CompressionPlugin({
algorithm: "gzip",
test: /\.(js|css|html|svg)$/,
threshold: 10240, // 10KB 이상 파일 압축
minRatio: 0.8,
})
);
}
/** ✅ 3. 번들 분석 도구 추가 */
if (process.env.ANALYZE) {
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}
return webpackConfig;
},
},
};
"scripts": {
"analyze": "set ANALYZE=true && craco build"
}
npm run analyze
Webpack Bundle Analyzer를 확인해보니...
오... 최적화 해야할께 한눈에 보인다.
웹팩 코드 스플릿팅 기능을 이용해서 build해봐서 결과물도 확인해봤다.
(최적화를 진행하고 나중에는 build 결과물도 줄어드는 것을 확인해볼 수 있다.)
암호화 라이브러리(crypto-js) 최적화
일단 암호화 라이브러리인 crypto-js를 최적화 해보았다.
✅ 현재 문제점: crypto-js는 md5.js, tripledes.js 등 모든 암호화 모듈을 포함하고 있다.
👉 해결 방법: 필요한 모듈만 로드하는 방식으로 최적화했다.
import CryptoJS from "crypto-js";
const encrypted = CryptoJS.AES.encrypt("message", "secret key");
과거에는 CryptoJS를 import 해서 사용했다.
import AES from "crypto-js/aes";
import Utf8 from "crypto-js/enc-utf8";
import Pkcs7 from "crypto-js/pad-pkcs7";
import CryptoJS from "crypto-js/core"; // mode 사용을 위한 core import
const secretKey = Utf8.parse("my-secret-key");
const encrypted = AES.encrypt("message", secretKey, {
mode: CryptoJS.mode.CBC,
padding: Pkcs7,
});
crypto-js의 전체 모듈을 로드하지 않고, AES, Utf8, Pkcs7 등 필요한 것만 로드하는 방식으로 작업했다.
Webpack Bundle Analyzer를 확인해보니 최적화 된 것을 확인해 볼 수 있다.
moment.js 최적화하기
날짜 및 시간 관련 라이브러리인 moment.js를 최적화 할 것이다.
moment.js는 더 이상 추천하는 라이브러리가 아니라고 한다.
⛔️ 일단 파일 크기가 크게 젤 큰 이유다. 최근에는 훨씬 가볍고 좋은 날짜 및 시간 라이브러리가 많다.
그 중에서 나는 day.js를 쓸지 date-fns를 쓸지 고민을 했다.
비교항목 | date-fns | dayjs |
번들 크기 | 약 25KB (필요한 함수만 가져올 수 있음) | 약 2KB (Moment.js와 호환되지만 가벼움) |
Tree shaking 지원 | ✅ O (필요한 함수만 가져오기 가능) | ❌ X (전체 라이브러리 로드) |
사용법 | 함수형 API (개별 함수 호출) | OOP 방식 (.format(), .add() 등 메서드 체이닝) |
Immutable 지원 | ✅ O (날짜 변경 시 새로운 객체 반환) | ✅ O (불변 객체 방식) |
Moment.js 호환성 | ❌ X | ✅ O (거의 동일한 API) |
TypeScript 지원 | ✅ O (함수별로 정확한 타입 제공) | ✅ O (하지만 일부 동적 타입 처리 필요) |
플러그인 지원 | ❌ X (기본 기능만 제공) | ✅ O (플러그인 방식으로 확장 가능) |
moment.js와 문법이 거의 동일하다는 day.js로 결정했다.
일단 moment.js 를 많이 쓰는 것도 아니여서, 시간을 많이 들이기가 좀 그랬다.
나는 moment.js 를 대체하는 거라서 dayjs를 선택했지만 date-fns도 최근 많이 쓰는 라이브러리라고 한다.
✅ date-fns가 좋은 경우
1. Tree shaking이 중요한 프로젝트 : date-fns는 ES 모듈 방식으로, 필요한 함수만 가져올 수 있어 번들 크기를 줄일 수 있음
2. 함수형 스타일이 익숙한 경우
3. 강력한 TypeScript 지원이 필요한 경우
Tree Shaking을 지원한다는 뜻?
사용되지 않는 코드(Dead code)를 제거하는 기술로,
JavaScript 번들러(Webpack, Rollup, ESBuild 등)가 사용되지 않는 모듈을 감지하고 최종 번들에서 제외하는 최적화 기법
진짜 moment.js와 흡사해서 크게 수정할게 없었다!!
moment.js도 최적화 된 것을 눈으로 확인해 볼 수 있다.
오 build 결과물도 보면 용량이 많이 준 것을 확인해볼 수 있다!!
그럼 Lighthouse 결과는?
11점이나 올렸다!!!
이제 앞으로 젤 큰 용량을 차지하고 있는 svg 이미지 최적화를 진행해봐야겠다.
'Frontend > 성능최적화' 카테고리의 다른 글
성능최적화가 필요한 이유 (0) | 2025.02.12 |
---|