1. Node.js module system


Module과 Node.js module system

Node.js에서 가장 근본적이고 중요한 Node.js 모듈 시스템(module system) 모듈(module)은 LEGO 블록에 비유할 수 있다. LEGO 블록은 독립적으로 각각 존재하지만 사용자가 조립하는 방법과 블록의 종류에 따라서 최종 결과물이 달라진다.모듈 또한 LEGO 블록과 마찬가지로 코드의 조각이며, 여러 모듈이 조합되어 하나의 소프트웨어를 이루게 된다. 코드의 깔끔한 모듈화는 유지보수가 쉬운 시스템을 구축할 수 있다. 재사용성과 확장성을 높여 새로운 기능을 개발하거나 유지보수 할 때, 전체적인 비용을 감소시키고 개발팀의 생산성을 증대시킬 수 있다. 모듈화는 지속 가능한 소프트웨어 개발에 있어 중요한 부분이다.

초기 자바스크립트(JavaScript)는 모듈화와 거리가 먼 언어였다. 언어차원에서 모듈을 위한 명시적인 키워드나 패키징 정책을 지원하지 않았기 때문. ES6의 등장으로 달라지긴 하였으나 이전 개발자들에게 자바스크립트의 모듈화는 자바스크립트의 범용적인 사용을 위해서는 반드시 해결해야 하는 과제였다.

CommonJS라는 JavaScript를 브라우저에서뿐만 아니라, 서버사이드 애플리케이션이나 데스크톱 애플리케이션에서도 사용하려고 조직한 자발적 워킹 그룹에서 가장 의미있는 결과를 만들어 냈다. CommonJS의 'Common'은 JavaScript를 브라우저에서만 사용하는 언어가 아닌 일반적인 범용 언어로 사용할 수 있도록 하겠다는 의지로 볼 수 있다.이 그룹은 JavaScript를 범용적으로 사용하기 위해 필요한 '명세(Specification)'를 만들었고, Node.js 모듈 시스템도 CommonJS의 Module specification을 따르고 있다.

CommonJS의 모듈 명세는 모듈을 어떻게 정의하고, 어떻게 사용할 것 인지에 대한 것으로 모듈화에 필요한 것은 크게 세 가지다.

첫 번째는 모든 모듈은 자신만의 독립적인 실행 영역이 있어야 한다. 이 말은 전역변수(Global variable)와 지역변수(Local variable)를 분리하는 것을 의미한다. 서버 사이드 JavaScript의 경우에는 파일마다 독립적인 파일 스코프가 있기 때문에 파일 하나에 모듈 하나를 작성하는 방법으로 독립적인 실행 영역을 만든다.

두 번째는 모듈을 외부에서 사용할 수 있도록 공개하는 것인데, Node.js (CommonJS의 모듈 명세를 따르는)에서는 exports라는 전역 객체를 이용해서 정의한다.

세번째로 모듈을 사용하는 영역에서는 require() 함수를 이용해서 모듈을 불러온다.

Custom module 생성

Module은 파일과 1대1의 대응 관계를 가지며 하나의 모듈은 자신만의 독립적인 실행 영역(Scope)를 가지게 된다. 모듈은 module.exports 또는 exports 객체를 통해 정의하고 외부로 공개하고, 공개된 모듈은 require함수를 사용하여 import할 수 있다.

✔️ exports 객체를 사용하여 생성하는 방법

모듈을 파일로 작성하고 외부에 공개할 대상을 exports 객체의 프로퍼티 또는 메소드를 정의하는 방법이 있습니다.

// calculator.js
const initialNumber = 0

exports.add = (x, y) => initialNumber + x + y; // export 객체에 add method 정의
exports.substract = (x, y) => initialNumber + x - y; // export 객체에 substract method 정의

