Command Palette

Search for a command to run...

AI 웹개발 기초: 프론트엔드 1-4 | React를 쓰는데 왜 Node.js와 npm이 필요할까

2026-05-12·31 min read

3편에서는 jQuery식 DOM 직접 조작에서 React, Vue, Angular 같은 state/data 기반 component UI로 넘어간 이유를 봤다. React를 대표 사례로 두고, "현재 state라면 화면이 어떻게 보여야 하는가"라는 질문이 중요해졌다는 이야기를 했다.

그런데 React를 직접 시작하려고 하면 이상한 일이 생긴다. 브라우저에서 실행되는 화면을 만들려는 것 같은데, 설치 문서는 Node.js를 요구한다. npm install을 실행하라고 하고, npm run dev로 개발 서버를 띄우라고 하고, 배포 전에는 npm run build를 돌리라고 한다.

이 글에서 붙잡을 문장은 이것이다.

프론트엔드에서 Node.js는 화면 실행 환경이라기보다 package 설치, 개발 서버, build, test 같은 개발 도구의 실행 기반이다.

이 문장을 잡으면 혼란이 줄어든다. 사용자가 보는 최종 UI는 브라우저에서 실행된다. 하지만 그 UI를 만들고, 변환하고, 묶고, 검사하고, 배포 가능한 파일로 만드는 도구들은 대개 Node.js 위에서 실행된다.

브라우저 JavaScript와 Node.js JavaScript는 실행 위치가 다르다

JavaScript라고 해서 항상 같은 곳에서 같은 일을 하는 것은 아니다.

브라우저에서 실행되는 JavaScript는 사용자의 화면 안에서 일한다. DOM을 읽고 바꾼다. 버튼 click event를 처리한다. fetch로 API를 호출한다. React component가 browser 안에서 state에 맞춰 화면을 갱신하는 것도 이 영역에 있다.

Node.js는 JavaScript를 브라우저 밖에서 실행하게 해주는 runtime이다. 내 컴퓨터의 terminal, CI runner, server process 같은 환경에서 JavaScript를 실행한다. 이쪽에는 DOM이 없다. 대신 파일을 읽고, process 환경 변수를 보고, local server를 띄우고, package를 설치하고, build 도구를 실행한다.

브라우저 JavaScript:
사용자의 화면 안에서 실행
DOM, event, fetch, UI 갱신

Node.js:
브라우저 밖에서 실행
file system, process, server, package 설치, build 도구 실행

그래서 "React를 쓰려면 Node.js가 필요하다"는 말을 이렇게 받아들이면 안 된다.

React 화면이 전부 Node.js에서 실행된다

더 정확한 이해는 이쪽이다.

React 화면을 만들기 위한 개발 도구가 Node.js 위에서 실행된다

물론 Node.js로 백엔드 서버도 만들 수 있다. Express나 NestJS 같은 framework를 쓰면 API server를 만들 수 있다. 하지만 프론트엔드 입문에서 먼저 이해할 역할은 server runtime보다 tool runtime이다.

Java 백엔드 개발자라면 Node.js를 Spring Framework보다 JVM 쪽에 가깝게 보면 감이 빠르다. JVM 위에서 Java code와 build/test tool이 실행되듯이, Node.js 위에서 JavaScript toolchain이 실행된다.

npm은 설치 명령 하나가 아니라 package manager와 script runner다

Node.js를 설치하면 보통 npm도 함께 만난다.

npm은 Node.js 생태계의 package manager다. React, Vite, TypeScript, linter 같은 외부 package를 설치하고, 프로젝트가 어떤 package에 의존하는지 기록하게 해준다.

하지만 npm의 역할은 설치에서 끝나지 않는다. package.json에 적힌 script를 실행하는 진입점이기도 하다.

npm install
npm run dev
npm run build
npm test

이 명령들을 하나씩 보면 역할이 다르다.

명령하는 일
npm installpackage.json과 lockfile을 보고 dependency를 설치한다
npm run dev개발 서버를 실행한다. 보통 빠른 갱신과 HMR을 제공한다
npm run build소스 코드를 배포 가능한 정적 파일로 변환한다
npm test프로젝트가 정한 test script를 실행한다

