모듈이란 전체를 이루는 부품 하나하나를 의미합니다. NodeJS에서는 자바스크립트 파일을 모듈이라고 할 수 있습니다.
강의에서는 common js module(require, exports)을 사용했는데, 장기적 관점에서 ES module로 바꿔 실습하려고 합니다.
ES Module은 ECMAScript 6 (ES6)에서 도입된 자바스크립트 모듈 시스템입니다. ES6에서 모듈화는 기본 기능으로 추가되어 브라우저 및 Node.js에서 사용할 수 있습니다.
ES Module은 다른 자바스크립트 파일에서 함수, 클래스, 변수 등을 내보내고 가져오는 데 사용됩니다. 모듈은 독립적인 파일로 작성되어 있으며, 다른 모듈에서 내보낸 항목을 가져와 사용할 수 있습니다. 이를 통해 코드의 모듈성, 재사용성, 유지 보수성이 향상됩니다.
ES Module을 사용하려면 import 문과 export 문을 사용하여 모듈에서 내보내고 가져올 항목을 선언해야 합니다. 브라우저에서는 type="module" 속성을 사용하여 ES Module을 로드하고 사용할 수 있습니다. Node.js에서는 .mjs 확장자를 사용하여 모듈 파일을 작성하고, import와 export 문을 사용하여 모듈을 사용합니다.
export
선언은 자바스크립트 모듈로부터 변수들이나 함수들을 내보내는 데 사욥됩니다. 내보낸 값은 import
선언 또는 dynamic import
으로 다른 프로그램으로 가져올 수 있습니다. 가져올 바인딩(binding)된 값은 내보내는 모듈에서 변경할 수 있습니다.
소스 파일에서 export
선언을 사용하려면 런타임에서 파일을 모듈로 해석해야 합니다. HTML에서는 <script>
태그에 type="module"
을 추가하거나 다른 모듈에서 import
하는 방식을 사용합니다.
// Exporting declarations
export let name1, name2/*, … */; // also var
export const name1 = 1, name2 = 2/*, … */; // also var, let
export function functionName() { /* … */ }
export class ClassName { /* … */ }
export function* generatorFunctionName() { /* … */ }
export const { name1, name2: bar } = o;
export const [ name1, name2 ] = array;
// Export list
export { name1, /* …, */ nameN };
export { variable1 as name1, variable2 as name2, /* …, */ nameN };
export { variable1 as "string name" };
export { name1 as default /*, … */ };
// Default exports
export default expression;
export default function functionName() { /* … */ }
export default class ClassName { /* … */ }
export default function* generatorFunctionName() { /* … */ }
export default function () { /* … */ }
export default class { /* … */ }
export default function* () { /* … */ }
// Aggregating modules
export * from "module-name";
export * as name1 from "module-name";
export { name1, /* …, */ nameN } from "module-name";
export { import1 as name1, import2 as name2, /* …, */ nameN } from "module-name";
export { default, /* …, */ } from "module-name";
export { default as name1 } from "module-name";
// Import
import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { default as alias } from "module-name";
import { export1, export2 } from "module-name";
import { export1, export2 as alias2, /* … */ } from "module-name";
import { "string name" as alias } from "module-name";
import defaultExport, { export1, /* … */ } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
// package.json
{
"type": "module"
}
// math-tools.js
export function add(a, b) {
return a + b;
}
// main.js
import { add as plus } from "./math-tools.js"
console.log(plus(1, 2)); // 3
코어 모듈(Core module)은 프로그램에서 기본적으로 제공하는 내장 모듈으로, Built-in module
이라고도 합니다.
assert
단위 테스트 및 디버깅을 위한 기능을 제공합니다.
buffer
이진 데이터를 다루는 기능을 제공합니다.
child_process
다른 프로세스를 생성하고, 명령어를 실행하며, 프로세스간 통신을 할 수 있는 기능을 제공합니다.
cluster
멀티 프로세스 환경을 구성하는 기능을 제공합니다.
console
콘솔 로그와 디버깅 기능을 제공합니다.
crypto
암호화와 관련된 기능을 제공합니다.
debugger
디버깅 기능을 제공합니다.
dns
DNS(도메인 네임 시스템) 조회 기능을 제공합니다.
events
이벤트 기반 프로그래밍을 위한 기능을 제공합니다.
fs
파일 시스템에 대한 접근 기능을 제공합니다.
http
HTTP 서버와 클라이언트 기능을 제공합니다.
net
TCP 서버와 클라이언트 기능을 제공합니다.
os
운영체제와 관련된 기능을 제공합니다.
path
파일 경로를 다루기 위한 기능을 제공합니다.
process
프로세스와 관련된 기능을 제공합니다.
querystring
URL 쿼리 스트링을 다루기 위한 기능을 제공합니다.
stream
데이터 스트림 처리를 위한 기능을 제공합니다.
timers
타이머 기능을 제공합니다.
url
URL을 다루기 위한 기능을 제공합니다.
util
유틸리티 함수를 제공합니다.
vm
가상 머신을 사용한 자바스크립트 코드 실행 기능을 제공합니다.
zlib
데이터를 압축하고 해제하는 기능을 제공합니다.
import * as fs from "fs";
import * as os from "os";
let fileList = fs.readdirSync(".");
console.log(fileList);
fs.writeFileSync("new", "Hello Ndoe.js!");
console.log(os.cpus());
Node.js에서는 컴퓨터 제어 API가 있습니다. 그래서 Electron 프레임워크를 통해 VS code같은 데스크탑 애플리케이션을 만드는 데도 사용될 수 있습니다.
웹 브라우저에서는 UI 관련 API가 있습니다. 그리고 window, document같은 객체가 존재합니다.
Node.JS의 경우 chrome V8을 실행 엔진으로 사용합니다.
웹 브라우저의 경우 종류와 버전에 따라 다양한 실행 엔진을 사용합니다.
Chrome
V8
Firefox
SpiderMonkey
Microsoft(Chromium) Edge
V8
Edge(구버전)
Chakra
ECMAScript 6 compatibility table 참조
각 실행 환경이 지원하는 ES 문법을 확인할 수 있습니다.
서드파티 모듈은 Node.js 프로젝트에서 사용되는 외부 모듈을 말합니다. 이러한 모듈은 프로젝트를 개발하는 개발자나 팀이 작성한 것이 아닌, 다른 개발자나 조직이 만들어서 배포한 것입니다. 이러한 모듈은 npm
과 같은 패키지 매니저를 통해 설치할 수 있으며, Node.js 프로젝트에서 필요한 다양한 기능을 제공합니다.
package-lock.json
파일은 npm
패키지 매니저를 사용하여 Node.js 프로젝트에서 설치된 패키지들의 의존성 관리를 위한 파일입니다. 이 파일은 npm install
명령을 실행할 때 생성되며, 프로젝트의 루트 디렉토리에 위치합니다.
package-lock.json
파일은 설치된 패키지들의 정확한 버전과 의존하는 다른 패키지들의 버전 정보를 담고 있습니다. 이 파일을 통해 프로젝트에서 사용되는 패키지들의 버전을 고정시키고, 동일한 버전의 패키지를 여러 컴퓨터나 서버에서 사용할 수 있습니다.
또한 package-lock.json
파일은 다른 개발자들과 협업할 때, 같은 패키지 버전을 사용할 수 있도록 도와줍니다. 이 파일이 없으면 npm install
명령을 실행할 때마다 다른 버전의 패키지를 설치할 수 있으며, 이는 프로젝트의 호환성 문제를 일으킬 수 있습니다.
따라서, package-lock.json
파일은 Node.js 프로젝트에서 중요한 역할을 합니다. 프로젝트를 개발하거나 배포할 때는 이 파일을 함께 제공하여 패키지들의 버전을 일관성 있게 유지하는 것이 좋습니다.
yarn
패키지 매니저는 package-lock.json
대신 yarn.lock
파일을 사용합니다.
node_modules
디렉토리는 Node.js 프로젝트에서 사용되는 모듈들을 포함하는 디렉토리입니다. 이 디렉토리는 보통 프로젝트의 루트 디렉토리 내에 위치하며, 프로젝트에서 사용되는 의존 모듈들이 여기에 저장됩니다.
모듈을 import할 때 Node.js는 모듈을 찾기 위해 node_modules
디렉토리를 탐색하며, 해당 모듈이 없는 경우 상위 디렉토리로 올라가면서 탐색합니다. 이러한 방식으로 node_modules 디렉토리를 사용함으로써 모듈의 로딩과 의존성 관리를 간편하게 할 수 있습니다.
node_modules
디렉토리는 npm
이나 yarn
과 같은 패키지 매니저를 사용하여 프로젝트에서 필요한 모듈들을 설치할 때 생성됩니다. 패키지 매니저는 모듈을 설치할 때 node_modules
디렉토리 내에 해당 모듈과 그 모듈이 의존하는 다른 모듈들을 모두 저장합니다. 이를 통해 프로젝트에서 사용되는 모듈들을 쉽게 관리할 수 있습니다.
비동기 프로그래밍은 순차적으로 실행되는 코드 흐름이 아닌, 병렬적으로 실행되는 코드 흐름을 구현하는 방법입니다.
Design overview — libuv documentation 참조
Node.js의 비동기 실행은 libuv라는 라이브러리를 통해서 이루어집니다.
Node.js는 단일 스레드로 작동하며, 이는 많은 요청과 동시에 처리해야 하는 I/O 작업이 많은 서버에서 문제가 될 수 있습니다. 따라서 Node.js에서는 메인 스레드에서 이벤트 루프를 실행하는 비동기 프로그래밍을 통해 I/O 작업을 비차단적(non-blocking)으로 처리할 수 있도록 설계되었습니다.
비동기 프로그래밍은 일반적으로 콜백(callback) 함수나 프로미스(promise) 객체, async/await 구문 등을 사용하여 구현됩니다. 이러한 기법들은 비동기적으로 실행되는 함수들을 동기적인 코드처럼 작성할 수 있도록 도와줍니다.
Javascript 동작원리 (Single thread, Event loop, Asynchronous) | by vincent | Medium, 동시성(Concurrency) vs 병렬성(Parallelism) 참조
콜백(callback)은 다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 말한다. 실행은 동기 콜백에서처럼 즉시 이루어질 수도 있고 비동기 콜백에서처럼 나중에 이루어질 수도 있습니다.
Node.js에서는 비동기적인 작업을 처리할 때, 콜백 함수를 사용하여 작업이 완료되면 해당 함수를 호출합니다. 이를 통해 Node.js는 비동기적인 작업을 비차단적으로 처리할 수 있습니다.
Node.js에서 events
모듈은 이벤트 기반(event-driven) 프로그래밍을 구현하기 위한 코어(core) 모듈 중 하나입니다. events
모듈은 이벤트를 생성하고 처리하기 위한 클래스(EventEmitter
)를 제공합니다.
EventEmitter
클래스는 이벤트를 발생시키고, 이벤트를 처리하기 위한 콜백 함수들을 등록하고 관리하는 기능을 제공합니다. 즉, EventEmitter
객체를 생성하여 이벤트를 정의하고, 이벤트가 발생했을 때 실행할 콜백 함수를 등록하는 방식으로 이벤트 기반 프로그래밍을 구현할 수 있습니다.
events
모듈은 Node.js의 다른 모듈들과 함께 사용되며, 대표적으로 http
, net
, fs
, stream
등의 모듈에서 이벤트를 사용합니다. 이를 통해 Node.js는 비동기적인 I/O 작업을 처리하고, 이벤트 기반으로 프로그램을 작성할 수 있습니다.
import EventEmitter from 'events';
const myEmitter = new EventEmitter();
myEmitter.on('test', () => {
console.log('Success!');
});
myEmitter.emit('test');
Node.js core API는 대부분 비동기적인 이벤트 기반(event-driven) 아키텍처를 일관된 방식으로 구현합니다. EventEmitter
클래스를 사용하여 이벤트를 정의하고, 등록된 콜백 함수(listener
)를 실행합니다. 이를 통해 emitter
객체가, 함수 객체 listener
를 호출하는 named events
를 내보내는(emit) 방식으로 이벤트 기반 프로그래밍을 구현합니다.
Node.js 코어 모듈에서 이벤트를 내보내는(emit) 모든 객체는 EventEmitter
클래스를 상속합니다.
on(eventName, listener)
eventName
에 지정한 이름의 이벤트가 발생했을 때, 실행할 콜백 함수인 listener
를 등록합니다.on
메서드는 addListener
라는 alias도 내장되어 있습니다.emit(eventName[, ...args])
eventName
에 지정한 이름의 이벤트를 발생시킵니다.listener
)가 실행됩니다.emit
메서드에 인자를 전달합니다.once(eventName, listener)
eventName
에 지정한 이름의 이벤트가 최초로 발생했을 때, 한 번만 실행할 콜백 함수(listener
)를 등록합니다.listeners(eventName)
eventName
에 지정한 이름의 이벤트에 등록된 모든 콜백 함수(listener
)들을 배열로 반환합니다.off(eventName, listener)
eventName
에 지정한 이름의 이벤트에서 등록된 특정 콜백 함수(listener
)를 제거합니다.listener
파라미터에 전달해야합니다.Reference