이제 calculator.js는 독립적인 파일 스코프를 갖는 모듈이다. calculator 모듈에 add와 substract를 exports 객체의 메소드로 정의했다. 변수 initialNumber는 calculator 모듈에서만 유효한 private 변수가 되고, add와 substract 메소드는 외부에 공개되어 필요한 곳에서 사용할 수 있다. 이제 add와 sub 함수가 필요한 곳에서 require() 함수를 사용하여 임의의 이름으로 circle 모듈을 import 할 수 있다.

// main.js
const calculator = require("./calculator.js");

console.log(`1 + 5 =  ${calculator.add(1, 5)}`);
console.log(`1 - 5 =  ${calculator.subtract(1, 5)}`);

이때 require 함수 호출 결과 calculator 모듈은 객체 형태로 반환되어 calculator 변수에 담기게 된다 . 따라서 calculator.add, calculator.sub과 같은 형식으로 공개된 calculator 모듈을 참조한다. 아래 명령어로 main.js 코드를 실행해보면 정상적으로 분리된 모듈을 참조해서 사용할 수 있음을 알 수 있다.

$ node main

1 + 5 =  6
1 - 5 =  -4

✔️ module.exports를 사용하여 만드는 방법 (공식문서 권장)

앞에서 살펴본 exports 객체는 여러 개의 속성과 메소드를 정의할 수 있었다. 하지만 module.exports에는 하나의 객체만 할당할 수 있다.

// calculator.js
const initialNumber = 0

function add(a, b) {
  return a + b;
}
function substract(a, b) {
  return a - b;
}
module.exports = {  // 하나의 객체
	add,
	substract
}

calculator 모듈의 module.exports에는 하나의 객체만을 할당했다.

// main.js
const calculator = require("./calculator.js");
console.log(`1 + 5 =  ${calculator.add(1, 5)}`);
console.log(`1 - 5 =  ${calculator.substract(1, 5)}`);

require 함수를 통해 calculator 모듈을 임포트하여 calculator 변수에 할당했다. 아래와 같이 구조분해 할당을 활용하여 import해 사용할 수도 있습니다.

// main.js
const {add, substract} = require("./calculator.js");
console.log(`1 + 5 =  ${add(1, 5)}`);
console.log(`1 - 5 =  ${substract(1, 5)}`);

지금까지 .js 파일을 만들어서 독립적인 파일 스코프를 갖는 모듈을 만들었다. 그리고 만든 모듈을 외부에 공개하는 방법으로 exports와 module.exports 객체를 사용하는 방법, 그리고 require 함수를 사용해서 필요한 곳에서 모듈을 임포트 하는 방법이 있었다.

처음 exports와 module.exports 방식을 접하게되면 혼동하기 쉬운데, exports는 module.exports를 참조하고 있기 때문에 exports는 module.exports와 같다고 보아도 무방하다. 공식문서에서도 exports는 module.exports의 축약형(shortcut)이라고 언급되어 있다. 그래도 혼란스럽다면, module.exports를 사용한다.





2. Built-in modules - File system module


Node.js로 javascript file 실행

//index.js

const hello = 'Hello world';
console.log(hello)

index.js 파일에 ‘Hello world’ 문자열을 참조하고 있는 hello 변수를 console.log() 함수를 사용해서 출력한다. 터미널에서 아래 명령어를 통해서 index.js 파일을 실행한다.

# zsh or bash
$ node index.js

Hello World

Reading and Writing Files - Synchronously

단순히 Hello World를 출력하는 것 외에도, Node.js는 Browser에서 javascript로 할 수 없는 많은 놀라운 일들을 할 수 있게 만들어 준다.

대표적으로 파일 시스템(File system)에서 파일을 읽고 쓰는 기능이다. 이 기능을 구현하기 위해서는 Node.js에서 기본으로 제공하는 파일 시스템 모듈(module)을 사용하면 쉽게 구현할 수 있다.