중요한 점은 npm이 모든 일을 직접 깊게 수행하는 것은 아니라는 점이다. npm은 script runner 역할을 하고, 실제 작업은 Vite, TypeScript compiler, test runner, linter 같은 도구가 맡는 경우가 많다.

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "vitest"
  }
}

여기서 npm run build는 npm이 직접 React 코드를 이해해서 build한다는 뜻이 아니다. npm이 vite build라는 명령을 실행하고, Vite가 build pipeline을 수행한다는 뜻이다.

Java 백엔드에 비유하면 npm은 Maven/Gradle과 Maven Central 계열 registry를 조금씩 닮았다. 다만 Maven/Gradle처럼 강한 build lifecycle을 하나로 제공한다기보다, package 설치와 script 실행 진입점을 제공하는 성격이 더 강하다.

package.json은 프로젝트의 부품 목록과 실행 명령 계약이다

프론트엔드 프로젝트에서 package.json은 단순한 메모 파일이 아니다.

프로젝트가 어떤 package를 쓰는지, 어떤 명령으로 개발 서버를 띄우는지, 어떤 명령으로 build하고 test하는지를 기록하는 계약이다.

{
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "react": "version-range"
  },
  "devDependencies": {
    "vite": "version-range",
    "typescript": "version-range"
  }
}

대략 이렇게 나눠 볼 수 있다.

scripts:
npm run dev, npm run build 같은 실행 명령

dependencies:
앱 실행에 필요한 library

devDependencies:
개발, build, test에 필요한 도구

여기서 조심할 점이 있다. dependenciesdevDependencies의 구분은 "중요한 것과 안 중요한 것"이 아니다. 둘 다 중요하다. 다만 최종 앱 runtime에 필요한지, 개발과 build 과정에 필요한지 성격이 다르다.

프론트엔드에서 Vite나 TypeScript는 보통 devDependencies에 있다. 사용자의 브라우저가 Vite package를 직접 실행하는 것이 아니라, 개발자와 CI가 build 과정에서 Vite를 실행하기 때문이다.

AI에게 코드를 맡길 때도 package.json 변경은 가볍게 보면 안 된다. 새 package가 추가되면 dependency tree가 바뀌고, build 결과와 보안 표면도 바뀐다.

package.json은 범위이고 lockfile은 실제 설치 결과다

package.json에 적힌 version은 보통 정확한 숫자 하나가 아니라 허용 범위다.

{
  "dependencies": {
    "some-package": "^1.2.3"
  }
}

Semantic versioning은 version을 보통 MAJOR.MINOR.PATCH로 읽는다.

1.4.2
MAJOR.MINOR.PATCH

^1.2.3은 같은 major version 안에서 더 새 minor/patch를 허용하고, ~1.2.3은 같은 minor version 안에서 patch를 허용한다.

그런데 package.json만 있으면 실제로 어떤 version이 설치됐는지 완전히 고정되지 않는다. 그 역할을 lockfile이 맡는다.

package.json:
설치 가능한 dependency version 범위

package-lock.json:
이번 설치에서 실제 선택된 dependency tree

npm은 package-lock.json을 쓴다. Yarn은 yarn.lock, pnpm은 pnpm-lock.yaml을 쓴다.

한 project root에서 이 lockfile들을 섞으면 설치 기준이 여러 개가 된다. 개발자 A는 npm 기준으로 설치하고, 개발자 B는 pnpm 기준으로 설치하고, CI는 Yarn 기준으로 설치할 수 있다. 그러면 같은 source code를 봐도 실제 dependency tree가 달라질 수 있다.

그래서 한 앱 루트에서는 package manager와 lockfile을 하나로 맞춘다.

npm project:
package-lock.json

Yarn project:
yarn.lock

pnpm project:
pnpm-lock.yaml

Lockfile은 협업과 CI 재현성의 기본 장치다. dependency update를 code review할 때도 package.json만 보는 것이 아니라 lockfile diff까지 봐야 한다.

