티스토리 뷰

목차

1. ES11문법을 위한 babel의 최신화(Hi, Unexpected token, bye!)
2. polyfills는 Default를 가지고있다.
3. core-js 3 라고 왠만하면 명시하자.

...그리고 -1. 별첨. es6? es7? ㄴㄴ es!


1. ES11문법을 위한 babel의 최신화(Hi, Unexpected token, bye!)

문제점

현재 프로젝트에서 사용하고 있는 컴포넌트의, 새버전이 릴리즈되어 현장에 적용하려하였는데...
아래와 같은 에러 로그를 만나게 되었다.
Module parse failed: Unexpected token

 

에러가 발생한 코드

Unexpected token 이라는 에러는 보통, Javascript 문법을 잘 못 썼거나 컴파일 단계에서 babel이 이해하지 못 하는 구분자(token)이 있을 때 발생하는 에러다. 그리고 이번 트러블 슈팅의 원인은 후자였다. transpiler인 babel이 ?. 라는 코드를 해석하지 못 하는 에러.
(혹시나해서 적어둡니다만, 위의 에러로그에 예시로 활용된 코드는 실제 에러로그 발생 코드를 참고하여 제가 임의로 작성한 코드입니다. 원본 코드를 그대로 노출하는 건, 사내 보안위규 사항이라서요)

 

해결법

?. 라는 코드는 Javascript의 optional chaining 연산자이다.
ES11에 추가된 연산자로써 체이닝된 객체의 속성값을 읽어서 유효한지 확인하며, 유효하다면 해당값을 리턴하고 유효하지 않다면 undefined를 리턴하는 연산자다. ES11에 추가된 연산자이니만큼, 그보다 이전에 정의된 babel의 preset을 사용중이라면 babel 입장에서는 해당 연산자가 무슨 의미인지 알 수가 없다. 따라서, babel의 preset을 재설정해주어야 하는데, 이 방법에도 2가지가 있다.

우선, 가장 직접적인 해결법은 @babel/plugin-proposal-optional-chaining을 preset으로 사용하는 방법인데, 사실 해당 링크를 들어가보면 아래와 같은 인용구가 적혀있다.

NOTE: This plugin is included in @babel/preset-env, in ES2020


즉, @babel/preset-env를 최신버전으로 적용하면 결국 optional chaining뿐만 아니라 여타 ES11 관련 문법도 모두 transpile이 가능해지는 것이다. 그리고, 나는 현재 Vue-cli로 생성한 프로젝트를 활용하고 있기 때문에 babel의 preset 설정(babel.config.js)을 아래와 같이 정의하고 있는데,

module.exports = { 
  presets: [ 
    [ 
      '@vue/app', 
      { 
        modules: 'commonjs', 
        useBuiltIns: "usage", 
        polyfills: [ 
          'es6.promise' 
        ] 
      } 
    ] 
  ] 
}

여기서 사용되는 @vue/app 이라는 preset의 지원범위는 @vue/babel-preset-app 에서 확인할 수 있으며, 위에서 언급했던 @babel/preset-env가 이 안에 포함되어있다. 즉, babel의 최신화를 위한 최종 목표는 @vue/babel-preset-app을 최신화하면 해결이 되는 것이다.

 

바로 요놈이 최신화되어야하는데...

그럼 어떻게 @vue/babel-preset-app을 최신화하느냐.
npm에 익숙한 사람이라면, 당연하게도 패키지를 관리하는 package.json을 떠올렸을 텐데, 나처럼 Vue-cli를 활용해서 프로젝트를 구성한 사람이라면 package.json에는 @vue/babel-preset-app에 대한 버전정보가 명시되어있지않을 것이다. 왜냐면 @vue/babel-preset-app 은 @vue/cli-plugin-babel 패키지의 의존모듈(dependency)이기 때문이다.

아래 스크린샷과 같이 node_modules 내의 @vue/cli-plugin-babel의 package.json을 열어보면

 

node_modules/@vue/cli-plugin-babel/package.json

"dependencies" 항목에 @vue/babel-preset-app이 있는 것을 확인 할 수 있다.
그래서 우리는, 최종적으로 @vue/cli-plugin-babel을 최신화해주면

npm install @vue/cli-plugin-babel --save-dev

Unexpected token과 같은 에러는 사라지는 것을 볼 수 있다.


2. polyfills는 Default를 가지고있다.

문제점

Syntax Error: Error: [BABEL] ~~파일경로 중략~~~ : Cannot find polyfill es6.promise, please refer to 'core-js-compat' for a complete list of available modules


그리고 나는 위와같은 새로운 에러를 맞이하게 된다.

 

해결법

위 에러는 생각보다 쉽게 원인을 파악할 수 있었다.
babel의 설정을 담당하는 babel.config.js 파일을 보면 아래와 같이 정의해서 활용중이라고 했었다.

module.exports = { 
  presets: [ 
    [ 
      '@vue/app', 
      { 
        modules: 'commonjs', 
        useBuiltIns: "usage", 
        polyfills: [ 
          'es6.promise' // 여기가 문제였다. 
        ] 
      } 
    ] 
  ] 
}

presets 설정의 polyfills는, transpile시의 polyfill 대상을 정의한 것이다.
ES6에 추가된 Promise에 대해서 polyfill 하도록 한 것인데, babel 최신화를 위해서 참고했던 @vue/babel-preset-app 의 설명에 보면 하기와 같은 문구가 작성되어있다.

 