syncFileSystem.js 파일에서 require() 함수를 사용해 FS 모듈을 호출하면, 모듈 안에 사용 가능한 많은 함수들이 있는 객체가 반환됩니다. 반환된 객체를 fileSystem 변수에 담아 파일 시스템에 데이터를 읽고 쓰는 기능이 필요할 때마다 사용할 수 있다. fs 모듈이 제공하는 기능은 공식문서를 참고한다.

//syncFileSystem.js
const fileSystem = require('fs')
const data = fs.readFileSync("{파일경로}", "utf-8") // 동기적 파일 I|O 작업

fileSystem 객체를 사용해 직접 파일 시스템에 저장되어 있는 privateInfomation.txt 파일에 접근해 데이터를 읽고 쓰는 작업을 할 수 있다. privateInfomation.txt 예제 파일 안에 이름과 나이 두 가지 개인정보가 저장되어 있다고 가정할 때, node.js 환경에서 실행되는 javascript 코드를 작성해서 privateInfomation.txt을 연 뒤, 추가 개인정보(폰번호, 수정일 등)을 privateInfomation.txt에 추가로 저장할 수 있다. 아래 예제를 보자.

//privateInfomation.txt
Name : Harry Potter
Age : 22
// syncFileSystem.js
const fileSystem = require("fs");

//Read File (Before)
const privateInformation = fileSystem.readFileSync("./privateInformation.txt", "utf-8");
console.log(`===== Before written ===== \n${privateInformation}`);

//Write File
const additionalInfo = `${privateInformation}PhoneNumber : 010-7777-0000\nModified at : ${Date.now()}`;
fileSystem.writeFileSync("./privateInformation.txt", additionalInfo);
console.log("===== Successfully File written! ===== \n");

//Read File (After)
const updatedPrivateInformation = fileSystem.readFileSync("./privateInformation.txt", "utf-8");
console.log(`===== After written ===== \n${updatedPrivateInformation}`);

//추가적으로 실행되어야 하는 코드 (동기적 실행을 이해하기 위해 추가된 코드)
console.log("추가적으로 실행되어야 하는 코드 1");
console.log("추가적으로 실행되어야 하는 코드 2");
console.log("추가적으로 실행되어야 하는 코드 3");
console.log("추가적으로 실행되어야 하는 코드 4");

여기서, fileSystem.readFileSync() 메서드를 사용해서 파일에 접근하게 된다. fileSystem.readFileSync()에 넘겨주는 첫번째 인자는 “파일이 위치한 경로”이고, 두번째 인자는 “문자의 인코딩을 정의하기 위해서 필요한 인자”다.여기서 Sync라는 용어가 등장하는데 이는 synchronic(동기)을 의미한다. 동기란 각 코드가 한 줄 한줄로 처리된다는 것을 뜻한다. **즉 readFileSync() 함수는 동기적으로 실행된다. 때문에 함수가 호출되어 실행된 뒤, 값을 반환할 때까지 기다린 후에 다음 코드를 실행**하게 된다.

아래 명령어를 통해서 코드를 실행시켜보면, 아래와 같이 코드가 순차적으로 실행되는 것을 확인할 수 있다.

$ node syncFileSystem.js

===== Before written =====
Name : Harry Potter
Age  : 22

===== Successfully File written! =====

===== After written =====
Name        : Harry Potter
Age         : 22
PhoneNumber : 010-7777-0000
Modified at : 1653178357269

===== 추가적으로 실행되어야 하는 코드 =====
추가적으로 실행되어야 하는 코드 1
추가적으로 실행되어야 하는 코드 2
추가적으로 실행되어야 하는 코드 3
추가적으로 실행되어야 하는 코드 4
// privateInfomation.txt
// after written!
Name        : Harry Potter
Age         : 22
PhoneNumber : 010-7777-0000
Modified at : 1653178357269

또한 privateInfomation.txt에 핸드폰 번호와 수정 시간이 새롭게 추가된 것을 확인할 수 있다. 이처럼 Node.js는 브라우저와 다르게 운영체제에서 기본적으로 제공하는 주된 서비스(예를 들어서, 파일 I/O 작업)들에 바인딩할 수 있는 기능을 제공해준다.

