안녕하세요. 이번 시간에는 Node.js 모듈 시스템에 대해 알아보겠습니다.
우선 모듈은 독립적인 하나의 소프트웨어입니다. Node.js는 파일 하나하나가 모듈로 기능하는데요. 브라우저에서는 script 태그로 스크립트를 불러오면 다른 스크립트에서도 이전 스크립트의 변수를 사용할 수 있었지만, Node.js는 명시적으로 이전 스크립트의 변수를 사용하겠다고 선언해주어야 합니다. 이러한 특성 때문에 Node.js에서는 모듈 시스템을 이해하는 것이 중요합니다.
요즘 ES2015가 대세라서 ES2015의 모듈 시스템을 사용해본 분들이 많을텐데요. Node.js의 모듈 시스템은 비슷하긴 하지만 조금 다릅니다. Node.js 버전 6부터는 ES2015를 지원하긴 하지만 하나 도입하지 않은 게 바로 ES2015의 모듈 시스템입니다(이제는 실험적인 기능으로 지원합니다). 아마도 Node.js는 자신의 모듈 시스템(common.js)을 그대로 가져갈 모양입니다.
지금까지 Node.js에서 모듈을 만들 때 module.exports
를 사용했었죠? 대표적인 모듈 생성 방법입니다. 하지만 사실 모듈을 만드는 방법이 하나 더 있습니다. 이번 시간에는 그 방법에 대해서도 알아보겠습니다.
calc.js
function add(a, b) {
return a + b;
}
module.exports = add;
main.js
const add = require('./calc.js');
console.log(add(1, 2)); // 3
위의 calc.js는 흔히 볼 수 있는 모듈입니다. add 함수가 여러 번 재사용 될 때, 개별적인 파일로 만들고 마지막에 다른 파일에서 사용할 변수를 module.exports
에 대입해주면 됩니다. 파일 하나가 모듈 하나의 역할을 하게 됩니다. 저렇게 모듈로 만들면 쉽게 재사용할 수 있죠. 다른 파일(main.js)에서는 해당 파일 경로를 require 해주면 calc.js의 add 함수를 사용할 수 있습니다..
만약 calc.js에 빼기나 곱하기, 나누기같은 기능들을 추가하고 싶다면 어떻게 해야 할까요?
calc.js
function add(a, b) {
return a + b;
}
function substract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
function divide(a, b) {
return a / b;
}
module.exports = {
add: add,
substract: substract,
multiply: multiply,
divide: divide,
};
main.js
const add = require('./calc.js').add;
const multiply = require('./calc.js').multiply;
console.log(multiply(add(1,2), add(2,3)); // 15
하면 됩니다. 객체를 만들어서 안에 내보내고 싶은 것들을 넣고 통째로 export하는 겁니다. require을 하게 되면 객체를 통째로 가져오기 때문에 따로 .add나 .multiply로 속성에 접근해야 합니다. 그런데 위와 비슷하지만 조금 다른 방법이 있습니다. 바로 exports 객체를 사용하는 방법입니다.
calc.js
exports.add = function(a, b) {
return a + b;
};
exports.substract = function(a, b) {
return a - b;
};
exports.multiply = function(a, b) {
return a * b;
};
exports.divide = function(a, b) {
return a / b;
};
main.js는 이전과 같습니다. exports를 사용해 따로따로 추가할 수 있습니다. 사실 exports는 module.exports
와 같습니다. 참조 관계이기 때문이죠. 하지만 주로 module.exports
는 한 번에 export할 때 사용하고, exports는 여러 개의 객체를 따로 export할 때 사용합니다. 문법적 특성 때문입니다.
주의해야 할 점은 exports 자체에는 절대로 다른 값을 대입하면 안 된다는 겁니다. 항상 exports 객체의 속성에 값을 넣어주어야 합니다.
exports = divide;
이렇게 하는 순간 더는 모듈로 기능하지 않습니다. exports는 module.exports
를 참조하고 있는데 다른 것을 대입해버리면 참조 관계가 깨지기 때문이죠. exports는 속성으로 추가할 때만 사용해야 합니다.
ES2015는 위와 개념은 비슷하지만 문법이 조금 달라졌습니다. 아쉽게도 Node.js에서는 ES2015 모듈은 사용하지 못 합니다. ES2015 모듈 시스템에 대해 알고싶으시면 이 강좌 를 참고하세요!
제가 실수로 개정판을 구매하지 않은 탓에 다소 오래된 내용으로 배우게 됐습니다. 그래서 express-generator를 사용하며, 이 패키지가 아직 ES Module을 지원하지 않음을 알게 되었습니다.
ES Module을 사용하는 게 문법적으로나 ESLint와의 호환성 면으로나 더 도움이 될 것 같은데요... 혹시 이를 보완하는 express-generator에 대한 대안이 있을까요?