기존에 웹서버를 직접 구현해봤었는데, 이제는 그 원리를 알았으니, 이미 만들어진 좋은 도구를 사용해야할 때라고 생각해서 번들러를 도입하고자 했다.
그러던 중, 어떻게 번들링이 일어나는지 의문이 생겼고, 번들링 과정에 대해 찾아보게됐다.
번들러를 왜쓰고, 기능은 무엇이 있으며, 어떻게 번들링이 일어나는지 알아보자.
번들러 왜쓰는데
React, Angular, Vue 등 프레임워크가 등장하고, 점점 js파일이 많아지면서 하나의 페이지에서 사용되는 js파일들이 엄청나게 많아지기 시작했다.이러면 한 페이지가 로드될때 모든 js파일을 네트워크를 통해 받아와야 한다.
번들링 없이 ESM만을 사용해 만든 프로젝트의 경우, 이런식으로 모든 js파일을 http요청을 통해 받아오는 것을 확인할 수 있다.
이 모든 파일을 묶어서 하나의 파일로 만드는걸 번들링이라고 한다.
이게 번들러를 사용하는 가장 큰 이유이며, 가장 큰 기능일 것이다.
번들러의 여러 기능들
1. Tree shaking
번들링시에 필요없는 코드를 제거하고, 번들 파일의 크기, 번들링 시간을 줄여준다.
2, HMR(Hot Module Replacement)
코드가 변경되면 감지하고, 최신코드를 반영해서 자동으로 모듈을 교체한다.
새로고침 없이도 반영된 결과를 확인할 수 있다.
3. Code splitting
하나의 js로 바꾸면, 번들 크기가 매우 커질 수 있게 된다. 이 번들을 받아서 파싱하고 컴파일 하려면 로딩시간이 더 길어질 수도 있다. 이를 해결하기 위해서 코드 스플리팅(하나의 번들을 여러개로 쪼개서 필요한 경로에만 제공)을 통해 최적화를 진행한다.
4. 트랜스파일링
번들러에 Babel을 통합해서 최신 ES문법을 이전 ES문법으로 변환해줄 수 있게된다.
번들링 과정
이 번들링 과정은 정확한 번들러의 원리라기보다는 해당링크와 해당링크, 그리고 해당링크에서 번들러를 만드는 과정을 가져온 것이다.
번들링은 두 단계를 거쳐서 완료된다.
1. 의존성 그래프 생성
2. 패킹
의존성 그래프 그리기
번들링이 시작되면 번들러는 모든 파일의 의존성을 그리기 시작한다.
이를 위해서는 진입점이 필요한데 이게 바로 entry다.
의존성 표현하기
entry파일부터 들어가면서 import, require등 다른 모듈을 필요로 하는 의존성 구문을 찾고, 다시 그 파일을 찾아서 의존성 구문을 찾으면서 재귀적으로 각 파일의 정보를 얻는다.
그럼 이걸 어떻게 데이터로 변경할까? 바로 객체다.
파일이름, 식별자, 경로, 파일의 코드, 의존성 정보를 모아 객체로 만든다.
그럼 한 모듈에서 어떻게 다른 모듈을 참조하는지는 알 수 있게 되었다.
올바른 의존성 찾아주기
우리는 보통 import를 상대경로로 하게된다. 혹은 절대경로로 alias를 부여해서 찾기도 한다.
혹은, 모듈을 npm으로 설치해 쓰는 경우, 그냥 이름으로 사용하기도 한다.
어떻게 이걸 매치시켜 주는걸까?
모듈 맵을 사용해서 처리한다.
모듈맵은 앞선 단계에서 의존성을 표현한 객체의 id값을 경로에 매치시켜서 해당 모듈을 잘 찾아갈 수 있게 한다.
그럼 entry에서 만든 객체를 통해서 모든 모듈에 접근할 수 있게된다. 일종의 그래프가 되는 것이다.
패킹
이제 만든 그래프를 의존성을 사용할 수 있게 묶어주면된다.
기존의 의존성을 객체에서 찾도록 처리한다.
요런식으로 말이다.
이런식으로 작성하면 require함수를 그대로 사용하므로,기존 CJS형태를 그대로 쓸 수 있다.(ESM을 쓰는경우는 따로 CJS문법으로 변환해줄 필요가 있다.)
모듈 객체를 만들어두고, 각 모듈별 id를 가진 배열을 만들어둔다.
첫 인덱스에는 function(require,module,exports)가 오고, 내용으로 기존의 코드 내용이 오게된다.
두번째 인덱스에는 그 파일이 의존하고 있는 다른 파일을 갖고있게 된다.
그리고 이 modules의 index를 받아 실행시키는 함수를 구현한다.
이러면 entry파일을 실행시키기만 하면 executeModule이 재귀적으로 호출되면서 모든 의존성 파일이 modules객체에서 찾아지고, 수행된다.
결국, 번들링도 객체를 활용해서 구현된 것이다!
참고한 글
- Let’s learn how module bundlers work and then write one ourselves - https://www.freecodecamp.org/news/lets-learn-how-module-bundlers-work-and-then-write-one-ourselves-b2e3fe6c88ae/
- [Bundler] JavaScript 번들러 그리고 Webpack , Parcel , Rollup , Vite... - https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-1
- Webpack 같은 모듈 번들러를 만들어 보자 - https://engineering.linecorp.com/ko/blog/write-you-a-webpack-for-great-good