뿐만아니라 동기적(Synchronously) 실행이 갖는 의미에 대해서도 알아봤다. 동기적 실행으로 파일 시스템에 접근해서 파일을 읽어오는 방식은 좋지 않다. 그 이유는 만약에 위에 예제와 같이 파일을 읽은 후 추가적으로 실행되야 하는 코드들이 있다면, 파일을 읽는 작업 동안 실행이 지연되기 때문이다. 이어지는 설명에서 이러한 블로킹 문제를 해결해주는 비동기적 실행에 대해 알아본다.

Reading and Writing Files - Asynchronously

위 코드에서 사용한 readFileSync() 함수를 사용해서 파일 시스템에 접근하는 방식은 좋지 않다. 그 이유는 readFileSync() 함수가 동기식(Synchronous)으로 코드가 실행되기 때문입니다. 동기란 각 코드가 한 줄 한줄로 처리된다는 것을 의미합니다.즉, 각 줄은 나머지 코드의 실행을 차단하기 때문에 특히 느린 작업(파일을 읽는데 오래 걸리는 작업)에서는 문제가 될 수 있다.

//asyncFileSystem.js
const fileSystem = require('fs')
const data = fs.readFileSync("{파일경로}", "utf-8", callback(err, 읽은data)) // 비동기적 파일 I|O 작업

비동기 함수를 사용함으로써 이러한 문제를 해결할 수 있다. 아래 CASE 1은 위에서 살펴본 fs.readFileSync() 동기 함수를 사용해서 구현한 코드다. 위에서 출력된 결과는 코드가 위에서부터 순차적으로 실행되는 것을 알 수 있다. 즉 파일 작업을 모두 끝낸 뒤, 추가적으로 실행되어야 하는 코드가 실행됩니다.

// CASE 1. Blocking, Synchronous
// syncFileSystem.js

const fileSystem = require("fs");

//Read File (Before)
const privateInformation = fileSystem.readFileSync("./privateInformation.txt", "utf-8");
console.log(`===== Before written ===== \n${privateInformation}`);

//Write File
const additionalInfo = `${privateInformation}PhoneNumber : 010-7777-0000\nModified at : ${Date.now()}`;
fileSystem.writeFileSync("./privateInformation.txt", additionalInfo);
console.log("===== Successfully File written! ===== \n");

//Read File (After)
const updatedPrivateInformation = fileSystem.readFileSync("./privateInformation.txt", "utf-8");
console.log(`===== After written ===== \n${updatedPrivateInformation}`);

//추가적으로 실행되어야 하는 코드 (동기적 실행을 이해하기 위해서 추가된 코드 입니다.)
console.log("\n===== 추가적으로 실행되어야 하는 코드 =====");
console.log("추가적으로 실행되어야 하는 코드 1");
console.log("추가적으로 실행되어야 하는 코드 2");
console.log("추가적으로 실행되어야 하는 코드 3");
console.log("추가적으로 실행되어야 하는 코드 4");

Case 1의 실행 결과를 보면 fileSystem.readFileSyncfileSystem.writeFileSync 메서드들이 동기적으로 실행되기 때문에 결과도 실행 순서와 동일하게 출력되는 것을 볼 수 있다.

$ node syncFileSystem.js

===== Before written =====
Name : Harry Potter
Age  : 22

===== Successfully File written! =====

===== After written =====
Name        : Harry Potter
Age         : 22
PhoneNumber : 010-7777-0000
Modified at : 1653178357269

===== 추가적으로 실행되어야 하는 코드 =====
추가적으로 실행되어야 하는 코드 1
추가적으로 실행되어야 하는 코드 2
추가적으로 실행되어야 하는 코드 3
추가적으로 실행되어야 하는 코드 4

