foo, bar 변수를 선언하고 setTimeout으로 1초뒤에 변수들을 다른 값으로 대입한다면 setTimeout에 있은 console.log에서도 동일하게 반영이 될까요?
위 코드를 webpack으로 빌드하고 실행해보면 다음과 같은 결과가 나옵니다.
같은 코드이지만 출력된 결과물은 다른데요
어떻게 이런 출력이 나왔는지 webpack에서 빌드된 코드를 살펴보겠습니다.
Commonjs 방식에서는 modules 객체를 파라미터로 넣어서 modules.exports 객체에 직접 할당하는 방식입니다. 그래서 foo,bar의 값들이 복사됩니다.
Esm에서는 exports 객체에 해당 변수를 반환하는 함수를 만듭니다.
그래서 setTimeout으로 변수값들을 바꾸면 Commonjs에서는 반영안되지만 Esm에서는 제대로 되는 이유입니다.
전체 코드는 맨 아래에 있습니다.
Commonjs, Esm 순환 참조 차이
A, B모듈이 서로를 참조하는 것을 순환 참조라고 하는데 commonjs에서는 빈객체를 반환하지만 esm에서는 ReferenceError를 출력합니다.
webpack에서는 이러한 순환참조를 어떤식으로 변환을 하고 왜 다른지를 알아보겠습니다.
a,b 파일 서로 참조하는 코드입니다. 이걸 실행하면 다음과 같은 결과를 나타냅니다.
이러한 결과를 보여주는 이유는 모듈이 캐싱이 된다는 점,
모듈을 어떻게 정의하냐에서 차이를 보여줍니다.
webpack에서는 모듈 파일을 읽을때 캐시(__webpack_module_cache__)에서 먼저 찾습니다.
없으면 exports 객체가 담긴 객체로 초기화하고 캐시에도 넣습니다.
그리고 해당 모듈 파일을 실행합니다
esm 도 동일하게 캐싱된 객체를 가지고 오지만 모듈정의 방식이 다르기 때문에 Reference 에러가 나옵니다.
전체 코드는 맨 아래에 있습니다.