개발 서버는 배포 서버가 아니라 빠른 피드백 장치다

npm run dev를 실행하면 보통 local development server가 뜬다.

처음에는 이것을 "내 앱 서버"처럼 느낄 수 있다. 하지만 프론트엔드 개발 서버의 1차 목적은 운영 서버가 아니라 빠른 피드백이다.

개발 서버는 source file을 읽고, 브라우저가 요청할 때 필요한 변환을 해주고, 파일이 바뀌면 화면을 빠르게 갱신한다. Vite 같은 도구는 개발 모드에서 browser의 native ESM을 활용해 필요한 module을 요청 시점에 제공하고, 바뀐 module만 빠르게 교체한다. 이 흐름을 HMR이라고 부른다.

개발 모드:
빠른 서버 시작
요청 시점 변환
HMR로 빠른 화면 갱신
디버깅 친화성

반대로 production build는 최종 사용자 성능과 cache가 중요하다. 모든 source file을 그대로 배포하지 않는다. import graph를 분석하고, bundle과 chunk를 만들고, minify하고, hash가 붙은 파일명을 만든다.

프로덕션 모드:
최적화된 bundle/chunk
tree shaking
minify
cache hash
배포 가능한 dist/ 파일

그래서 npm run dev가 잘 된다고 해서 배포 준비가 끝났다고 보면 안 된다. npm run build가 통과해야 개발용 코드가 실제 배포 가능한 artifact로 변환되는지 확인할 수 있다.

build는 개발자가 쓰기 좋은 코드를 브라우저가 받기 좋은 파일로 바꾼다

현대 프론트엔드 코드는 브라우저가 그대로 이해하기 어려운 형태로 작성된다.

TypeScript를 쓴다. JSX나 TSX를 쓴다. import로 파일을 나눈다. CSS와 image를 JavaScript module 안에서 import하기도 한다. 환경별 설정을 넣고, route별로 code splitting도 하고 싶다.

Build는 이 소스 코드를 브라우저와 배포 환경이 받기 좋은 정적 파일로 바꾸는 과정이다.

소스 코드
  -> transpiling
  -> bundling
  -> tree shaking
  -> production optimization
  -> dist/ 정적 파일

각 단계를 짧게 나누면 이렇다.

단계하는 일
transpilingTypeScript, JSX, 최신 JavaScript 문법을 실행 가능한 JavaScript로 바꾼다
bundlingimport graph를 따라 JavaScript, CSS, image, font를 bundle/chunk로 묶는다
tree shaking실제로 사용하지 않는 export와 code path를 제거한다
production optimizationminify, code splitting, cache hash, asset 최적화를 수행한다

예를 들어 개발자는 이렇게 쓸 수 있다.

import "./style.css";

type ButtonProps = {
  label: string;
};

export function Button({ label }: ButtonProps) {
  return <button className="primary">{label}</button>;
}

브라우저는 TypeScript 타입과 JSX를 그대로 실행하지 못한다. Build 도구는 타입을 제거하고, JSX를 JavaScript 호출로 바꾸고, CSS import를 처리하고, 최종 bundle에 필요한 파일을 모은다.

Build는 "귀찮은 compile 단계"가 아니라 개발자 경험과 사용자 경험 사이의 변환 계약이다.

개발자에게는:
TypeScript, JSX, module, component, CSS import

사용자에게는:
작고 빠르고 cache 가능한 JavaScript/CSS/asset

build tool은 한 층짜리 도구가 아니다

여기서 Vite를 조금 더 정확히 놓고 보자.

Vite는 build tool이 맞다. 하지만 Vite를 Rollup, Babel, TypeScript compiler와 같은 한 층의 도구로만 보면 헷갈린다. Vite는 개발 서버, HMR, dependency pre-bundling, production build 명령을 묶어 제공하는 상위 build tool에 가깝다.

프론트엔드 build 도구는 대략 이렇게 층위를 나눠 볼 수 있다.