아래 Case 2 코드에서와 같이 fileSystem.readFilefileSystem.writeFile 메서드를 사용해서 비동기적(Asynchronously) 실행으로 파일을 읽거나 쓸 수 있다.

// CASE 2. Non-blocking, Asynchronous
// asyncFileSystem.js

const fileSystem = require("fs");

// Read File (Before)
fileSystem.readFile("./privateInformation.txt", "utf-8", (err, data1) => {
  console.log(`===== Before written ===== \n${data1}`);

  const additionalInfo = `${data1}PhoneNumber : 010-7777-0000\nModified at : ${Date.now()}`;

  // Write File
  fileSystem.writeFile("./privateInformation.txt", additionalInfo, "utf-8", (err, data2) => {
      console.log("===== Your file has been written =====");

      // Read File (After)
      fileSystem.readFile("./privateInformation.txt", "utf-8", (err, data3) => {
        console.log(`===== After written ===== \n${data3}`);
      });
    }
  );
});

//추가적으로 실행되어야 하는 코드
console.log("\n===== 추가적으로 실행되어야 하는 코드 =====");
console.log("추가적으로 실행되어야 하는 코드 1");
console.log("추가적으로 실행되어야 하는 코드 2");
console.log("추가적으로 실행되어야 하는 코드 3");
console.log("추가적으로 실행되어야 하는 코드 4");

readFile() 메서드는 readFileSync 메서드와 다르게 인자로 파일이 저장된 경로, 인코딩, 그리고 Callback 함수를 추가로 받도록 되어 있다. 콜백 함수는 단순히 말해 비동기 동작 함수를 호출할 때, 필수적으로 전달해야 하는 함수로 비동기 실행이 완료되고 호출되는 함수라고 설명하고 넘어가겠습니다. 실행 결과를 먼저 확인해보면, 코드가 위에서부터 순차적으로 실행되는 것이 아니라 마지막 코드가 먼저 실행되고, 파일 읽기/쓰기 작업은 나중에 출력되는 것을 확인 할 수 있다.

//zsh
$ node asyncFileSystem.js

===== 추가적으로 실행되어야 하는 코드 =====
추가적으로 실행되어야 하는 코드 1
추가적으로 실행되어야 하는 코드 2
추가적으로 실행되어야 하는 코드 3
추가적으로 실행되어야 하는 코드 4

===== Before written =====
Name : Harry Potter
Age  : 22

===== Your file has been written =====

===== After written =====
Name        : Harry Potter
Age         : 22
PhoneNumber : 010-7777-0000
Modified at : 1653192110477

이것이 비동기적 실행이다. 지금은 비동기 함수가 실행되면 작업이 끝날때까지 기다리는 것이 아니라 백그라운드에 비동기 작업을 위임해주기 때문에 File I/O 작업이 오래 걸리더라도 추가적으로 실행되어야 하는 코드들에 영향을 주지 않는다. 제대로 이해하기 위해서는 동기, 비동기, blocking, non-blocking, Single-thread, Thread Pool, event-loop 등의 개념을 이해해야 한다.

여기까지의 자료에서 Node.js에서는 브라우저에서 자바스크립트로 할 수 없었던 파일 시스템의 I/O 작업이 가능하다는 사실과 기본으로 제공해주는 파일 시스템 모듈은 동기/비동기 읽기/쓰기를 제공해준다는 것을 알아봤다. 동기와 비동기 시스템에 관하여는 아래의 이미지로 간단히 정리할 수 있다.






3. NPM (Node Package Manager)


NPM이란?

Node.js 기반의 패키지를 사용하려면 npm(node package manager)이라는 패키지 관리 도구가 필요하다. npm을 통해 다양한 패키지를 설치하고 버전을 관리할 수 있다. Node.js를 설치하면 npm이 자동으로 설치된다. 즉, npm을 사용하기 위해서는 Node.js 설치가 선행되어야 한다.

