1. 모듈: 코드 구성의 기본 단위
1.1 모듈이란 무엇인가?
모듈은 특정 기능이나 데이터를 캡슐화한 독립적인 코드 블록입니다. 쉽게 말해, 하나의 잘 정의된 역할을 수행하는 코드 덩어리라고 생각할 수 있습니다. Node.js에서 각 파일은 개별 모듈로 취급됩니다. 모듈 시스템은 이러한 코드 블록을 효율적으로 구성하고 재사용할 수 있도록 돕는 체계입니다. 이를 통해 개발자는 필요한 기능만 선택적으로 가져다 사용할 수 있어 코드 가독성이 향상되고 유지보수가 쉬워집니다.
2. 모듈 활용의 핵심: require
와 module.exports
Node.js에서 모듈을 사용하기 위해서는 module.exports
를 통해 모듈을 외부로 공개(내보내기)하고, require
를 통해 필요한 모듈을 가져와야 합니다.
2.1 모듈 내보내기: module.exports
module.exports
는 모듈의 기능을 다른 파일에서 사용할 수 있도록 외부로 공개하는 역할을 합니다. 특정 함수, 객체, 변수 등을 module.exports
에 할당하여 외부에서 접근 가능하게 만들 수 있습니다.
예제 1: math.js
- 수학 관련 함수들을 모듈로 내보내기
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
function divide(a,b) { // 나누기 함수 추가
return a / b;
}
// add, subtract, multiply, divide 함수를 외부에서 사용할 수 있도록 객체 형태로 내보냅니다.
module.exports = {
add,
subtract,
multiply,
divide // 추가
};
예제 2: greetings.js
- 다양한 인사말을 제공하는 모듈
// greetings.js
const koreanGreeting = (name) => `안녕하세요, ${name}님!`;
const englishGreeting = (name) => `Hello, ${name}!`;
// korean, english 인사말 함수를 외부에서 사용할 수 있도록 객체 형태로 내보냅니다.
module.exports = {
korean: koreanGreeting,
english: englishGreeting
};
2.2 모듈 가져오기: require
require
함수는 다른 모듈을 현재 파일로 불러와 사용할 수 있게 해줍니다. require
함수에 가져올 모듈의 경로를 인자로 전달하면 해당 모듈에서 module.exports
로 공개한 객체를 반환합니다.
예제 1: app.js
- math.js
모듈 사용하기
// app.js
// math.js 모듈을 가져옵니다.
const math = require('./math');
console.log(math.add(5, 3)); // 출력: 8
console.log(math.subtract(10, 4)); // 출력: 6
console.log(math.multiply(2, 6)); // 출력: 12
console.log(math.divide(10,2)); // 출력 : 5
예제 2: main.js
- greetings.js
모듈 사용하기
// main.js
// greetings.js 모듈을 가져옵니다.
const greetings = require('./greetings');
console.log(greetings.korean('철수')); // 출력: 안녕하세요, 철수님!
console.log(greetings.english('John')); // 출력: Hello, John!
예제 3: calculator.js
- 더하기, 곱하기 기능을 제공하는 모듈
// calculator.js
// 더하기, 곱하기 함수를 각각 내보냅니다.
module.exports.add = (a, b) => a + b;
module.exports.multiply = (a, b) => a * b;
예제 4: index.js
- calculator.js
모듈 사용하기
// index.js
// calculator.js 모듈을 가져옵니다.
const calculator = require('./calculator');
console.log(calculator.add(10, 5)); // 출력: 15
console.log(calculator.multiply(3, 7)); // 출력: 21
3. Node.js 내장 모듈: 강력하고 편리한 기본 도구
Node.js는 별도의 설치 없이 바로 사용할 수 있는 다양한 내장 모듈을 기본적으로 제공합니다. 이러한 내장 모듈은 파일 시스템 접근, HTTP 서버 구축, 경로 처리, 운영 체제 정보 획득 등 개발에 자주 사용되는 핵심 기능들을 포함하고 있어 매우 유용합니다.
3.1 파일 시스템 제어: fs
모듈
fs
(File System) 모듈은 파일 및 디렉터리를 생성, 읽기, 수정, 삭제하는 등 파일 시스템과 관련된 작업을 위한 API를 제공합니다.
예제: 파일 읽기, 쓰기, 디렉토리 생성, 파일 삭제, 파일 존재 여부 확인
const fs = require('fs');
// 1. example.txt 파일을 비동기적으로 읽어서 콘솔에 출력합니다.
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log('파일 내용:', data);
});
// 2. output.txt 파일에 "Hello, Node.js!" 문자열을 비동기적으로 씁니다.
fs.writeFile('output.txt', 'Hello, Node.js!', err => {
if (err) {
console.error(err);
return;
}
console.log('파일 쓰기 완료');
});
// 3. new-directory 디렉토리를 비동기적으로 생성합니다.
fs.mkdir('new-directory', (err) => {
if (err) {
console.error(err);
return;
}
console.log('디렉토리 생성 완료');
});
// 4. file-to-delete.txt 파일을 비동기적으로 삭제합니다.
fs.unlink('file-to-delete.txt', (err) => {
if (err) {
console.error(err);
return;
}
console.log('파일 삭제 완료');
});
// 5. example.txt 파일의 존재 여부를 확인합니다.
fs.access('example.txt', fs.constants.F_OK, (err) => {
console.log(`example.txt ${err ? '존재하지 않음' : '존재함'}`);
});
주요 함수 설명:
fs.readFile(path, options, callback)
: 파일을 비동기적으로 읽습니다.path
: 파일 경로options
: 인코딩 등의 옵션 (예: 'utf8')callback
: 파일 읽기가 완료된 후 호출되는 콜백 함수. 에러(err
)와 파일 내용(data
)을 인자로 받습니다.
fs.writeFile(file, data, options, callback)
: 파일에 비동기적으로 데이터를 씁니다.file
: 파일 경로data
: 파일에 쓸 데이터options
: 인코딩 등의 옵션callback
: 파일 쓰기가 완료된 후 호출되는 콜백 함수. 에러(err
)를 인자로 받습니다.
fs.mkdir(path[, options], callback)
: 새로운 디렉터리를 비동기적으로 생성합니다.path
: 생성할 디렉터리 경로options
: 디렉터리 생성 옵션 (예: 권한 설정)callback
: 디렉터리 생성 완료 후 호출되는 콜백 함수. 에러(err
)를 인자로 받습니다.
fs.unlink(path, callback)
: 파일을 비동기적으로 삭제합니다.path
: 삭제할 파일 경로callback
: 파일 삭제 완료 후 호출되는 콜백 함수. 에러(err
)를 인자로 받습니다.
fs.access(path, mode, callback)
: 파일의 존재 여부 및 접근 권한을 확인합니다.path
: 확인할 파일 경로mode
: 접근 권한 확인 모드 (예:fs.constants.F_OK
- 파일 존재 여부)callback
: 확인 완료 후 호출되는 콜백 함수. 에러 발생 시 에러(err
)를 인자로 받습니다.
3.2 HTTP 서버 구축: http
모듈
http
모듈은 HTTP 서버와 클라이언트를 구축하는 데 필요한 API를 제공합니다. 이를 통해 웹 서버를 손쉽게 개발할 수 있습니다.
예제: HTTP 서버 생성, HTML 응답, JSON 응답, URL에 따른 동적 응답
const http = require('http');
// 1. 3000번 포트에서 "안녕하세요! 이것은 HTTP 서버입니다."라는 텍스트 응답을 보내는 기본 HTTP 서버를 생성합니다.
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('안녕하세요! 이것은 HTTP 서버입니다.');
});
server.listen(3000, () => {
console.log('서버가 http://localhost:3000/ 에서 실행 중입니다.');
});
// 2. 3001번 포트에서 HTML 형식의 응답을 보내는 서버를 생성합니다.
const htmlServer = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Hello, World!</h1><p>This is an HTML response.</p>');
});
htmlServer.listen(3001, () => {
console.log('HTML 서버가 http://localhost:3001/ 에서 실행 중입니다.');
});
// 3. 3002번 포트에서 JSON 형식의 응답을 보내는 서버를 생성합니다.
const jsonServer = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'This is a JSON response.' }));
});
jsonServer.listen(3002, () => {
console.log('JSON 서버가 http://localhost:3002/ 에서 실행 중입니다.');
});
// 4. 3003번 포트에서 요청 URL에 따라 다른 응답을 보내는 동적인 서버를 생성합니다.
const dynamicServer = http.createServer((req, res) => {
if (req.url === '/hello') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, user!');
} else if (req.url === '/goodbye') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Goodbye, user!');
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
dynamicServer.listen(3003, () => {
console.log('동적 서버가 http://localhost:3003/ 에서 실행 중입니다.');
});
주요 함수 설명:
http.createServer([options][, requestListener])
: HTTP 서버 객체를 생성합니다.requestListener
: 클라이언트의 요청이 있을 때마다 호출되는 함수.request
(요청 객체)와response
(응답 객체)를 인자로 받습니다.
server.listen(port, callback)
: 서버를 지정된 포트에서 실행합니다.port
: 서버가 실행될 포트 번호callback
: 서버가 시작된 후 호출되는 콜백 함수
3.3 파일 경로 처리: path
모듈
path
모듈은 파일 경로를 안전하고 효율적으로 처리하기 위한 유틸리티 함수들을 제공합니다. 특히, 운영체제별로 다른 경로 구분자(separator)를 고려하여 플랫폼 간 호환성을 높여줍니다.
예제: 파일 경로 결합, 파일 이름/디렉터리 이름/확장자 추출, 경로 정규화, 경로 구분자 확인
const path = require('path');
// 1. 현재 디렉토리(__dirname)와 'folder', 'file.txt'를 결합하여 플랫폼에 맞는 전체 경로를 생성합니다.
const fullPath = path.join(__dirname, 'folder', 'file.txt');
console.log('전체 경로:', fullPath); // 예: /Users/username/project/folder/file.txt (운영체제에 따라 다를 수 있음)
// 2. /Users/username/project/folder/file.txt 경로에서 파일 이름(file.txt)을 추출합니다.
const filename = path.basename('/Users/username/project/folder/file.txt');
console.log('파일 이름:', filename);
// 3. /Users/username/project/folder/file.txt 경로에서 디렉터리 이름(/Users/username/project/folder)을 추출합니다.
const dirname = path.dirname('/Users/username/project/folder/file.txt');
console.log('디렉터리 이름:', dirname);
// 4. /Users/username/project/folder/file.txt 경로에서 확장자(.txt)를 추출합니다.
const extname = path.extname('/Users/username/project/folder/file.txt');
console.log('확장자:', extname);
// 5. /Users/username/../project/folder/./file.txt 경로를 정규화합니다. (불필요한 . 및 .. 제거)
const normalizedPath = path.normalize('/Users/username/../project/folder/./file.txt');
console.log('정규화된 경로:', normalizedPath); // 예: /Users/project/folder/file.txt (운영체제에 따라 다를 수 있음)
// 6. 현재 운영체제의 경로 구분자를 출력합니다.
console.log('경로 구분자:', path.sep); // 예: / (macOS, Linux), \ (Windows)
주요 함수 설명:
path.join([...paths])
: 여러 경로 문자열을 하나로 결합하여 플랫폼에 맞는 경로를 생성합니다.path.basename(path[, suffix])
: 경로의 마지막 부분(파일 이름)을 반환합니다.path
: 전체 경로suffix
: (선택적) 제거할 확장자
path.dirname(path)
: 경로에서 디렉터리 이름 부분을 반환합니다.path
: 전체 경로
path.extname(path)
: 경로에서 파일 확장자를 반환합니다.path
: 전체 경로
path.normalize(path)
: 경로 문자열을 정규화하여 불필요한.
및..
부분을 정리합니다.path
: 정규화할 경로
path.sep
: 플랫폼별 경로 구분자를 제공합니다. (Windows는\
, POSIX는/
)
3.4 운영체제 정보: os
모듈
os
모듈은 운영체제와 관련된 정보를 제공하는 유틸리티 함수들을 포함하고 있습니다. 이를 통해 시스템의 CPU, 메모리, 플랫폼, 아키텍처 등의 정보를 얻을 수 있습니다.
예제: 운영체제 이름, 호스트 이름, CPU 정보, 총 메모리, 사용 가능 메모리, 플랫폼, 아키텍처, 사용자 정보 조회
const os = require('os');
// 1. 운영체제 이름을 출력합니다.
console.log(`운영체제 이름: ${os.type()}`); // 예: Darwin (macOS), Windows_NT (Windows)
// 2. 호스트 이름을 출력합니다.
console.log(`호스트 이름: ${os.hostname()}`); // 예: my-computer.local
// 3. CPU 코어 정보를 배열로 출력합니다.
console.log('CPU 정보:', os.cpus());
// 4. 시스템의 총 메모리 양을 바이트 단위로 출력합니다.
console.log(`총 메모리: ${os.totalmem()} bytes`);
// 5. 시스템의 사용 가능한 메모리 양을 바이트 단위로 출력합니다.
console.log(`사용 가능한 메모리: ${os.freemem()} bytes`);
// 6. 운영체제 플랫폼을 식별하는 문자열을 출력합니다.
console.log(`플랫폼: ${os.platform()}`); // 예: darwin, win32, linux
// 7. 운영체제의 CPU 아키텍처를 식별하는 문자열을 출력합니다.
console.log(`아키텍처: ${os.arch()}`); // 예: x64, arm64
// 8. 현재 사용자에 대한 정보(사용자 ID, 그룹 ID, 홈 디렉터리 등)를 객체로 출력합니다.
console.log('사용자 정보:', os.userInfo());
주요 함수 설명:
os.type()
: 운영체제 이름을 반환합니다.os.hostname()
: 호스트 이름을 반환합니다.os.cpus()
: CPU 코어 정보를 배열로 반환합니다.os.totalmem()
: 시스템의 총 메모리 양을 바이트 단위로 반환합니다.os.freemem()
: 시스템의 사용 가능한 메모리 양을 바이트 단위로 반환합니다.os.platform()
: 운영체제 플랫폼을 식별하는 문자열을 반환합니다. (예: 'darwin', 'win32', 'linux')os.arch()
: 운영체제의 CPU 아키텍처를 식별하는 문자열을 반환합니다. (예: 'x64', 'arm64')os.userInfo([options])
: 현재 사용자에 대한 정보를 담은 객체를 반환합니다.
4. 커스텀 모듈: 사용자 정의 모듈 생성 및 활용
Node.js의 내장 모듈이 제공하는 기능 외에도, 개발자가 직접 필요한 기능을 묶어 커스텀 모듈을 생성하여 활용할 수 있습니다. 커스텀 모듈은 코드 재사용성을 높이고 프로젝트 구조를 체계적으로 관리하는 데 큰 도움이 됩니다.
4.1 커스텀 모듈 생성 및 사용 절차
- 새 파일 생성: 커스텀 모듈로 만들 기능들을 포함할 새로운 JavaScript 파일을 생성합니다. (예:
myModule.js
) - 기능 구현 및 내보내기: 파일에 필요한 기능을 구현하고,
module.exports
를 사용하여 외부에서 사용할 수 있도록 공개합니다. - 모듈 가져오기 및 사용: 메인 애플리케이션 파일에서
require
함수를 사용하여 생성한 커스텀 모듈을 가져와서 사용합니다.
4.2 커스텀 모듈 예제
예제 1: greet.js
- 인사말 및 작별 인사 생성 모듈
// greet.js
function greet(name) {
return `안녕하세요, ${name}!`;
}
function farewell(name) {
return `안녕히 가세요, ${name}!`;
}
// greet, farewell 함수를 외부에서 사용할 수 있도록 객체 형태로 내보냅니다.
module.exports = { greet, farewell };
예제 2: app.js
- greet.js
모듈 사용
// app.js
// greet.js 모듈을 가져옵니다. 객체의 구조 분해 할당 문법을 사용합니다.
const { greet, farewell } = require('./greet');
console.log(greet('홍길동')); // 출력: 안녕하세요, 홍길동!
console.log(farewell('김철수')); // 출력: 안녕히 가세요, 김철수!
예제 3: logger.js
- 로그 메시지 출력 모듈
// logger.js
function logInfo(message) {
console.log(`[INFO] ${message}`);
}
function logError(message) {
console.error(`[ERROR] ${message}`);
}
// logInfo, logError 함수를 외부에서 사용할 수 있도록 객체 형태로 내보냅니다.
module.exports = { logInfo, logError };
예제 4: main.js
- logger.js
모듈 사용
// main.js
// logger.js 모듈을 가져옵니다.
const logger = require('./logger');
logger.logInfo('정보 메시지 출력');
logger.logError('에러 메시지 출력');
예제 5: arrayUtils.js
- 배열 유틸리티 모듈
// arrayUtils.js
const sumArray = (arr) => arr.reduce((sum, num) => sum + num, 0);
const findMax = (arr) => Math.max(...arr);
// sumArray, findMax 함수를 외부에서 사용할 수 있도록 객체 형태로 내보냅니다.
module.exports = { sumArray, findMax };
예제 6: app.js
- arrayUtils.js
모듈 사용
// app.js
// arrayUtils.js 모듈을 가져옵니다.
const arrayUtils = require('./arrayUtils');
const numbers = [1, 2, 3, 4, 5];
console.log('배열 합계:', arrayUtils.sumArray(numbers)); // 출력: 배열 합계: 15
console.log('최댓값:', arrayUtils.findMax(numbers)); // 출력: 최댓값: 5
4.3 폴더 구조를 활용한 모듈 관리
프로젝트 규모가 커지면 여러 개의 모듈이 생겨나게 됩니다. 이때, 관련 있는 모듈들을 하나의 폴더에 모아서 관리하면 프로젝트 구조를 더 체계적으로 유지할 수 있습니다. 예를 들어, utils
폴더를 생성하고 그 안에 다양한 유틸리티 모듈을 모아둘 수 있습니다.
예제: 프로젝트 폴더 구조
project/
├── utils/
│ ├── mathUtils.js
│ └── stringUtils.js
└── app.js
예제: mathUtils.js
- 수학 관련 유틸리티 함수 모듈
// utils/mathUtils.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function power(base, exponent) {
return Math.pow(base, exponent);
}
// add, subtract, power 함수를 외부에서 사용할 수 있도록 객체 형태로 내보냅니다.
module.exports = { add, subtract, power };
예제: stringUtils.js
- 문자열 관련 유틸리티 함수 모듈
// utils/stringUtils.js
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function reverseString(str) {
return str.split('').reverse().join('');
}
// capitalize, reverseString 함수를 외부에서 사용할 수 있도록 객체 형태로 내보냅니다.
module.exports = { capitalize, reverseString };
예제: app.js
- utils
폴더 내 모듈 사용
// app.js
// utils 폴더 내의 mathUtils.js, stringUtils.js 모듈을 가져옵니다.
const mathUtils = require('./utils/mathUtils');
const stringUtils = require('./utils/stringUtils');
console.log('대문자 변환:', stringUtils.capitalize('hello')); // 출력: 대문자 변환: Hello
console.log('문자열 뒤집기:', stringUtils.reverseString('world')); // 출력: 문자열 뒤집기: dlrow
const sum = mathUtils.add(10, 20);
console.log(`합계: ${sum}`); // 출력: 합계: 30
console.log('거듭제곱:', mathUtils.power(2, 3)); // 출력: 거듭제곱: 8
5. 결론: Node.js 모듈 시스템, 강력한 도약을 위한 발판
Node.js의 모듈 시스템은 코드 구성과 재사용을 위한 강력하고 효율적인 체계를 제공합니다. require
와 module.exports
를 통해 모듈을 가져오고 내보내는 핵심 메커니즘을 이해하고, 파일 시스템(fs
), HTTP(http
), 경로 처리(path
), 운영체제 정보(os
)와 같은 유용한 내장 모듈을 자유자재로 활용할 수 있어야 합니다. 또한, 프로젝트의 특성에 맞게 커스텀 모듈을 직접 생성하고 폴더 구조를 활용하여 체계적으로 관리하는 능력을 키운다면 Node.js 개발자로서 한 단계 더 성장할 수 있을 것입니다. 본 가이드가 Node.js 모듈 시스템을 정복하고, 더 효율적이고 유지보수 가능한 코드를 작성하는 데 든든한 기반이 되기를 바랍니다.
'프로그래밍 > Node.js' 카테고리의 다른 글
Node.js를 활용한 네트워킹: HTTP 서버, 요청 및 응답 처리, 웹 소켓 사용하기 (0) | 2025.02.19 |
---|---|
Node.js 파일 시스템 정복: 파일, 디렉토리, 스트림, 버퍼까지! (0) | 2025.02.19 |
Node.js 비동기 프로그래밍: 효율적인 서버 개발을 위한 핵심 가이드 (0) | 2025.02.19 |
Node.js 시작하기: 설치부터 첫 프로젝트까지 완벽 가이드 (0) | 2025.02.19 |
Node.js 완벽 가이드: 개념부터 역사, 장점, 활용까지 (0) | 2025.02.19 |