층위예시역할
상위 build toolVite, Parcel, Rsbuild개발 서버와 production build 흐름을 묶어 제공한다
bundlerwebpack, Rollup, Rolldown, Rspack, esbuild, Turbopackimport graph를 분석해 bundle/chunk를 만든다
compiler/transpiler/minifierTypeScript compiler, Babel, SWC, Oxc, esbuildTypeScript, JSX, 최신 JavaScript를 변환하거나 압축한다
framework toolchainNext.js, Nuxt, Angular CLI, SvelteKitframework의 routing, rendering, build, deployment convention까지 묶는다

그래서 "Vite 같은 상위 build tool이 하위 build tool 역할을 대신한다고 이해해도 되는가"라는 질문에는 이렇게 답할 수 있다.

네, 큰 방향은 맞다.
다만 Vite가 모든 일을 혼자 직접 구현한다기보다,
일부는 직접 수행하고 일부는 하위 bundler/compiler를 내부에서 이용한다.

Java 백엔드에 비유하면 Spring Boot plugin이 compile, test, packaging, resource 처리, dependency 설정을 하나의 개발 경험으로 묶어주지만, 그 아래에는 compiler, test runner, jar packaging, dependency resolver 같은 세부 도구와 단계가 있는 것과 비슷하다.

중요한 것은 도구 이름을 외우는 것이 아니다. npm run build를 실행했을 때 어떤 층위의 도구가 어떤 책임을 맡는지 구분하는 것이다.

npm:
package.json script 실행

Vite:
상위 frontend build tool

bundler/compiler:
module graph 분석, 코드 변환, bundle/chunk 생성, 최적화

dist/:
브라우저와 배포 서버가 받을 최종 정적 파일

Vite는 개발 모드와 production build에서 다르게 움직인다

Vite를 쓰면 개발 서버가 빠르게 뜨는 경험을 많이 한다.

그 이유 중 하나는 개발 모드에서 전체 앱을 미리 다 bundle하지 않는다는 점이다. Vite는 browser의 native ESM을 활용해 필요한 module을 요청 시점에 변환해 제공한다. 파일을 수정하면 바뀐 부분만 빠르게 갱신한다.

하지만 production build에서는 접근이 달라진다. 최종 사용자는 수많은 source file을 개발 서버처럼 하나씩 받아 실행하는 것이 아니라, 최적화된 bundle과 chunk를 받는 편이 유리하다.

Vite의 내부 구현은 version과 설정에 따라 달라질 수 있다. 과거와 많은 프로젝트 설명에서는 production build를 Rollup 기반으로 설명했고, 2026-05-12 기준 최신 Vite 문서에서는 Rolldown/Oxc 전환도 함께 봐야 한다. 입문 단계에서는 특정 구현명 하나보다 역할을 먼저 잡는 편이 안전하다.

Vite production build는:
Rollup/Rolldown 계열 bundler와 compiler/minifier toolchain을 이용해
import graph 분석, tree shaking, code splitting,
CSS/assets 처리, hash filename 생성을 수행한다.
Vite 개발 모드:
native ESM
요청 시점 변환
빠른 HMR

Vite production build:
Rollup/Rolldown 계열 bundle/chunk 생성
tree shaking
code splitting
cache hash

그래서 Vite를 "개발 서버"로만 이해하면 절반만 본 것이다. Vite는 개발 중에는 빠른 피드백을 제공하고, production에서는 배포 가능한 정적 파일을 만드는 build 도구 역할을 한다.

import graph부터 hash filename까지는 한 흐름이다

앞에서 나온 "import graph를 분석하고, tree shaking, code splitting, CSS/assets 처리, hash filename 생성을 수행한다"는 말을 더 풀어보자.

먼저 import graph는 source file 사이의 의존 관계 지도다. 예를 들어 entry가 src/main.tsx라면 build 도구는 그 파일에서 시작해 import를 따라간다.

src/main.tsx
  -> src/App.tsx
    -> src/components/Button.tsx
    -> src/routes/Dashboard.tsx
    -> src/utils/formatDate.ts
  -> src/styles/global.css
  -> node_modules/react
  -> node_modules/react-dom