여기서 우리가 주목해야 할 포인트는 2가지다.
하나는, es라는 키워드 뒤에 6 혹은 7과 같은 숫자가 없다는 것.
그리고 하나는, Default에 es.promise가 있다는 것.

polyfills 항목이 이미 기본값(Default)으로 Promise 에 대한 설정값을 가지고 있기 때문에
나는 babel.config.js에서 해당 항목을 지워줌으로써 쉽게 해결되었다.

(혹시 지우지 않고 명시적으로 남겨두고 싶다면 es.promise 로 값을 변경해주면 된다)

만약, 위 기본 항목들외에 polyfills 대상으로 등록해야하는 것들이 있다면
core-js의 Github에서 관련 모듈을 검색해서 이름에 맞게 등록해주면 된다.

※ es 키워드 뒤에 6 혹은 7이 왜 없어졌는지에 대해서는 아래 별첨 -1에서 설명한다.


3. core-js 3 라고 왠만하면 명시하자.

문제점

2번사항까지 해결하고 node 서버를 재기동했지만...또 다시 어마어마한 에러로그를 마주하게 됐다.

* core-js/modules/es.array-buffer.constructor.js ./node_modules~~~~~~~~~~~~
* core-js/modules/es.array-buffer.slice.js in ./node_modules~~~~~~~~~~~~
* core-js/modules/es.array.concat.js in ./node_modules/@vue/cli-plugin-babel~~~~~~~
* core-js/modules/es.array.fill.js in ./node_modules ~~~~~~~~~

/* 중략 */

To install them, you can run: npm install --save core-js/modules/es.array-buffer.constructor.js core-js/modules/es.array-buffer.slice.js ~~~~~~~~~~~~~~~~~~~~~~


위 에러로그 같은 경우에는 우리가 npm 패키지를 활용하다보면 흔하게 만날 수 있는 건데,
활용하려는 node_modules를 찾지 못 하겠으니 npm install을 통해서 설치를 해라. 라는 내용이다.

그렇기때문에 우리는 우선적으로 node_modules에 해당 모듈이 정말 없는지 확인부터 해야한다.
그리고 당연하게도 해당 모듈들이 없을 것이다(없으니까 에러가 나오겠지)

 

해결법

사실, 이 에러는 1번에서 했던 @vue/cli-plugin-babel 설치가 순조롭게 잘 진행되었다면 발생하지않는 이슈다. 왜냐면, 이 에러로그의 해결법이 바로 core-js 3.x 버전의 설치이기 때문이다.

@vue/cli-plugin-babel을 최신버전(2021.09.15기준으로 4.5.13 버전)으로 설치하였다면 node_modules 디렉토리 안의 @vue/babel-preset-app의 package.json을 열어보면 dependencies항목에 core-js의 버전이 3.6대로 정의되어 있을 것이다. 즉, 우리가 1번에서 babel을 최신화하기 위해 @vue/cli-plugin-babel 버전을 최신으로 재정의했고, 그에따라 @vue/babel-preset-app의 버전도 최신화가 되었으니 해당 패키지에서는 core-js의 버전이 3.x가 되어야 정상적으로 동작하게 되는 것이다.

일반적인 경우라면 @vue/cli-plugin-babel을 npm install 할 때
@vue/babel-preset-app의 의존성에 따라, core-js도 3.6 이상의 버전으로 설치가 되었어야했지만...

 

현 프로젝트의 package.json에는 기존에 사용하던 core-js 버전이 2.6.5로 명시 되어있었고,
그로인해 @vue/cli-plugin-babel이 최신 버전으로 설치되면서도 core-js 버전은 그대로였던 것이다.

그래서 아래 2개의 명령어를 통해 core-js 버전을 삭제(uninstall)하고 재설치(install)해주면 해결이 된다.

npm uninstall core-js 
npm install core-js

혹은, package.json에 정의된 "core-js": "^2.6.5" 와 같은 명시사항을 지우고 @vue/cli-plugin-babel을 install 해도 된다.


-1. 별첨. es6? es7? ㄴㄴ es!

core-js 측에서 늘 고심했던 이슈 몇가지를 3.x 버전으로 올리면서 정리하려고 노력했는데, 걔중에는 core-js 가 2MB에 육박할 정도로 너무 용량이 크다는 것, 그리고 동일한 목적을 가진 파일들이 중복되어 패키징되고 있다는 이슈가 있었다고한다. 이러한 부분을 좀 더 효율적으로 정리하기위해 기존에 es6 혹은 es7 이라는 prefix를 제거하고 es로 통일하였으며 그에따라 실제로 node_modules 디렉토리에 설치되는 디렉토리 구조나 내용도 아래와 같이 매우 깔끔해졌음을 알 수 있다.

 

core-js 2.x와 core-js 3.x의 node_modules 차이


좀 더 상세히 알고 싶은 분은 원문 링크를 따라 가보시면 될 것 같다.


참고사이트
1. vue.js, Vue-cli의 package 중 @vue/babel-preset-app Github
2. vue-cli core-js 3.x 으로 변경하면서..
3. core-js Github
4. MDN Optional chaining
5. What's new in ECMAScript 2020 (ES11)
6. babeljs.io

댓글
댓글쓰기 폼