Allra Fintech

(기본기) 노드 런타임과 브라우저 런타임

같은 자바스크립트인데 실행 환경이 다릅니다. Node.js와 브라우저가 각각 무엇을 제공하는지 정리합니다.

같은 언어, 다른 환경

자바스크립트는 하나의 언어지만, 실행되는 곳이 두 군데입니다.

  • 브라우저: 크롬, 파이어폭스 같은 웹 브라우저 안
  • Node.js: 서버, 로컬 컴퓨터의 터미널 안

자바로 비유하면 이렇습니다.
자바 코드는 JVM 위에서 돌아갑니다.
자바스크립트 코드는 자바스크립트 엔진 위에서 돌아가는데, 그 엔진을 감싸고 있는 환경이 브라우저일 수도 있고 Node.js일 수도 있습니다.

엔진(V8)은 같은데, 그 위에 어떤 API가 올라가느냐가 다릅니다.

브라우저 런타임

브라우저는 화면을 그리는 환경입니다.
자바스크립트가 브라우저에서 실행되면, 엔진 외에 이런 것들을 쓸 수 있습니다.

제공하는 것설명
documentHTML 요소를 읽고 조작 (DOM)
window브라우저 창 정보, 전역 객체
fetch서버에 HTTP 요청
localStorage브라우저에 데이터 저장
alert, confirm팝업 대화상자
addEventListener클릭, 키보드 등 이벤트 감지

투두리스트에서 localStorage를 썼던 게 기억나실 겁니다.
그건 브라우저가 제공하는 API이기 때문에 가능한 것이고, Node.js에서는 localStorage가 없습니다.

document.getElementById('app');   // 브라우저에서만 동작
window.innerWidth;                // 브라우저에서만 동작
localStorage.getItem('todos');    // 브라우저에서만 동작

Node.js 런타임

Node.js는 브라우저 바깥에서 자바스크립트를 실행하는 환경입니다.
2009년에 V8 엔진을 브라우저에서 꺼내서, 서버에서도 돌릴 수 있도록 만든 프로젝트입니다.

자바 진영에서 톰캣이 HTTP 요청을 받아서 자바 코드를 실행하는 것처럼,
Node.js는 HTTP 요청을 받아서 자바스크립트 코드를 실행할 수 있습니다.

제공하는 것설명
fs파일 읽기/쓰기
path파일 경로 조작
httpHTTP 서버 생성
process실행 중인 프로세스 정보, 환경 변수
__dirname현재 파일의 디렉토리 경로
const fs = require('fs');
const data = fs.readFileSync('./data.json', 'utf-8');  // 파일 읽기
console.log(process.env.NODE_ENV);                     // 환경 변수

브라우저에서는 fs가 없고, Node.js에서는 document가 없습니다.
같은 자바스크립트인데 쓸 수 있는 도구가 다릅니다.

비교 정리

브라우저Node.js
목적화면을 그리고 사용자와 상호작용서버 실행, 파일 처리, 빌드 도구
전역 객체windowglobal (또는 globalThis)
DOM 접근document로 HTML 조작없음
파일 시스템없음 (보안상 차단)fs로 파일 읽기/쓰기
모듈 시스템<script> 태그, ES ModulesCommonJS (require), ES Modules
패키지 관리없음npm, pnpm, yarn

개발할 때 두 환경이 섞이는 순간

React 개발을 하다 보면, 코드를 작성하는 곳과 실행되는 곳이 다른 상황이 계속 생깁니다.

Vite 개발 서버

리액트 기초 트랙에서 pnpm dev로 개발 서버를 띄웠습니다.
이 개발 서버는 Node.js에서 돌아갑니다.

pnpm dev
→ Node.js가 Vite 서버를 실행
→ .tsx 파일을 변환해서 브라우저에 전달
→ 브라우저가 받아서 화면을 그림

.tsx 파일을 저장하면 화면이 바로 바뀌는 것(HMR)도, Node.js가 파일 변경을 감지해서 브라우저에 알려주기 때문입니다.

npm 스크립트

package.jsonscripts에 들어있는 명령들은 전부 Node.js에서 실행됩니다.

{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  }
}

pnpm build를 실행하면 Node.js가 TypeScript를 컴파일하고, Vite가 번들링해서 순수한 HTML/CSS/JS 파일을 만들어냅니다.
그 결과물이 브라우저에서 실행됩니다.

환경 변수

Node.js에서는 process.env로 환경 변수를 읽습니다.
하지만 브라우저에는 process가 없습니다.

Vite는 이걸 해결하기 위해, .env 파일에서 VITE_로 시작하는 변수만 골라서 빌드 시점에 코드에 주입합니다.

# .env
VITE_API_URL=https://api.example.com
DB_PASSWORD=secret123
console.log(import.meta.env.VITE_API_URL);  // 빌드 시 값이 치환됨
// DB_PASSWORD는 VITE_ 접두사가 없으므로 브라우저에 노출되지 않음

VITE_ 접두사가 없는 변수는 브라우저 번들에 포함되지 않습니다.
DB 비밀번호 같은 것이 프론트엔드 코드에 실수로 들어가는 걸 방지하는 장치입니다.

왜 이걸 알아야 할까

React 코드를 쓰다 보면 이런 에러를 만날 수 있습니다.

ReferenceError: document is not defined

이건 Node.js 환경에서 실행된 코드가 document에 접근하려 할 때 나옵니다.
서버 사이드 렌더링(SSR)이나 빌드 시점에 코드가 실행되면 브라우저 API가 없기 때문입니다.

반대로 Node.js의 fs를 브라우저에서 쓰려고 하면 동작하지 않습니다.

이런 문제를 피하려면 지금 이 코드가 어디서 실행되는지를 항상 인식하고 있어야 합니다.
다음에 나올 서버 사이드 렌더링, 서버 컴포넌트 문서를 이해하려면 이 감각이 필수입니다.

직접 해보기

  • 브라우저 개발자 도구(F12) 콘솔에서 window, document, localStorage를 입력해보기
  • 터미널에서 node를 실행한 뒤 process.version, __dirname을 입력해보기
  • 두 환경에서 fetch가 되는지 확인해보기 (Node 18+ 부터는 fetch 지원)

다음 문서