https://cashdoc.yeogiya.io 해당 사이트를 Next.js로 마이그레이션하는 작업 중 겪었던 문제가 있는데, SSR이 적용된 페이지를 웹뷰에 올리면 초기로딩이 너무 느리다는 것이었다... 어느 요청에서 pending이 되나 봤는데 그냥 초기 페이지 로딩자체가 느렸다.
결론 부터 말하면 원인은 Mui의 named import로인한 번들 사이즈였다. (원인 내가 찾음ㅋ)
개발환경 뿐만 아니라 production환경에서도 발생했던 이슈이므로 기록해 둔다!
Mui에서 Button을 import한다고 가정할 때, 뭐가 더 빠를까?
// Default import
import Button from '@mui/material/Button';
// Named import
import { Button } from '@mui/material';
정답은 1번이다. 둘 다 Button 하나만 가져오니까 똑같지 않나?? 라는 생각은 오산이다.
(경기도 오산 아님ㅋ)
import { AbcRounded } from '@mui/icons-material' 처럼 가져오게되면, @mui/icons-material에서 내보내고있는 모든 모듈이 번들 사이즈에 포함된다.
실제 번들사이즈 크기 차이는 이렇다.
↓ Named import
하위 Icon들까지 다 가져온 걸 볼 수 있다. 반면,
↓ Default import
확실히 줄어들었다.
🤔 왜 트리쉐이킹이 잘 되지 않았을까? issue를 보면 코드수준이 아닌, 모듈 수준에서 트리쉐이킹을 한다고 한다. 그래서 내가 추측한 바로는, typescript는 tree shaking할 때 모듈 확인 중 index.ts를 발견하면 그곳에 정의된 모든 모듈을 가져오려 하는데, 그래서 그런 것 같다. 개선 해야할듯하다... 개선티비..
그렇다고 mui에서 필요한 모듈을 일일이 named import하긴 싫었다... 그래서 찾은 해결 방법은 @mui/material과 @mui/icons-material을 modularize import하는 것!
import 경로가 @mui/material인 것을 @mui/material/~~에서 default import 한 것처럼 트랜스파일 해주는 방식으로 동작하는 것 같다.
const nextConfig = {
...,
experimental: {
modularizeImports: {
"@mui/material": {
transform: "@mui/material/{{member}}",
},
"@mui/icons-material": {
transform: "@mui/icons-material/{{member}}",
},
},
},
};
GPT(님)도 맞다고 한다
https://mui.com/material-ui/guides/minimizing-bundle-size/
https://github.com/mui/material-ui/issues/35840
https://github.com/vercel/next.js/discussions/37614