모듈은 크게 Built-in module, Custom module, 3rd-party module로 나눌 수 있다. 커스텀 모듈은 Node.js CommonJS 방식으로 만들 모듈을 의미하고, 빌트인(Built-in) 모듈은 Node.js가 설치되면서 기본으로 내장되어 있는 모듈들을 의미한다. 대표적으로 모듈을 import 할 때 사용하는 require 함수도 빌트인 모듈이다.

마지막으로 3rd-party module은 다른 개발자들이 만들어 놓은 모듈을 의미한다. 개발에 생산성을 높여주고 효율적으로 개발하기 위해서 많이 사용한다. 이러한 3rd-party module의 소스 코드들이 모아져 있는 저장소(npm registry), 웹 사이트(website), 그리고 npm CLI를 통칭하여 NPM이라고 한다. 개발에 필요한 여러가지 패키지는 NPM을 통해 관리한다.

✔️ package.json

  • 프로젝트에 대한 메타 정보와 프로젝트에서 사용중인 npm 패키지에 대한 정보를 담은 파일
  • 프로젝트 초기 세팅할 때 package.json부터 만들고 시작
  • 이때, 프로젝트 별로 필요한 npm 패키지가 버전별 다를 수 있기 때문에 버전까지 명확하게 기록
  • 동일한 버전을 설치하지 않으면 문제가 발생
    # project 폴더에서 아래 명령어 실행
    $ npm init
    
    Press ^C at any time to quit.
    package name: (nodejs-study) westarbucks
    version: (1.0.0)
    description:
    entry point: (index.js)
    test command:
    git repository:
    keywords:
    author: lordmyshepherd
    license: (ISC) MIT
    About to write to /Users/lims/software_engineer/nodejs-study/package.json:
    
    # npm init이 완료되면 폴더에 package.json이 생성됨
  • pacakage.json 파일은 다음과 같이 구성되어 있다. 가장 중요한 몇 가지 속성에 대해 알아보자.
    # pacakage.json 파일
    {
      "name": "api",
      "version": "1.0.0",
      "description": "",
      "main": "index.js", // import하는 entry point
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "lordmyshepherd",
      "license": "MIT",
    	"keywords": [ "" ],
    	"dependencies": {
        "bcryptjs": "^2.4.3",
        "cors": "^2.8.5",
        "dotenv": "^16.0.0",
        "express": "^4.17.3",
        "jsonwebtoken": "^8.5.1",
        "mysql2": "^2.3.3",
        "typeorm": "^0.3.0"
      },
      "devDependencies": {
        "nodemon": "^2.0.15"
      }
    }
    • name: 패키지의 이름. package.json의 name 속성에 저장된다.
    • version: 패키지의 버전. npm의 버전은 다소 엄격하게 관리된다.
    • scripts : node.js command line을 정의해서 사용할 수 있다.
    • dependencies : 프로젝트에서 사용하는 배포용 패키지와 각 버전을 명시.
    • devDependencies : 프로젝트에서 사용하는 로컬 개발용 패키지와 각 버전이 명시.
    • git repository: 소스코드를 저장해둔 Git 저장소 주소를 의미. 나중에 소스에 문제가 생겼을 때 사용자들이 이 저장소에 방문해 문제를 제기할 수도 있고, 코드 수정본을 올릴 수도 있다. package.json의 repository 속성에 저장된다.
    • keywords: 키워드는 npm 공식 홈페이지(https://npmjs.com)에서 패키지를 쉽게 찾을 수 있게 해준다. package.json의 keywords 속성에 저장된다.
    • license: 해당 패키지의 라이선스를 넣어주면 된다. MIT는 오픈소스를 의미.

✔️ node_modules

  • npm install 명령어를 실행할 때 생성되는 node_modules 디렉토리를 말한다.
  • node_modules 디렉토리 내부에는 설치한 패키지들(express, cookie, 등)이 포함되어 있다. 이렇게 해당 프로젝트에 필요한 패키지들을 디렉토리에서 전부 관리할 수 있는 편리함을 제공해 준다.
  • 예를 들어서, http server 개발을 빠르게 하기 위해서 express라는 라이브러리를 설치했다고 가정했을때, 그러면 express 외에도 express와 의존 관계가 있는 패키지들이 모두 설치되어 있는 것을 확인할 수 있다.
    /node_modules
    .
    ├── body-parser
    │   └── lib
    │       └── types
    ├── bytes
    ├── content-disposition
    ├── content-type
    ├── cookie
    ├── cookie-signature
    ├── express
    │   └── lib
    │       ├── middleware
    │       └── router
    ├── finalhandler
    ├── forwarded
    ├── fresh
    ├── http-errors
    ...
  • package-lock.json도 생성되어 패키지 간 의존 관계를 명확하게 표시합니다.

📍 자주 사용하는 npm 명령어 목록

  • npm outdated : 사용하는 어떤 패키지에 업데이트된 내역을 확인
    Package      Current  Wanted  Latest  Location                  Depended by
    body-parser   1.19.2  1.20.0  1.20.0  node_modules/body-parser  NodeJS-simple-api-server-with-express
    express       4.17.3  4.18.1  4.18.1  node_modules/express      NodeJS-simple-api-server-with-express
    
  • npm install + package : 배포용 패키지를 설치한 후에 package.json의 dependencies 속성에 추가
  • npm install --save-dev + package : 개발용 패키지를 설치한 후에 package.json의 devDependencies 속성에 추가
  • npm uninstall + package : 패키지를 삭제(npm rm + package도 가능)
  • npm search + 검색어 : npm 패키지를 검색
  • npm info + package : 패키지의 세부 정보 출력
  • npm login : npm에 로그인을 하기 위한 명령어로 사전에 npmjs.com에서 회원가입이 필요
  • npm whoami : 현재 사용자가 누구인지 출력
  • npm logout : 로그인한 계정에서 로그아웃
  • npm version + major : package.json에서 major version 업로드
  • npm deprecate + [package][version][message] : 패키지를 설치할 때 경고 메시지를 띄운다
  • npm publish : 만든 패키지를 npm에 배포
  • npm unpublish : 만든 패키지의 배포를 중단





4. 마무리


  • 모듈화가 잘 된 코드는 재사용성과 확장성을 높여 새로운 기능을 개발하거나 유지보수 할 때, 전체적인 비용을 감소시키고 개발팀의 생산성을 증대시킬 수 있습니다.
  • Node.js의 모듈 시스템(module system)은 Node.js를 이루고 있는 가장 근본적이고 중요한 근간입니다.
  • CommonJS는 Node.js의 첫 번째 내장 모듈 시스템으로 CommonJS의 모듈 명세를 따르고 있습니다.
  • CommonJS의 모듈 명세는 모듈을 어떻게 정의하고, 어떻게 사용할 것 인지에 대한 것으로 모듈화에 필요한 것은 크게 세 가지다.
    • 첫 번째, 모든 모듈은 자신만의 독립적인 실행 영역이 있어야 한다.
    • 두 번째, 모듈을 외부에서 사용할 수 있도록 공개하는 것인데 Node.js (CommonJS의 모듈 명세를 따르는)에서는 module.exports라는 전역 객체를 이용해서 정의한다.
    • 마지막으로 모듈을 사용하는 영역에서는 require() 함수를 이용해 모듈을 불러온다.
  • fs 모듈을 사용해서 파일 시스템에 접근할 수 있다.
  • fs.readFileSync() 메서드는 동기적으로 실행되고, fs.readFile() 메서드는 비동기적으로 실행된다.
  • npm은 Node.js 기반의 다양한 패키지를 설치하고 버전을 관리할 수 있게 도와주는 패키지 관리 도구다.
profile
helloworld

0개의 댓글