web

Node.js - Node.js를 직접 만들어보자

제이훈 : 세상 모든 지식의 탐구자 2025. 5. 7. 21:28

Node.js를 직접 만든다면? 런타임 구성 요소와 구현 예제

Node.js는 V8 JavaScript 엔진libuv 비동기 I/O 라이브러리를 기반으로 동작하는 JavaScript 런타임.
Node.js를 직접 만든다면 어떤 요소들이 필요한지, 그리고 실제로 C++로 구현해볼 수 있는 예제들을 통해 구조를 이해 ㄱㄱ

1. Node.js의 기본 구성 요소

Node.js는 아래와 같은 구성 요소로 이루어져 있음.

  • JavaScript 엔진: V8 (또는 SpiderMonkey, JavaScriptCore)
  • 비동기 I/O: libuv 또는 직접 구현한 이벤트 루프
  • C++ 네이티브 모듈: 파일 시스템, 네트워크 API 등
  • 바인딩 시스템: C++ API를 JS에서 호출할 수 있도록 연결

2. V8을 사용한 간단한 JavaScript 실행기

V8 엔진만 사용해도 JavaScript 코드를 실행 가능.

#include <v8.h>
#include <iostream>

using namespace v8;

int main() {
    V8::InitializeICUDefaultLocation("");
    V8::InitializeExternalStartupData("");
    Platform* platform = v8::platform::NewDefaultPlatform().release();
    V8::InitializePlatform(platform);
    V8::Initialize();

    Isolate* isolate = Isolate::New();
    {
        Isolate::Scope isolate_scope(isolate);
        HandleScope handle_scope(isolate);

        Local<Context> context = Context::New(isolate);
        Context::Scope context_scope(context);

        Local<String> source = String::NewFromUtf8(isolate, "'Hello, V8!'", NewStringType::kNormal).ToLocalChecked();
        Local<Script> script = Script::Compile(context, source).ToLocalChecked();
        Local<Value> result = script->Run(context).ToLocalChecked();

        String::Utf8Value utf8(isolate, result);
        std::cout << *utf8 << std::endl;
    }

    isolate->Dispose();
    V8::Dispose();
    V8::ShutdownPlatform();
    delete platform;
}

위 코드를 통해 Node.js처럼 JavaScript 실행이 가능하지만, 파일 시스템이나 네트워크는 구현되지 않은 반쪽짜리임.

3. libuv를 이용한 비동기 이벤트 루프

Node.js는 libuv를 통해 비동기 I/O이벤트 루프를 관리. 아래는 비동기 타이머 예제.

#include <stdio.h>
#include <uv.h>

void timer_callback(uv_timer_t* handle) {
    printf("비동기 타이머 실행됨!\n");
}

int main() {
    uv_loop_t *loop = uv_default_loop();
    uv_timer_t timer_req;

    uv_timer_init(loop, &timer_req);
    uv_timer_start(&timer_req, timer_callback, 1000, 0);

    printf("이벤트 루프 시작!\n");
    uv_run(loop, UV_RUN_DEFAULT);

    return 0;
}

setTimeout()처럼 타이머 기능을 구현할 수 있습니다.

4. JavaScript에서 C++ 함수 호출 (바인딩)

Node.js는 내부적으로 C++ 코드를 JavaScript에서 사용할 수 있게 바인딩. 아래는 예시.

#include <v8.h>
#include <uv.h>

using namespace v8;

void HelloWorld(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = args.GetIsolate();
    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Hello from C++!", NewStringType::kNormal).ToLocalChecked());
}

void Initialize(Local<Object> exports) {
    NODE_SET_METHOD(exports, "hello", HelloWorld);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

위 코드를 빌드하면 JavaScript에서 require('./myModule').hello()로 C++ 함수를 실행할 수 있습니다.

5. 정리

Node.js는 결국 JavaScript 실행기(V8)에 다음과 같은 요소들이 결합된 런타임이다.

  • V8 엔진
  • libuv로 구현된 비동기 이벤트 루프
  • C++로 작성된 네이티브 모듈
  • JavaScript에서 네이티브 호출을 가능하게 하는 바인딩