[Node.js] Module Wrapper, modules, ES6 Imports

Juyeon Lee·2024년 6월 29일

[새싹x코딩온]

목록 보기
11/23

Node.js

브라우저에 크롬의 V8 엔진이라는 것이 있는데, 이 엔진과 다른 코드들을 결합하여 원래는 브라우저에서만 사용했던 자바스크립트를 브라우저 밖에서 사용할 수 있게 되었다. 그래서 브라우저 바깥에서 애플리케이션을 만들 수 있는 환경을 제공하게 되었는데, 이것이 Node.js이다.

Node.js 특징

  1. 자바스크립트 언어를 사용한다.
  2. Single thread로 데이터 흐름이 하나밖에 없다. 여기서 thread는 프로세스 내에서 실행되는 흐름의 단위를 말한다. 프로세스란 실행 중인 프로그램을 말하고, 운영체제에서 할당하는 작업의 단위를 말한다.
  3. non-blocking I/O input output이다. 입출력이 외부에서 오면 파일을 읽어들이거나 파일을 보낼 때 시간이 많이 걸리는데, 이 non-blocking I/O input output 개념으로 입출력 시간을 개선하고 실행 시간을 빠르게 한다. 이름처럼 block하지 않고 진행하기 때문이다.
  4. 비동기적 event-driven 방식으로 이미 만들어져 있는 코드들을 사용하여 처리를 한다. 명령어를 실행할 때 그 즉시 만들어지는 것이 아니라 이미 만들어져 있는 코드를 실행하고, 어떤 코드가 실행될지 이벤트로 알려준다.

Module Wrapper

Node.js는 각각의 파일을 모듈이라고 한다. 이 각각의 파일들의 코드들을 실행하기 전 우리가 보이지 않는 곳에서 Node.js가 코드를 자동으로 함수로 감싸준다. 이것을 Module Wrapper이라고 한다. Module Wrapper는 다음과 같은 형태를 가지고 있다.

(function (exports, require, module, __filename, __dirname) {
     console.log('Hello from IIFE')
 })()

이런 함수의 형식을 IIFE라고 한다. 이 코드에서 매개변수들은 Node.js가 제공하는 내장 객체들이다.

exports: 다른 파일에서 사용할 수 있도록 현재 모듈에서 외부로 내보내는 역할
require: 다른 모듈 불러오는데 사용
module: 현재 모듈에 대한 정보를 가지고 있음
__filename: 현재 실행중인 파일의 절대 경로
__dirname: 현재 실행중인 파일이 위치한 디렉터리의 경로 제공

이러한 연유로 우리가 따로 저렇게 IIFE 형식으로 직접 쓰지 않아도 예를 들어 이런식으로 코드를 쓰면

console.log(__filename);
console.log(__dirname);

현재 실행중인 파일의 절대 경로와 현재 실행중인 파일이 위치한 디렉토리의 경로가 나오게 되는것이다.

Modules

다음으로 다른 파일에 써있는 코드를 어떻게 가져올 수 있는지에 대해 알아보겠다.

예를 들어 이렇게 greet함수를 포함한 greet.js 파일이 있다고 해보자

function greet(username) {
    console.log('hello',username);
}

// Tell other file you can use this same function
module.exports = greet;

이 greet 함수를 다른 파일에 내보내기 위해서는 module.exports를 사용해야 한다. 앞에서 말한 module wrapper에서의 매개변수를 활용했다는 것을 알 수 있다.

그리고 나서 다른 파일인 index.js에서는 다음과 같이 해당 함수를 가져올 수 있다.

const greet = require('./greet');
greet('Yuuka')

이렇게 하면 greet 함수를 index.js 파일 내에서 직접 정의하지 않고도 사용할 수 있게 된다.
다른 예시로 여러 변수들이 정의되어 있는 people.js 파일을 살펴보자.

let person1 = 'Yuuka';
let person2 = 'Yurika';
let person3 = 'Greta';

//We have to tell other files you can use these
// variables

// module.exports = person1;
module.exports = {person1, person2, person3}

이 파일에서는 여러 변수들을 객체 안에 담아 module.exports로 다른 파일에 내보낸다.index.js 파일에서 이 변수들을 가져와 사용할 수 있게 해주는 코드는 다음과 같다.

const {person1,person2, person3} = require('./people');

console.log(person1);
console.log(person2);
console.log(person3);

ES6 Imports

위에서 다른 파일에 써 있는 코드를 가져올 때 require를 사용했었다. 그런데 더 최신 버전으로 import를 이용하는 방법도 있다. 그 방법을 한 번 알아보자. 위와 똑같이 greet 함수를 포함한 아래의 greet.js의 함수를 내보낸다고 해보자.

function greet(username) {
    console.log('Hello',username)
}

//Tell other files you can use this function
export default greet;

이렇게 export default를 붙여서 내보낼 수 있다. index.js에서 이 함수를 어떻게 불러오는지도 보자.

import greet from "./greet.js";

greet('Yuuka');

이렇게 require 대신 import를 써주면 된다. 그런데 여기서 주의해야 할 점은 from 후에 불러오는 파일 경로를 써줄 때 js를 꼭 붙여줘야 한다는 것이다. require를 사용할 때는 js를 붙여주지 않아도 된다는 점이 다르다.

그럼 import를 사용할 때 여러 가지를 내보내고 불러오는 것은 어떻게 할까? people.js 파일에 이런 코드가 있다고 해보자.

let p1 = 'Yurika'
let p2 = 'Angel'
let p3 = 'Zzong'

export { p1, p2, p3 };

위의 코드처럼 export하고 객체에 보낼 것들을 적어주면 된다. 불러오는 것은 index.js 파일에 이렇게 써주면 된다.


import {p1, p2, p3} from './people.js'

console.log(p1, p2, p3)

여기서 기억해야 할 점은 이렇게 import를 이용할 때는 package.json에서 타입을 추가해 줘야 한다는 것이다. (참고로 package.json은 npm init -y을 해줘야 생김)

위의 캡쳐에서 "type":"module", 이라고 적어준 부분이 보일것이다. 이렇게 써줘야지만 import를 사용할 수 있다.

또, import쓰게 되면 require 을 썼을 때와 다르게 __filename 과 __dirname에 접근할수가 없다. 따라서 아래와 같이 콘솔로그에 출력해보려고 해도 되지 않는다.

console.log(__filename); 
console.log(__dirname);

그렇기 때문에 import를 쓸때는 따로 path module이라는걸 써준다. path module은 다음 포스트에서 정리해보도록 하겠다.

0개의 댓글