이 지도에는 JavaScript/TypeScript 파일만 들어가는 것이 아니다. CSS, image, font, JSON, node_modules dependency도 import 관계에 묶일 수 있다.

Tree shaking은 이 지도에서 실제로 쓰이지 않는 export를 최종 bundle에서 제거하려는 최적화다.

// utils/math.ts
export function used() {
  return 1;
}

export function unused() {
  return 2;
}

// main.ts
import { used } from "./utils/math";

console.log(used());

위 코드에서 unused()가 어디에서도 import되지 않고 side effect도 없다면 production build는 그 코드를 최종 bundle에서 제외할 수 있다. 다만 tree shaking은 마법이 아니다. ESM처럼 정적으로 분석하기 쉬운 module 구조, package의 side effect 표시, 코드 작성 방식에 영향을 받는다.

Code splitting은 처음 화면에 필요하지 않은 코드를 별도 chunk로 나누는 일이다. 예를 들어 관리자 화면이나 차트 화면이 처음 방문 때 바로 필요하지 않다면 dynamic import로 분리할 수 있다.

const AdminPage = lazy(() => import("./routes/AdminPage"));

이렇게 분리된 코드는 처음 bundle에 모두 들어가지 않고, 해당 route나 기능이 필요할 때 별도 파일로 받을 수 있다.

CSS/assets 처리는 CSS와 image/font 같은 정적 자원을 production output에 맞게 정리하는 작업이다. 개발자는 component에서 CSS나 image를 import할 수 있다.

import "./button.css";
import logoUrl from "./logo.png";

Build 도구는 CSS를 모으고 압축하거나 chunk별 CSS로 나누고, image/font는 dist/assets/ 같은 위치로 내보낸다. 그리고 JavaScript나 CSS 안의 참조 경로를 실제 배포 파일명으로 다시 쓴다.

마지막으로 hash filename은 파일 내용 기반 hash를 파일명에 붙이는 방식이다.

dist/
  index.html
  assets/index-C8f3a91.js
  assets/index-B4d20aa.css
  assets/logo-F91d8c2.png

파일 내용이 바뀌면 hash도 바뀐다. 내용이 바뀌지 않으면 파일명도 유지된다. 이 덕분에 브라우저와 CDN은 index-C8f3a91.js를 오래 cache할 수 있고, 새 build에서 내용이 바뀐 파일만 새 이름으로 받아갈 수 있다. index.html은 새 hash가 붙은 파일을 참조하도록 다시 생성된다.

전체 흐름을 한 줄로 쓰면 이렇다.

entry 확인
  -> import graph 생성
  -> TypeScript/JSX/CSS/assets 처리
  -> 사용하지 않는 코드 제거
  -> 필요한 기준으로 chunk 분리
  -> minify와 hash filename 생성
  -> dist/ output 생성

그래서 production build는 "소스 파일을 그냥 복사하는 작업"이 아니다. 개발자가 나눠 작성한 코드를 브라우저, CDN, 배포 서버가 다루기 좋은 파일 묶음으로 다시 조직하는 작업이다.

외부 package는 편리하지만 supply chain이기도 하다

npm package를 쓰면 개발 속도가 빨라진다. 날짜 처리, form, chart, router, query cache, icon, build plugin을 직접 만들지 않고 가져다 쓸 수 있다.

하지만 package는 내 프로젝트 안으로 들어오는 외부 코드다. 직접 설치한 dependency뿐 아니라 그 dependency가 다시 끌고 오는 transitive dependency도 함께 들어온다.

여기서 software supply-chain risk가 생긴다.

위험의미
악성 package의도적으로 악성 code가 들어간 package
typosquatting유명 package와 비슷한 이름을 잘못 설치
maintainer 계정 탈취정상 package publish 권한이 공격자에게 넘어감
install script 악용설치 과정에서 실행되는 script가 악성 동작 수행
방치된 dependency오래된 하위 dependency에 취약점이 누적됨

