ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Webpack] exports is not defined 에러 해결방법 정리 (JS)
    프론트엔드 2022. 3. 25. 23:56

    리액트 + JS 프로젝트에서 웹팩을 번들러로, 바벨을 트랜스파일러로 사용하는데
    exports is not defined 에러가 발생했다.

    ESModule 시스템을 지원하지 않는 브라우저를 위해 Babel이 
    import/export문을 require/exports문으로 변환하게 되는데,
    변환 후에 exports문을 인식하지 못해서(CommonJS 문법을 해석하지 못해서) 발생한 에러인 것 같다.



    내가 해결한 방법

    나는 ESModule 시스템을 지원하는 브라우저만 지원하도록 설정해서 해결했다.
    (IE 제외하고는 대부분 지원되기 때문)

    webpack.config.js

    loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-react',
                [
                  '@babel/preset-env',
                  {
                    targets: {
                      esmodules: true, // 추가한 부분
                    },
                  },
                ],

    만약 ESModule을 지원하지 않는 브라우저까지 지원하고 싶다면
    commonjs 모듈로의 변환을 지원해주는 babel 플러그인을 설치하면 해결될 수 있다.
    (npm install --D @babel/plugin-transform-modules-commonjs
    또는 yarn add -D @babel/plugin-transform-modules-commonjs)

     

    다른 해결방법

    위 방법만으로 해결이 되지 않는다면, 다음 방법들을 시도해보는 것을 추천!
    직접 시도해 본 방법은 아니고 검색하면서 찾은 방법들을 정리해뒀다.

    1. package.json에 "type": "module" 추가하기
      : 프로젝트에서 CommonJS(exports)가 아닌 ES모듈 시스템을 사용한다고 명시하는 방법.

    2. 자바스크립트 코드 상단에 var exports = {}; 추가하기
      : 약간 트릭이긴 하지만 이 방법으로 해결했다는 글이 많이 보여서 추가

    3. 타입스크립트를 사용하는 경우 tsconfig에 "module": "commonjs"가 설정되어 있는지 확인하고 지운다.
      : commonjs로의 컴파일이 지원되지 않는 상태에서 module 방식이 commonjs로 설정되어 있어 발생하는 에러일 수 있기 때문이다.
      이런 경우 "module": "commonjs"를 지우면 해결될 수 있다.

      단, tsconfig에서 es6 이전 버전까지 지원하는 것으로 설정되어 있다면, "module": "commonjs"를 지워도
      자동으로 모듈 시스템이 commonjs로 설정된다. 이런 경우 es6 이전 버전을 지원하지 않도록
      설정을 수정해야 한다.

    참고) https://stackoverflow.com/questions/43042889/typescript-referenceerror-exports-is-not-defined


    (여기부터는 에러를 해결하면서 공부한 내용들)

     

    Babel 설정

    targets 옵션 :

    프로젝트가 지원하는 환경(주로 브라우저)을 설정하는 옵션이다.

    브라우저리스트를 나타내는 쿼리를 지정할 수도 있고 ("targets": "> 0.25%, not dead" (사용자가 0.25% 이상인 모든 브라우저 지원)),
    다음과 같이 지원할 브라우저 버전을 직접 지정할 수도 있다.
    "targets": { "chrome": "58", "ie": "11" }

    타겟이 지정되어 있지 않으면, Babel에서 지원 가능한 가장 오래된 브라우저까지 지원한다.

    targets.esmoules 옵션 :
    true로 설정할 경우, esmoule 시스템을 지원하는 브라우저만 지원한다.
    (package.jsontype: module 도 같이 설정해주면 번들 사이즈를 좀 더 줄일 수 있다고 한다. )

    참고) https://babeljs.io/docs/en/babel-preset-env#targets

     

    CommonJS(require, exports) VS ESModule(import, export) 시스템

    JS에서 모듈을 불러오고 내보낼 때 사용하는 키워드는
    require, exports와 import, export가 있다.

    CommonJS는 require, exports 키워드를 사용하며, JS 모듈 시스템이라고도 한다.
    ESModule 시스템은 import, export 키워드를 사용한다.
    ESModule 시스템은 ES6부터 추가되었기 때문에 ES6가 지원되지 않는 환경에서는 require/exports 키워드를 사용하거나
    바벨과 같은 트랜스파일러를 사용해야 한다.

    Node.js의 경우 기본적으로 CommonJS를 채택하고 있기 때문에
    es 모듈 시스템을 사용하려면 Babel을 사용해야 했다.
    그래서 Node.js 환경을 대상으로 작성된 코드는 대부분 require/exports 문을 사용해서 작성된 코드가 많다.
    하지만 Node.js도 13.2 버전부터 es모듈을 정식으로 지원하기 시작했다.

    Node.js에서 es모듈을 사용하려면
    package.json에 { "type": "module" }을 추가해주면 된다.

    구식 브라우저를 반드시 지원해야 하는 경우가 아니라면 ESModule 시스템을 사용하는 것을 권장한다.

    import/export 키워드가 가독성이 더 좋고,
    비동기 방식으로 작동하고 실제로 쓰이는 부분만 불러와, 성능과 메모리 측면에서 유리하기 때문이다.

    댓글

Designed by Tistory.