NextJS Babel 에서 SWC 전환 하는 과정에서 겪은 에러

IT공부중·2023년 2월 26일
2

Next

목록 보기
10/12

NextJS 12 버전부터 SWC를 Next.js Compiler 로 소개한다.
SWC는 Rust 기반의 컴파일러로 싱글 코어에서 babel 보다 20배, 4 코어에서 babel 보다 70배 빠르다고 소개하고 있다.

회사에서 작업하는 프로젝트를 9버전에서 12버전으로 직접 올렸는데, SWC를 바로 적용할 수 없었다. 그 이유는 twin.macro 를 사용하고 있기 때문이었다. twin.macro는 emotion + tailwind 라고 생각하면 된다.
이게 swc를 지원하지 않아서 바로 적용하지 못 했었다. 여러 곳을 찾아봤을 때 stailwc 라이브러리를 대신 쓰라는 글이 많았다. 하지만 아직 버전도 낮고, 사용법도 미묘하게 나마 다를 것이기 때문에 프로젝트 전체를 수정해야하는 공수가 들 것이기 때문에 바꾸고 싶지 않았다. 또한, 잘 바꾸고 나서라도 다르게 동작하는 부분이 있을 수 있기에 일단 보류했다.

그러던 중 작업을 빨리 끝내고 관련 내용에 대해 찾아보다가 babel 관련 설정을 조금 추가해서 twin.macro를 사용할 수 있는 것 같아 적용했다.
https://www.inflearn.com/blogs/2858
https://github.com/ben-rogerson/twin.examples/tree/master/next-emotion-typescript
참고 한 글을 위와 같으며, withTwin.js 를 만들어서 next.config.js 에 설정해주면된다. 간단히 요야갛면 webpack 설정을 추가하는 것인데, twin이 쓰인 폴더들을 지정하고, tsx나 ts 파일들에 babel을 적용하는 것이었다. 이러면 결국 babel을 쓰는 것이라 엄청 맘에 드는 것은 아니었다. 그리고 과연 빌드속도가 빨라질까? 라는 의구심이 들기도 했다. 하지만 빌드 시간을 측정해본 결과 꽤 빨라진 것을 알 수 있었다.
우리 프로젝트 기준으로 기존 설정인 babel로만 했을 때는 첫 빌드시 140초가 걸렸는데, SWC를 적용하고 나서는 95초로 약 32%가 감소했다.
또한 swc minfy 차이 때문인지 빌드된 파일 용량이 약 8MB 에서 약 7MB로 줄었다. (서버쪽 빌드 용량이 커짐) 그래서 그런지 light house 성능도 더 높고 안정적으로 나오는 것을 확인할 수 있었다. (약 6프로 상승 -> 밑의 next-translate 까지 다 수정하고 난 후 결과.)


SWC를 도입 하는 중에 또 에러가 많이 나서 나를 괴롭힌 라이브러리가 있는데 i18n 관련해서 사용하고 있는 next-translate 이다.
기존과 똑같은 방식으로 /i18n.js 에서 dynamic imports 를 사용하여
build를 하니 다음과 같은 에러가 나왔다.
Critical dependency: the request of a dependency is an expression 이것은 next-translateissue에서도 찾을 수 있었고 사람들이 시도한 다양한 방법들이 나와있었다.
처음에는

loadLocaleFrom: (locale, namespace) =>
    import(`locales/${locale}/${namespace}`).then((m) => m.default),

로 돼있던 코드를

  loadLocaleFrom: (locale, namespace) =>
    require(`locales/${locale}/${namespace}`),

로 바꾸라는 방법을 보고 진행시켜보았다. 이렇게 하니 잘 되는 것처럼 보였지만, 사실 함정이 숨어있었다. 기존에는 각각이 코드 스플릿이 되어 현재 적용된 언어에 대한 js파일만 불러오도록 되었는데, require로 바꾸니 모두가 _app.js 파일에 합쳐진 상태로 빌드 되어있는 것을 확인 할 수 있었고, first load js의 크기가 커져서 오히려 swc를 적용을 했음에도 오히려 light-house 점수가 나빠졌다. (swc 적용으로 빌드 속도가 빨라지는 것을 기대했기에 성능은 최소한 같기를 원했다. 높으면 더 좋고) 그래서 이 방법은 아니라고 판단하고 다른 방법을 찾아보았다. 지금 당장 잘 되는 방법은 이 방법이었다. 이것을 적용하니 기존과 똑같이 동작하는 것을 확인할 수 있었고, 성능이 기존보다 6프로 정도 빨라졌다.

이거를 적용하기 전에 next-translate의 메인테이너 분이 다른 방법을 올려놓으신 것도 써봤는데 웹팩 splitChunks 설정을 추가하여, 각각의 언어가 chunk 단위로 나뉘어지게 하는 것이었다. 하지만 내가 적용해보니 chunk 단위로 나뉘기는 하지만 제일 처음 로드시에 모든 언어 파일을 다 불러와 전혀 효과가 없는 것으로 파악됐다. 그래서 잘 안되는 것 같다고 댓글을 달았더니 고맙다고 해주고 다른 방법은 없는 것 같냐고 물어보는 재밌는 경험을 했다.
메인테이너 분은 i18n.js 에서 dynamic import를 사용하여 기존처럼 사용하고 싶어하시는 것 같았고, 지금으로써는 swc 가 고쳐지지 않으면 어려울 것이라 생각해서 NodeJS 단톡방에서 swc 메인테이너 분에게 여쭤보았다. 처음에는 swc는 dynamic import를 지원하기 때문에 swc의 문제가 아니라고 하셨지만 뭔가 next에서 swc 를 사용하는데에 문제가 있었던 모양이다. pr1, pr2 를 통해 수정을 해주셨고, v13.2.0 에 반영된 것을 볼 수 있었다. 내가 직접적으로 수정을 한 것은 아니지만, 메인테이너 님이 해당 이슈가 있는줄 놓치고 있었기 때문에 알려주는 다리 역할을 한 것만으로 꽤 재밌고 값진 경험이었다.

아직 Next12를 쓰고 있지만 조금 더 다듬은 다음에 얼른 13.2 로 업데이트 하는 여정을 가져봐야겠다.

결론

원래 SWC를 적용하는 것은 .babelrc 만 지우면 되고, next.config.js 에서 swcMinify 옵션을 true로 주면 끝나는 것인데 twin.macronext-translate 라이브러리에서 이슈가 발생했다. 이런저런 이슈를 찾아보면서 어떻게든 수정에 성공했다.
적용후 결과로는 빌드속도는 약 32% 상승, 클라이언트 측 번들 사이즈 8MB -> 7MB로 감소
light house Performance 점수 약 6% 상승의 효과를 얻을 수 있었다.

profile
4년차 프론트엔드 개발자 문건우입니다.

0개의 댓글