Post

Node 1

개인 프로젝트를 진행하면서 자주사용했던 Node.js 모듈을 한 번에 정리해보고자 한다.🙌

📌Node.js

Node.js는 개발자가 웹 브라우저 외부에서 JavaScript 코드를 실행할 수 있는 오픈 소스 크로스 플랫폼 JavaScript 런타임 환경이다.

우리가 Javascript를 실행하기 위해서는 웹 브라우저가 반드시 필요했으나, Node.js의 등장으로 서버, 데스크톱 환경에서도 Javascript 코드를 실행할 수 있게 되었다.

기본적으로 Node.js도 JS로 만들어져 있으며, 개발자 또한 JS를 활용해 프로그램을 작성할 수 있다.

React, Next.js 처럼 FE에서 사용하는 많은 프레임워크나 라이브러리를 실행하기 위해서는 npm install, npm init과 같은 명령어를 사용하는데 이 명령어는 Node.js 런타임(프로그램이 실행되는 시간 또는 환경)과 npm(Node Package Manager)를 기반으로 동작하게 된다.

즉 우리도 알게 모르게 대부분의 프로젝트가 Node.js 생태계에서 실행되는 것이다!

✍CommonJS VS ESModules

처음 npm init -y으로 node.js 환경을 만들고 아래와 같이 import 구문을 사용했더니 오류가 발생했다.

1
import puppeteer from "puppeteer"

이는 Node.js는 기본적으로 CommonJS를 사용하기 때문이다. 즉 오류를 해결하기 위해선 아래와 같이 작성해주어야 한다.

1
const puppeteer = require("puppeteer")

다만 나는 ESModule방식이 익숙해서, 아래와 같이 package.jsontype을 작성해 import구문을 사용할 수 있도록 수정해주었다.

1
2
3
4
5
6
7
{
  "name": "today-news",
  "version": "1.0.0",
  "type": "module", //🌟
  "main": "index.js",
  //생략...
}

❗그렇다면 두 방식의 차이점은 무엇이 있을까?

항목CommonJS (require)ECMAScript Modules (import)
로딩 방식동기적 (synchronous)비동기적 (asynchronous)
주요 문법require() / module.exportsimport / export
폴더 모듈 지원O (폴더 내 index.js 등 자동 인식)X (명시적 경로 필요: ./folder/index.js)
JSON 파일 로딩.json 자동 파싱importassert { type: "json" } 필요
기본 해석 방식확장자 없으면 JavaScript로 해석.js, .mjs, .cjs만 허용
Top-level await 지원❌ (CommonJS는 top-level await 미지원)✅ (ESM은 기본 지원)

🙌Next.js에서 만났던 Node.js의 모듈

Node 모듈은 기본적으로 client에서는 사용할 수 없기 때문에 대부분 api 작성을 위한 route.ts 파일에서 Node.js 모듈을 사용했었다.

아래는 내가 자주 사용했던 모듈을 위주로 정리한 내용이다.

path

파일 경로나 디렉토리 경로 조작용 유틸리티를 제공한다.

1
2
3
import path from "path"

const fullPath = path.join(__dirname, "uploads", "file.jpg")
  • __dirname은 현재 실행 중인 파일이 위치한 디렉토리 경로를 나타내는 Node.js 내장 변수
  • uploads는 하위 폴더 이름
  • file.jpg는 그 폴더 안에 있는 파일 이름

path.join이 이 세 가지를 합쳐서, 다음과 같은 결과를 만들어 낸다. 📌 Windows 기준 : C:\Users\YourName\project\uploads\file.jpg

fs (File System)

Node.js에서 파일을 읽고, 쓰고, 수정하고, 삭제할 수 있는 모듈이다. 기본적으로는 콜백 방식으로 작동해서, import { mkdir } from 'fs'처럼 불러와 사용하였으나 node.js 10.0 이상 부터 fs/promise로 호출하여 Promise 기반 비동기 처리가 가능하도록 모듈을 불러올 수 있게 되었다.

1
2
3
4
5
6
7
8
9
import {
  writeFile,
  mkdir,
  unlink,
  readdir,
  copyFile,
  rm,
  readFile,
} from "fs/promises"

writeFile(filePath, data)

파일을 생성하거나 덮어쓰기 할 때 사용

1
2
3
import { writeFile } from "fs/promises"

await writeFile("output.txt", "Hello, world!")
  • output.txt 파일이 생성되고 “Hello, world!”가 들어감

mkdir(dirPath, { recursive: true })

디렉토리 생성. {recursive: true}는 만약 지정한 경로에 해당하는 부모 디렉터리가 없다면, 자동으로 생성하는 명령어다.

1
2
3
import { mkdir } from "fs/promises"

await mkdir("public/images", { recursive: true })
  • public과 public/images 폴더가 없으면 모두 생성됨

unlink(filePath)

특정 파일을 삭제한다.

1
2
3
import { unlink } from "fs/promises"

await unlink("output.txt")
  • output.txt 파일이 삭제된다.
  • 존재하지 않으면 에러가 발생하므로 이 경우에는 try/catch문을 활용해 에러를 방지한다.
  • unlink는 특정 파일 1개만 삭제함에 주의한다. (폴더 삭제 명령어는 rm이다.)

readdir(dirPath)

폴더 안에 있는 파일/디렉터리 이름 목록을 배열로 반환한다.

1
2
3
4
import { readdir } from "fs/promises"

const files = await readdir("./logs")
console.log(files) // 예: ['log1.txt', 'log2.txt']

copyFile(src, dest)

파일을 복사 한다.

1
2
3
import { copyFile } from "fs/promises"

await copyFile("original.jpg", "copy.jpg")

예시를 좀 더 살펴보자.

1
2
3
4
5
documents/
├── my1/
│   └── origin.txt
└── my2/
    └── (여기에 copy.txt로 복사하고 싶음!)

다음과 같은 상황이 있을 때 명령어를 어떻게 작성해야 할까?

1
2
3
import { copyFile } from "fs/promises"

await copyFile("documents/my1/origin.txt", "documents/my2/copy.txt")

다음과 같이 어떤 파일을 어디에 보낼 것인지 정확히 입력만 해주면 된다.

rm(path, { recursive: true, force: true })

파일이나 폴더를 재귀적으로 삭제한다.

1
2
3
import { rm } from "fs/promises"

await rm("tmp/frames", { recursive: true, force: true })
  • tmp/frames 폴더 및 하위 파일/폴더 모두 삭제됨
  • force: true는 경로가 잘못되는 등의 문제로 삭제할 폴더가 없는 경우에도 에러를 발생시키지 않는다.

이때 재귀적으로 삭제한다는 것이 어떤 의미인지 살펴보자면

1
2
3
4
5
documents/
├── my1/
│   └── first.txt
└── my2/
    └── second.txt
1
await rm("documents", { recursive: true, force: true })

다음과 같은 폴더 구조를 삭제하고자 이런 명령을 내렸다고 가정해보자. 이때 recursive: true 옵션을 사용해 documents 안의 하위 폴더와 그 안의 모든 txt 파일까지 전부 삭제된다!

http

os

운영체제 관련 정보와 기능을 제공한다.

tmpdir

운영 체제의 임시 파일 기본 디렉터리 경로를 가져오는 데 사용된다.

1
2
3
import { tmpdir } from "os"

const tempPath = tmpdir()

crypto

암호학 적으로 안전한 기능을 제공한다.

randomUUID

1
2
3
import { randomUUID } from "crypto"

const id = randomUUID()
This post is licensed under CC BY 4.0 by the author.