npm audit은 현재 dependency tree를 알려진 취약점 database와 비교해준다.

npm audit

다만 audit은 모든 위험을 자동으로 판단하지 못한다. npm audit fix --force는 major version update까지 수행할 수 있어 앱 동작을 깨뜨릴 수도 있다.

그래서 dependency 변경은 기능 코드 변경처럼 검토해야 한다. 새 package가 꼭 필요한지, maintainer가 신뢰할 만한지, bundle size가 커지지 않는지, lockfile diff가 이상하지 않은지, test와 build가 통과하는지 확인해야 한다.

frontend environment variable은 secret 저장소가 아니다

Build를 다룰 때 environment variable도 자주 만난다.

API_BASE_URL=https://api.example.com
NODE_ENV=production

Backend에서는 environment variable을 secret 관리에 쓰는 경우가 많다. DB password, private API token, signing key 같은 값을 server process 안에서만 읽게 할 수 있기 때문이다.

하지만 frontend build에 들어가는 environment variable은 다르게 봐야 한다. 브라우저에 배포되는 JavaScript bundle 안으로 값이 들어갈 수 있다. 사용자는 최종 bundle을 열어 그 값을 확인할 수 있다.

Vite 기준으로는 VITE_ prefix가 붙은 environment variable이 client-side source code에 노출된다. 예를 들어 VITE_API_BASE_URL은 브라우저 bundle에서 읽을 수 있는 값으로 보아야 한다. 반대로 DB_PASSWORD처럼 prefix가 없다고 해서 frontend secret 저장소가 되는 것도 아니다. 숨겨야 하는 값은 처음부터 frontend build에 넣지 않는 편이 맞다.

frontend env에 넣어도 되는 값:
public API base URL
feature flag
build mode

frontend env에 넣으면 안 되는 값:
database password
private API token
server secret

AI에게 "환경 변수로 빼주세요"라고 요청할 때도 이 구분을 함께 말해야 한다. 공개 가능한 설정은 frontend env로 둘 수 있지만, 숨겨야 하는 secret은 backend나 deployment secret manager 쪽에 있어야 한다.

source map과 CI cache까지 build 운영의 일부다

Build 결과는 보통 압축되고 변환된 파일이다. Production에서 오류가 나면 stack trace가 assets/index-a1b2c3.js의 압축된 한 줄을 가리킬 수 있다. 이때 source map이 있으면 minified bundle 위치를 원래 TypeScript/JSX source 위치로 연결할 수 있다.

dist/assets/index-a1b2c3.js
dist/assets/index-a1b2c3.js.map

Source map은 debugging에 유용하지만, 공개 asset으로 배포하면 원본 source 구조와 일부 code가 노출될 수 있다. 운영에서는 공개 배포, error tracking 도구에 비공개 upload, production source map 비활성화 중 정책을 선택해야 한다.

CI build cache도 build 운영의 일부다.

CI는 매번 깨끗한 runner에서 시작하는 경우가 많다. 매번 package를 전부 새로 설치하고 build cache를 처음부터 만들면 검증 시간이 길어진다. 그래서 package manager cache, framework build cache, test cache를 재사용한다.

다만 cache는 source of truth가 아니다. 속도를 위한 장치다. Lockfile이나 build 설정이 바뀌면 cache key도 바뀌어야 한다. 오래된 cache 때문에 build가 이상하게 실패하거나 통과한다면 cache를 비우거나 key를 조정해야 한다.

AI에게 맡길 때는 명령보다 계약을 말해야 한다

바이브코딩에서 "React 앱 만들어줘"라고 말하면 AI는 코드를 만들 수 있다. 하지만 build와 dependency까지 안정적으로 만들려면 조금 더 구체적인 요구가 필요하다.

요청은 이렇게 바꿀 수 있다.

React + Vite 프로젝트 기준으로 작성해 주세요.

브라우저에서 실행되는 앱 코드와
Node.js에서 실행되는 개발 도구 코드를 구분해 주세요.

package.json에는 dev, build, test script를 명확히 두고,
새 dependency를 추가하면 왜 필요한지 설명해 주세요.

