ES6 문법이 도입됨에 따라 node.js에서 import/export 문법을 사용할 수 있게 됐다.
그렇다면 import/export와 require/module.exports의 차이점은 무엇일까?
import/export에 대해 설명하기 전에
require과 module.exports에 대해 알아보자.
ES6 문법이 도입되기 전의 모듈 시스템은 CommonJs 방식이라고 한다.
CommonJs 방식에서 모듈을 내보내는 방법은 exports와 module.exports 두 가지 방식이다.
두 가지 방식의 차이점은 없다! 공식 문서에 따르면 exports는 module 객체의 exports를 참조하는 것 뿐이다.
// test.js
exports.test = function () {
console.log('test');
};
exports.test2 = function () {
console.log('test2');
};
// test.js
function test() {
console.log('test');
}
function test2() {
console.log('test2');
}
module.exports = {
test,
test2,
};
위 코드와 아래 코드는 차이가 없다. 콘솔 로그를 통해 결과를 살펴보면,
exports = { test: [Function (anonymous)], test2: [Function (anonymous)] }
module = Module {
...
exports: { test: [Function (anonymous)], test2: [Function (anonymous)] },
...
}
exports는 module 객체의 exports를 참조하고 있고 결과는 같은 것으로 알 수 있다.
이렇게 외부로 보낸 모듈을 받기 위해서는 require() 함수를 사용해야 한다. require() 함수는 module.exports를 리턴한다. 이에 대해 자세하게 알고 싶으면, (https://medium.com/@chullino/require-exports-module-exports-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-1d024ec5aca3)을 읽어보길 추천한다.
exports 사용할 때 아무런 코드를 넣지 않고 콘솔 로그를 출력해보면, 빈 객체인 것을 확인할 수 있다. 빈 객체 안에 우리는
export.test = function() { ... }와 같이 객체의 프로퍼티를 추가해서 외부로 보내는 것이다.
당연히 프로퍼티로서 함수가 아닌 것들(일반 변수, 객체 등)과 같은 것들을 외부로 보낼 수 있다.
exports로 감싸 보낸 코드를 index.js에서 받아 출력하면 아래와 같은 결과가 나온다.
// test.js
exports.test = function () {
console.log('test');
};
exports.test2 = function () {
console.log('test2');
};
exports.test3 = {};
exports.test4 = 'test4';
// index.js
const test = require('./test');
console.log(test);
// console.log
{
test: [Function (anonymous)],
test2: [Function (anonymous)],
test3: {},
test4: 'test4'
}
물론, module.exports를 이용하여 같은 결과를 출력하게 할 수 있다.
// test.js
function test() {
console.log('test');
}
function test2() {
console.log('test2');
}
const test3 = {};
const name = 'foo';
module.exports = {
test,
test2,
test3,
name,
};
// index.js
const test = require('./test');
console.log(test);
// console.log
{
test: [Function: test],
test2: [Function: test2],
test3: {},
name: 'foo'
}
지금까지 빈 객체에 함수, 변수, 객체 등을 감싸 모듈화하여 외부로 보내는 방법에 대해 알아보았다.
단순히 하나의 함수만을 외부로 보내기 위해서는 어떻게 해야 할까? 간단하다.
// test.js
function test() {
console.log('test');
}
module.exports = test;
또는
// test.js
module.exports = function () {
console.log('test');
};
와 같이 사용하면 된다.
ES6 문법이 도입되고 나서 import/export 방식으로 모듈 불러오기/내보내기 방식을 사용할 수 있게 됐다.
위의 방식을 사용하기 위해서는 node.js의 package.json에서 "type":"module"을 추가해줘야 한다.
ES6의 모듈 내보내기를 할 때, CommonJs의 방식과 비슷하게 두 가지 방식이 존재한다.
1. export를 사용
2. export default를 사용
export 방식은 CommonJs의 exports 방식과 비슷하게 빈 객체로 감싸서 외부로 보내지게 된다.
따라서 외부에서 이를 받을 때 구조 할당 문법을 사용하거나 빈 객체에 담겨진 프로퍼티를 대표하는 객체의 이름을 명시하여 사용할 수 있다.
// test.js
export const test = function () {
console.log('this is test');
};
export const test2 = function () {
console.log('this is test2');
};
// index.js
import express from 'express';
const app = express();
import * as test from './test.js';
console.log(test);
// console.log
[Module: null prototype] {
test: [Function: test],
test2: [Function: test2]
}
// index.js
import { test, test2 } from './test.js';
console.log(test, test2);
// console.log
[Function: test] [Function: test2]
export default 또한, module.exports의 방식과 같이 빈 객체에 프로퍼티를 추가하여 보낼 수 있고,
// test.js
const test = function () {
console.log('this is test');
};
const test2 = function () {
console.log('this is test2');
};
export default {
test,
test2,
};
// index.js
import test from './test.js';
console.log(test);
// console.log
{ test: [Function: test], test2: [Function: test2] }
단순히 하나의 함수 또는 변수 등을 보낼 수도 있다.
// 하나의 함수만 외부로 보내는 예시
// test.js
const test = function () {
console.log('this is test');
};
export default test;
// index.js
import test from './test.js';
console.log(test);
// console.log
[Function: test]