module을 처음봤을 때 와 익숙하지 않았다.
요즘은 보통 바벨과 같이 사용하여 import / export default 를 자주써서 그랬던 것 같다.
이참에 제대로 이해하고 넘어가야겠다.( es6부터 사용)
1. 모듈이 필요한 이유
자바스크립트는 웹페이지에 있어서 보조적인 기능을 수행하기 위해 한정적인 용도로 만들어진 태생적 한계로 다른 언어에 비해 부족한 부분이 있는 것이 사실이다. 그 대표적인 것이 모듈 기능이 없는 것이다.
웹 페이지에서 자바스크립트를 사용하기 위해서는 위 사진과 같이 스크립트 태크를 통해 자바스크립트 파일을 가져오면된다.
그런데 만약 필요한 자바스크립트 파일이 2개라면 어떻게 해야할까?
script 태그를 하나 더 추가하고 파일을 가져오면 된다.
하지만 지금과 같이 두 파일에 서로 같은 이름의 변수가 선언되어 있다면 어떻게될까?
여기서 todo의 값이 무엇이 될지 상상해보자
todo의 값은 index.js 읽을 때 까진 '테크톡 준비하기'이다가 todo.js파일을 읽는 순간 '꿀잠자기'로 덮어 씌어질 것이다.
지금과 같은 방법으로 자바스크립트 파일을 불러온다면 하나의 파일에 모든 코드를 작성하는 것과 다르지 않다.
또한 현재 'todo'는 전역변수이다.
이런 방식으로 코드를 작성하는 것은 전역 스코프를 오염시킬 뿐 아니라, 예측하기 어렵고 오류를 만들어내기 쉬운 코드를 생산해내게 할 것이다.
이러한 문제는 클로저의 원리를 이용하여 즉시실행 함수 등을 통해 구현한 모듈 패턴으로,
외부로부터 독립적인 스코프를 만들어 사용하며 어느정도 해소되는 것처럼 보였다.
그런와중에 자바스크립트를 client-side에 국한하지 않고 범용적으로 사용하고자 하는 움직임이 생기면서 모듈 기능은 반드시 해결해야하는 핵심 과제가 되었고 이런 상황에서 제안된 것이 CommonJs와 AMD(Asynchronous Module Definition)이다.
Node.js는 사실상 모듈 시스템의 표준인 CommonJS를 채택하였고 현재 독자적인 진화를 거쳐 CommonJS사양과 100% 동일하지는 않지만 기본적으로 CommonJS방식을 따르고 있다.
Node.js는 module 단위로 각 기능을 분할할 수 있다. module은 파일과 1대1의 대응 관계를 가지며 하나의 모듈은 자신만의 독립적인 실행 영역(Scope)를 가지게 된다. 따라서 클라이언트 사이드 JavaScript와는 달리 전연변수의 중복 문제가 발생하지 않는다.
- 모듈은 module.exports 또는 exports 객체를 통해 정의하고 외부로 공개한다.
- 공개된 모듈은 requir 함수를 사용하여 임포트한다.
2. 모듈이란 무엇?
모듈이란 "독립된 기능을 갖는 것(함수, 파일)들의 모임"이다.
옛날 방식인 절차지향으로 모든 기능을 구성하는 것 보다.
기능별로 함수를 만들어 함수를 호출하는 방식으로 프로그래밍 하면 유지보수가 훨씬 편해진다.
모듈은 Node.js에서 제공한는 것이 있고, 또는 누군가가 만들어 놓은 모듈이 있으며, 직접 만들 수도 있다.
모듈을 라이브러리화 시켜서 깃헙에 올릴수도 있고, 비즈니스 로직에 따라 모듈을 만들어 사용할 수도 있다.
우리가 평소에 많이 쓰던 라이브러리들이은 누군가가 직접만든 것이다.
모둘은 2가지로 나눌 수 있다.
- 일반 모듈
- 일반 Node.js 개발자들이 만들어 놓은 모듈(라이브러리)
- 외장 모듈을 사용하기 위해서는 npm( Node Package Manager) 을 사용한다.
- 내장 모듈
- Node.js를 설치하고 나면 그 안에 이미 제공되어지는 모듈을 의미
- 내장 모듈은 이미 Node.js를 설치할 때 존재하기 때문에 npm을 사용하지 않는다.
3. 모듈 직접 만들어보기
1) module 객체 확인하기
<app.js>
console.log(module)
app.js를 만들고 module이라는 것을 출력해봅니다.
터미널에서 다음을 실행해 봅니다.
node app.js //만약 src폴더에 만들었으면 node src/app.js
node 명령어를 활용하면, app.js라는 파일 자체를 하나의 "모듈"로 인식합니다.
따라서 app.js에 자동으로 module 이라는 전역 객체가 생성됩니다.
터미널 명령어의 결과는 다음과 같습니다.
exports라는 프로퍼티를 주목해야한다.
우리가 app.js에서 만들어주는 함수,객체,원시값들을 모듈 밖에서도 사용 가능하게 만들어준다.
만약 function이었다면 exports에 function이 뜬다.
그리고 다른 모듈을 import하면 children value에 저장이된다.
2) export는 module 객체와는 다른 객체이다.
위에서 본 module이라는 객체의 exports와는 다른 객체인 exports 객체도 있다.
이 객체는 module.exports와 같은 객체를 "바라볼"뿐 같은 변수는 아니다.
exports 변수는 exports = ... 이런식으로 사용이 가능하다.
exports에 hi라는 메서드를 붙여주었다고 한다면, module.exports도 똑같이 바뀔 것이다.
같은 변수는 아니지만, 같은 객체를 바라보기 때문에 exports 프로퍼티에 잘 들어가 있는 것이다.
3) export 한 번 해보기
첫 번째 방법(export 사용하기)
<app.js>
// 첫 번째 방법
exports.add = function (a, b) {
return (a + b);
}
두 번째 방법
// 두 번째 방법
let app = {};
app.add = function(a, b){
return a + b;
}
module.exports = app;
아까 보았던 module 하의 exports라는 그 객체에 add라는 메서드를 넣는 것이다.
그 다음 두 가지의 방법을 각각 index.js에서 실행해보자
//index.js
let app = require("./app"); //clac === Module.exports
console.log(app.add(2, 3)); //5
이런 식으로 index.js를 구성한 다음, 아까처럼 node index.js 라고 명령어를 입력하자
그러면 console에 대한 결과 값으로 5가 나온다.
추가적으로 우리는 지금 두 개의 모듈을 생선한 것이다.
- add 함수를 가진 app.js
- app을 불러오는 index.js
4) exports 에 바로 할당하는 것은 안 된다.
// not do this!
exports = function add (a, b){
return a + b;
}
왜 안될까?? 그전에 require함수에 대해 알아야 한다.
require 함수란?
var require = function(src){
var fileAsStr = readFile(src)
var module.exports = {}
eval(fileAsStr)
return module.exports
}
이게 require 함수 원형인데 src에서 파일을 읽은 후 export라는 새로운 객체에 그 값을 넌는 것이다.
그리고 module.exports를 반환한다.
4. exports와 module.exports의 차이
exports와 module.exports는 같은 값을 바라보는 다른 변수이다.
즉 이들이 참조하는 값이 같은 뿐, 서로 다른 식별자라고 할 수 있다.
module.exports 사용하기 -> 실제 module 객체를 다루는 것
exports를 그대로 사용하기 -> 실제 module의 exports 프로퍼티와 단지 같은 값을 바라보는 변수를 사용하는 것
이렇게 하나의 객체를 바라보는 두 변수가 존재한다.
그렇기 때문에 생기는 문제가 있다.
exports = app;
이 코드는 exports라는 변수에 새로운 값을 넣은 것이다.
원래 exports가 가리키고 있었던 객체 {} 에서 다른 곳을 바라보도록 하는 것이다.
앞에서 봤듯이 require는 module.exports의 값을 참조한다.
그렇기 때문에 우리는, module.exports와 같은 값을 바라보는 exports 자체의 값을 바꾸어서 다른 곳을 바라보게 만들면 안 되고,
exports의 프로퍼티에 값을 저장해야 한다.
exports.add = function(a, b){
return a + b;
}
// not do this!
exports = function add (a, b){
return a + b;
}
이렇게 말이다.
source
https://www.youtube.com/watch?v=9b89f21Sizs
https://baeharam.netlify.app/posts/javascript/module
https://poiemaweb.com/nodejs-module
https://basemenks.tistory.com/233
'Node.js' 카테고리의 다른 글
Node.js 버전 변경하기 (0) | 2024.01.05 |
---|---|
Peer Dependencies는 왜 필요하고 사용될까? (0) | 2023.12.03 |
package.json (0) | 2023.10.08 |
패키지 매니저 비교 (npm vs yarn vs pnpm) (0) | 2023.08.20 |
yarn berry 세팅하기 (1) | 2023.07.02 |