개요
Node.js 환경에서 바닐라 자바스크립트를 이용해 내가 직접 만든 js 모듈을 불러오는 과정에서 다음과 같은 에러가 발생했다.
SyntaxError: Unexpected token 'export'
당시에 내가 작성한 코드는 다음과 같다.
// 모듈 파일
export const 모듈이름 = [ ... ]
// app.js
import 모듈이름 from "./파일이름";
에러 메시지에서 export
가 예기치 않은 토큰이라는데, 이게 대체 무슨 말일까?
우선 해당 오류가 왜 생기는지부터 알아보자.
SyntaxError: Unexpected token 'export' 발생 이유
해당 오류는 Node.js 환경에서 ES6 모듈 구문을 사용하려 할 때 발생한다.
Node.js는 기본적으로 CommonJS 모듈 시스템을 사용하기에 ES6 모듈을 지원하려면 몇 가지 추가 설정이 필요하다.
CommonJS 모듈 시스템이 뭔데?
CommonJS 모듈 시스템은 자바스크립트에서 모듈을 정의하고 가져오는 표준화된 방법이다.
Node.js는 CommonJS 모듈 시스템을 기본으로 사용한다.
- 모듈 정의(math.js)
// math.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
module.exports = {
add,
subtract
};
위의 코드처럼 모듈을 정의하고 내보낼 때는 module.exports
를 사용한다.
module.exports
은 다음과 같은 특징이 있다.
- 현재 모듈에서 외부로 내보낼 객체나 값 정의
- 다른 파일에서 이 모듈을
require
할 때module.exports
에 정의된 객체나 값을 가져온다.
- 모듈 가져오기(app.js)
// app.js
const math = require('./math');
const sum = math.add(2, 3);
const difference = math.subtract(5, 2);
console.log(`Sum: ${sum}`);
console.log(`Difference: ${difference}`);
모듈을 가져올 때는 require
를 사용한다.
require
은 다음과 같은 특징이 있다.
- 다른 모듈을 가져오기 위해 사용
- 모듈의 경로를 인수로 받는다. (위의 './math'처럼)
- 가져온 모듈의
module.exports
객체를 반환한다. - 동기적 로드 : 호출되는 즉시 해당 모듈을 로드하고 실행된다. 이 과정이 동기적으로 수행되므로, 모듈 로드가 완료될 때까지 다음 코드를 실행하지 않는다.
CommonJS와 ES6모듈의 가장 큰 차이는 비동기적 로드가 가능한지 아닌지이다. CommonJS는 동기적 로드를, ES6 모듈은 비동기적 로드까지도 가능하다. ES6가 최신 자바스크립트 표준이며 비동기적 로드 또한 가능하므로 ES6 사용을 권장한다.
Node.js에서 ES6 모듈을 사용하기 위해서는?
이전 절에서 ES6 모듈 사용을 권장한다고 했다. Node.js는 기본적으로 CommonJS 모듈을 사용하는데, 어떻게 ES6 모듈을 사용하도록 할 수 있을까? 방법은 여러 가지다.
Node.js 설정 변경
npm init
을 하면 생성되는 package.json
파일에 "type": "module"
을 추가한다.
{
"name": "my-project",
"version": "1.0.0",
"main": "index.js",
"type": "module" // 추가
}
이렇게 하면 Node.js가 .js 확장자 파일을 ES6 모듈로 인식하게 된다.
파일 확장자 변경
아주 간단한 프로젝트라 package.json이 딱히 필요하지 않은 경우에 단순히 모듈 파일의 확장자만 변경해 줌으로써 ES6 모듈로 인식하도록 하는 방법도 있다.
이 경우에는 파일 확장자를 .mjs
로 변경하면 된다.
모듈을 가져올 때 주의사항
모듈을 가져올 때는 경로에 반드시 확장자까지 써주어야 한다. 이는 브라우저에서 import가 작동하는 방식과 맞추기 위해 의도적으로 설계된 부분이므로 꼭! 지켜줘야 한다.
❌ 틀린 예시 - ERR_MODULE_NOT_FOUND 발생
import 모듈이름 from "./파일이름";
✅ 올바른 예시
import 모듈이름 from "./파일이름.확장자";
결론
CommonJS보다는 ES6 모듈을 사용하는 것이 좋다. 그런데 Node.js는 기본적으로 ES6 모듈을 지원해주지 않으므로 package.json 파일에 "type" : "module"을 추가하거나 파일 확장자를 '.mjs'로 변경하면 된다. 이렇게 하면 SyntaxError: Unexpected token 'export' 오류를 해결하며, Node.js 환경에서도 ES6 모듈을 활용할 수 있을 것이다.