Vite를 상위 build tool로 두고,
Rollup/Rolldown/esbuild/Oxc 같은 하위 bundler/compiler가
어떤 역할을 맡는지 구분해 주세요.

npm 기준이면 package-lock.json을 기준으로 설명하고,
Yarn/pnpm lockfile을 섞지 않게 해 주세요.

frontend environment variable에는 공개 가능한 값만 넣고,
Vite 기준으로 client에 노출되는 VITE_ prefix의 의미를 구분하고,
secret은 backend/deployment secret으로 분리해 주세요.

마지막에 npm run build가 통과해야 하는 구조로 작성해 주세요.

검토할 때는 다음 질문을 던지면 된다.

이 코드는 브라우저에서 실행되는가, Node.js에서 실행되는가?
새 package가 꼭 필요한가?
dependencies와 devDependencies 위치가 맞는가?
lockfile이 package manager와 일치하는가?
npm run dev와 npm run build의 목적이 구분되어 있는가?
상위 build tool과 하위 bundler/compiler 역할이 섞여 설명되지 않았는가?
import graph, tree shaking, code splitting, assets, cache hash가 build 결과와 연결되는가?
VITE_ prefix 같은 frontend env 노출 규칙을 고려했는가?
frontend env에 secret이 들어가지 않았는가?
source map과 CI cache 정책을 의식했는가?

AI가 만든 프론트엔드 코드는 화면만 보고 끝내면 안 된다. package.json, lockfile, build script, environment variable, CI 명령까지 같이 봐야 운영 가능한 코드가 된다.

4편의 핵심은 실행 위치를 나누는 것이다

React를 배우는데 Node.js와 npm이 계속 나오는 이유는 React 화면이 Node.js에서 실행되기 때문이 아니다.

사용자가 보는 UI는 브라우저에서 실행된다. 하지만 그 UI를 만들기 위해 package를 설치하고, 개발 서버를 띄우고, TypeScript와 JSX를 변환하고, bundle을 만들고, test와 build를 돌리는 도구들은 Node.js 위에서 실행된다.

그래서 4편의 핵심은 실행 위치를 나누는 것이다.

Browser:
최종 UI 실행
DOM, event, fetch, component rendering

Node.js:
개발 도구 실행
package 설치, dev server, build, test, CI

이 구분이 잡히면 npm install, npm run dev, npm run build, package.json, lockfile, Vite, Rollup/Rolldown, source map, CI cache가 하나의 흐름으로 이어진다.

다음 편에서는 build 결과물이 어떤 웹 애플리케이션 구조로 서비스되는지 본다. SPA는 무엇이고, MPA와는 무엇이 다른가. CSR, SSR, SSG는 같은 축의 말인가. Next.js는 React의 경쟁자인가, 아니면 React를 production web framework로 확장한 선택지인가.

5편의 주제는 SPA, CSR/SSR/SSG, 그리고 Next.js 선택 기준이다.

이어 읽기

시리즈는 순서대로, 편집 추천은 맥락대로, 비슷한 주제는 태그 기준으로 정리합니다.

시리즈 전체

AI에게 웹 개발을 더 잘 맡기기 위한 웹 기초4/5
  1. 1.AI 웹개발 기초: 프론트엔드 1-1 | 프론트엔드는 왜 이렇게 복잡해졌을까
  2. 2.AI 웹개발 기초: 프론트엔드 1-2 | DOM은 화면이 아니라 브라우저의 작업 모델이다
  3. 3.AI 웹개발 기초: 프론트엔드 1-3 | jQuery에서 React로 넘어간 진짜 이유
  4. 4.AI 웹개발 기초: 프론트엔드 1-4 | React를 쓰는데 왜 Node.js와 npm이 필요할까
  5. 5.AI 웹개발 기초: 프론트엔드 1-5 | SPA, SSR, Next.js는 어떤 기준으로 골라야 할까

비슷한 주제의 글

태그가 겹치는 글입니다. 시리즈와 편집 추천에 이미 나온 글은 제외합니다.