Skip to content

Latest commit

 

History

History
347 lines (159 loc) · 18 KB

File metadata and controls

347 lines (159 loc) · 18 KB

안녕하세요 연재 3회 를 시작 하겠습니다.

이번 회에서는 프로젝트 기초를 만들어볼겁니다. 우리가 OpenClaw 내구 구조를 파악하고 동일한 역활을 하는 구조로 프로젝트를 클론해보는 것이 목표이므로 거기에 맞는 프로젝트를 구성 하도록 하자는 목적입니다. 하나하나 따라 하다 실패하면 또 생성해보고 하면서 점점 익숙해 지니 너무 걱정마시고 절대 포기 하시 마세요 ^^ Chapter 1. 프로젝트 기초 공사 (Foundation Setup) 가장 먼저 튼튼한 기반을 다집니다. 이 프로젝트는 모든 구성 요소(서버, 앱, 플러그인)가 하나의 저장소에 있는 모노레포(Monorepo )구조를 따릅니다.

모노레포구조 란 ? 은유: 이것은 "온 가족의 짐을 하나의 거대한 트렁크에 담는 것"과 같습니다. 각자 작은 가방을 들고 다니면 잃어버리기 쉽지만, 하나로 묶어 관리하면 필요한 물건을 찾기도, 통째로 옮기기도 훨씬 쉬워지죠. (모노레포가 뭔지 까먹으셨다면? 👉 연재 1회의 '용어 미니 사전 2번' 을 다시 보고 오세요!)

1-1. 환경 설정 (Micro-Process) 1-1-0. 💡 [입문 수업] Node.js는 도대체 왜 쓰는 건가요?

자바스크립트는 들어봤는데, 노드(Node)는 또 뭐죠? Node 대해 잠깐 알아보고 진행 하도록 하죠.

  1. 은유: 수족관을 탈출한 자바스크립트 자바스크립트(JavaScript): 원래 브라우저(크롬, 사파리)라는 '수족관' 안에서만 살 수 있는 예쁜 물고기였습니다. 웹페이지 버튼 색을 바꾸거나 움직임을 주는 일만 할 수 있었죠.

Node.js: 이 물고기에게 **'강력한 기계 슈트'**를 입혀서 수족관 밖(컴퓨터 배경, 서버)으로 나오게 한 것입니다. 이제 자바스크립트는 수족관을 넘어 파일을 지우고, 데이터베이스를 관리하고, 서버를 운영하는 **'천하무적 일꾼'**이 되었습니다. 2. 엔진: 자전거에 페라리 엔진을 달다 (V8)

Node.js 안에는 구글 크롬에서 쓰이는 V8이라는 초고성능 엔진이 들어있습니다.

은유: 자전거(자바스크립트)에 페라리 엔진(V8)을 달아놓은 격입니다. 배우기 쉬운 가벼운 언어인데 속도는 엄청나게 빠른 마법 같은 이유가 여기에 있습니다.

  1. 한 줄 요약 Node.js는 "웹 브라우저 밖에서도 자바스크립트로 프로그램을 만들 수 있게 해주는 실행 환경"입니다.

우리가 만드는 OpenClaw의 든든한 '심장' 역할을 하게 될 친구입니다.

Node.js 설치: v22.12.0 이상 필수 (2장에서 이미 설치 하였음-참조용)

설명: Node.js는 자바스크립트 실행기로, 건설 현장의 작업자와 같은 역할을 합니다. 최신 LTS(Long Term Support, 장기 지원) 버전을 사용하는 이유는 비동기 I/O(입출력) 처리가 핵심인 게이트웨이 서버에 최적화되어 있기 때문입니다.

LTS란? : LTS는 "실수가 없는 노련한 베테랑 실무자"와 같습니다. 매일 새로운 기술이 쏟아지지만, 24시간 멈추지 않아야 하는 기반 시설에는 검증되지 않은 신입보다 경험 많은 베테랑이 필요하기 때문입니다.

설치 방법 (OS별 가이드)

🪟 Windows: 공식 홈페이지 (nodejs.org) 에서 LTS 버전(v22.x) 을 다운로드하여 설치합니다. (Next만 계속 누르면 됩니다) 🍎 Mac: 터미널에 brew install node@22 입력. (Homebrew가 없다면 여기 참조) 🐧 Linux: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs

TIP 🎓 [개념 수업] 비동기 I/O (Asynchronous I/O)가 뭔가요? "맛집 웨이터의 서빙 방식" 으로 이해하면 쉽습니다.

동기(Synchronous = Blocking): 웨이터가 손님 1명에게 주문을 받습니다. 손님이 "음... 뭐 먹지?" 하고 고민하는 5분 동안 웨이터는 아무것도 안 하고 옆에 서 있습니다. 다른 손님들은 기다리다 지쳐 나갑니다.

비동기(Asynchronous = Non-Blocking): 웨이터가 주문을 받다가 손님이 고민하면 "결정되시면 벨 눌러주세요" 하고 다른 테이블로 가서 일을 합니다. 그러다 벨이 울리면(이벤트 발생) 다시 와서 주문을 받습니다.

Why? 왜?: OpenClaw 게이트웨이는 수천 명의 사용자가 동시에 메시지를 보냅니다. 한 명 메시지 처리하느라 다른 사람들을 기다리게 하면 안 되겠죠? 그래서 Node.js의 비동기 방식이 필수입니다.

Language: TypeScript (^5.9.3): 설명: TypeScript(타입스크립트)는 거대한 모노레포(Monorepo, 단일 저장소) 프로젝트의 타입 안정성을 보장하는 엄격한 문법 검사기입니다. 인터페이스(Interface, 약속된 규격) 기반 설계가 필수적인 대규모 프로젝트에서 타입 오류를 사전에 방지합니다.

비유 (인터페이스란?): 인터페이스는 "부품 규격 약속"과 같습니다. 전구가 소켓에 딱 맞아야 불이 들어오듯, "이 코드에는 반드시 이런 모양의 데이터가 들어와야 한다"는 약속을 미리 정해두는 것입니다.

설치 방법: 윈도우/맥 공통 터미널에서 아래 명령어를 입력하세요.( 2장에서 설치 완료 하였습니다. 자세한 이해를 위해 참조 하세요.)

npm install -g typescript

설치 확인

tsc -v

은유 (Metaphor): "철저한 설계도 감리사"

일반 자바스크립트가 "일단 건물을 짓고 나중에 무너지면 고치자"는 식이라면, 타입스크립트는 "벽돌 하나를 쌓을 때마다 설계도(Type)와 일치하는지 확인" 합니다. 조금 귀찮을 수 있지만, 나중에 건물이 무너지는(런타임 에러) 대형 사고를 99% 막아줍니다.

실사용 예제 (Concept Class) :

자바스크립트 (무책임): [사과] + 100 = "사과100" (이상하지만 에러 없이 진행됨)

타입스크립트 (책임감): "잠깐! 과일(String)에 숫자(Number)를 더하다니요? 말도 안 됩니다!" 하고 빨간 줄을 쫙 그어줍니다.

pnpm 설치 : (2장에서 설치 완료함 참조용)

npm install -g pnpm@10.23.0

1-1-1. 🚨 [배경 지식] 왜 npm 대신 pnpm을 쓰는가? (The Revolution of pnpm)

"npm도 잘 되는데 굳이 왜 이걸 또 깔아야 하나요?" 라는 질문은 매우 타당합니다. 하지만 OpenClaw(Moltbot) 같은 대규모 프로젝트(Monorepo)에서 npm을 쓰면 재앙이 닥칩니다.

  1. 은유(Metaphor): 도서관 책 빌리기

npm (비효율의 끝판왕): 학생 100명이 "해리포터" 책을 읽어야 한다고 합시다. npm 방식은 100권의 책을 새로 사서 각 학생의 가방에 넣어주는 것입니다. 가방(디스크)이 터지고, 책값(설치 시간)이 엄청 듭니다.

pnpm (효율적 공유): 학교 도서관에 "해리포터" 딱 한 권만 사놓습니다. 학생들에게는 책 위치가 적힌 쪽지(Symlink) 만 줍니다. 읽을 때는 도서관 책을 참조합니다. 100명이든 1000명이든 책은 한 권이면 됩니다.

  1. 실제 차이 (Real World Impact)

OpenClaw(Moltbot) 프로젝트는 수백 개의 라이브러리를 씁니다.

npm 사용 시 : 프로젝트를 복사할 때마다 1GB가 넘는 node_modules 폴더가 계속 복제됩니다. 하드디스크가 순식간에 꽉 찹니다.

pnpm 사용 시: 100개를 복사해도 용량은 거의 늘어나지 않습니다. (Content Addressable Store 방식)

  1. 결정적 이유 (Killer Feature): 엄격함(Strictness) npm의 유령(Phantom Dependencies): npm은 내가 설치하지 않은 라이브러리도 실수로 쓸 수 있게 허용하는 버그(혹은 관대함)가 있습니다. 나중에 배포할 때 "어? 내 컴퓨터에선 되는데 서버에선 안 돼요!" 하는 지옥을 맛보게 됩니다.

pnpm: 내가 package.json에 명시한 것만 정확히 쓸 수 있게 막아줍니다. "정의되지 않은 것은 없다" 는 철학입니다.

1-1-2. 🛑 [보충 수업] npm이 도대체 뭔가요? (What is npm?) "개발자들은 왜 자꾸 npm npm 거리는 걸까요?"

  1. 은유(Metaphor): 개발자들의 "앱스토어" 혹은 "다이소"
  • 아이폰 앱스토어: 카카오톡이 필요하면 우리가 직접 코딩해서 만들지 않죠? 앱스토어에서 다운로드 받습니다.

  • npm (Node Package Manager): 개발할 때 "달력 기능"이나 "암호화 기능"이 필요하면 직접 짜지 않고 npm이라는 무료 부품 상점에서 다운로드 받습니다.

  1. 레고 블록 (Lego Blocks)
  • 여러분이 "성(Castle)" 을 만든다고 상상해 보세요.

  • 플라스틱을 녹여서 블록 하나하나를 직접 만드는 건 미친 짓입니다. (이게 npm 없이 개발하는 것)

  • npm은 "문", "창문", "성벽" 블록을 미리 만들어 파는 가게입니다. 우리는 npm install castle-wall 명령어 한 줄로 성벽 블록을 가져와서 조립만 하면 됩니다.

  1. 사용하는 이유 (Why?)

시간 절약: 남들이 10년 동안 만든 검증된 코드를 1초 만에 가져와 씁니다.

검증된 품질: 전 세계 수백만 명이 같이 고쳐나가는 코드라서, 내가 짠 코드보다 튼튼할 확률이 높습니다.

  1. 사용 방법 (How?) 연재 2회에서 다루었던 터미널 기억하시죠? 별도로 새 창을 열 필요 없이 거기서 이어서 계속 입력하시면 됩니다. 주문을 외우듯 터미널에 아래 명령어를 입력해 보세요.
  • npm install [부품이름]: "이 부품 우리 집(프로젝트)에 배달해 줘."

  • pnpm install: "이 부품 배달해 주는데, 아까 말했듯이 더 효율적으로(도서관 방식) 배달해 줘."

프로젝트 생성 (집터 닦기):

먼저 컴퓨터 하드디스크(C드라이브 혹은 홈 디렉토리)에 Workspace라는 이름의 폴더 아래 안에 들어가서, 다시 openclaw-lab이라는 폴더를 열어 둡니다.(2장에서 모두 생성함)

구조: 내 컴퓨터 -> Workspace -> openclaw-lab

터미널에서 만약 해당 폴더 안에 있지 않다면 아래 명령으로 이동한 뒤, 정보를 기입합니다.

cd ~/Workspace/openclaw-lab pnpm init

  • 2장에서 이미 설치가 되었던 분들은 " ERR_PNPM_PACKAGE_JSON_EXISTS  package.json already exists" 라는 메세지가 출력 되니 걱정 마세요.

NOTE [Coach's Tip] 왜 굳이 Workspace 폴더를 만드나요? 개발을 하다 보면 "어? 제 파일 어디 갔죠?" 하고 길을 잃는 경우가 정말 많습니다. 윈도우(C드라이브) 사용자, 맥(홈) 사용자 모두 Workspace라는 공통된 약속 장소를 정해두면, 나중에 "경로를 못 찾겠어요" 같은 문제를 99% 예방할 수 있습니다. 이것은 전 세계 개발자들의 '국룰(불문율)' 같은 습관이며, 경로 문제로 헷갈릴 일을 원천 봉쇄해 줍니다.

[ 내용 추가 예정 ]

1-2. 🚨 [심층 이해] 왜 코드를 짜기 전에 tsconfig.json 부터 건드리는가?

많은 분들이 "일단 server.ts 파일 만들고 코드부터 치면 안 되나요?" 라고 묻습니다. 결론부터 말하면, OpenClaw(Moltbot) 같은 거대한 프로젝트에서는 불가능합니다. 그 이유를 아주 쉽게 설명해 드립니다.

  1. 은유(Metaphor): 건물을 짓기 전의 "토지 용도 변경"

일반적인 코딩 (HTML/JS): 맨땅에 텐트를 치는 것과 같습니다. 그냥 폴대(index.html) 꽂고 천(script.js) 덮으면 집이 됩니다. 규칙이 없어도 됩니다.

OpenClaw (TS/ESM): 100층짜리 마천루를 짓는 것과 같습니다. 땅을 파기 전에 "여기는 상업지구이며, 내진 설계 기준은 7.0이고, 철근은 KS규격을 써야 한다" 는 법적/행정적 허가(tsconfig.json) 가 먼저 떨어져야 합니다. 허가증 없이 철근(import)을 하나라도 세우면 공사 중지 명령(Syntax Error)이 떨어집니다.

  1. 비교(Comparison): 동네 축구 vs 월드컵

동네 축구 (Legacy JS Project): 심판도 없고 규칙도 대충입니다. "손만 안 쓰면 돼." 바로 공 차면 됩니다.

월드컵 (Modern TypeScript Project): 경기 시작 전에 "오프사이드 반칙 기준", "VAR 판독 여부", "교체 선수 숫자"가 룰북(tsconfig.json)에 정의되어야 합니다. OpenClaw는 월드컵 결승전급의 엄격한 규칙 하에 돌아가는 시스템입니다.

  1. 실제 예시 (Real World Scenario)

만약 설정 없이 바로 코드를 짠다면?

개발자 : (자신있게) import { Server } from 'http'; 컴퓨터(Node.js) : "잠깐, import가 뭐죠? 저는 옛날 방식(require)밖에 모르는데요?" -> 에러 발생 (Crash) 개발자 : (당황하며) 어? 요즘 다 이거 쓰던데? 컴퓨터 : "그건 tsconfig.json 이라는 번역기가 있을 때 얘기입니다. 저한테 미리 언질을 안 주셨잖아요." 결론: tsconfig.json을 먼저 만드는 것은 컴퓨터에게 "지금부터 우리는 최신 유행어(ESM)와 엄격한 문법(TypeScript)으로 대화할 거야. 준비해." 라고 선전포고를 하는 것입니다. 이 합의가 없으면 단 한 줄의 코드도 실행되지 않습니다.

1-3. 🛠️ [실전 가이드] tsconfig.json 설정: 새로운 나라의 헌법 제정 "Moltbot은 대형 프로젝트라서 이미 설정이 다 되어있지만, 맨땅에서 시작하는 나만의 작은 앱은 어떻게 시작하나요?"

  1. 은유(Metaphor): 새로운 국가를 세울 때의 "헌법 제정"

백지에 그림을 그리는 것과 같습니다. 나라를 처음 세울 때, 우리 국민은 어떤 언어를 쓰고(Target), 주변 나라와는 어떻게 소통하며(Module), 범죄(Error)에는 얼마나 엄격할 것인지(Strict)를 정하는 **'국가 헌법'**을 만드는 과정이 바로 tsconfig.json 초기화입니다. 헌법이 모호하면 나라가 혼란에 빠지듯, 이 설정이 부실하면 개발 과정 내내 충돌이 일어납니다.

  1. 개념(Concept): 초기화의 두 가지 경로 (자동 vs 실전)

TypeScript는 개발자가 처음부터 고생하지 않도록 **'표준 헌법 초안'**을 자동으로 생성해주는 도구(npx tsc --init)를 제공합니다. 초보자는 자동 생성된 초안에서 시작하고, 숙련자는 프로젝트의 목적(고성능 서버, 프론트엔드 등)에 맞춰 그 초안을 수정하여 사용합니다.

  1. 코드(Code): 헌법의 탄생과 핵심 3조항

방법 A: 표준 초안 자동 생성 (권장)

연재 2회에서 사용하던 터미널 창을 그대로 사용하세요. 다음 명령어를 입력하면 수중한 주석과 함께 설정 파일이 생성됩니다.

npx tsc --init 방법 B: 실전 프로젝트 핵심 설정 (수동 수정)

자동 생성된 파일에서 아래 **'핵심 3개 조항'**만은 반드시 확인하고 수정해 주세요.

{ "compilerOptions": { "target": "ES2022", // [제1조] 사용할 언어의 문법 수준 (최신 사투리 인정) "module": "NodeNext", // [제2조] 소통 규약 (최신 스마트폰 규격 사용) "strict": true // [제3조] 법 집행의 엄격함 (무관용 원칙) } 4. 배경 및 실전 가이드(Context & Guide): 왜 이 3가지인가?

왜 target: ES2022인가? : 과거에는 구식 브라우저를 위해 코드를 어렵게 번역해야 했습니다. 하지막 지금 우리가 만드는 서버(Node.js 22)는 똑똑합니다. 최신 문법을 그대로 써야 속도가 빠르고 코드가 깔끔해집니다.

왜 module: NodeNext인가? : 자바스크립트 세계는 지금 '구식(CommonJS)'과 '신식(ESM)'이 교체되는 과도기입니다. NodeNext는 "우리는 신식을 쓰되, 구식도 알아듣겠다"는 가장 현명한 중재안입니다.

왜 strict: true인가? : "대충 짜고 나중에 고치지 뭐"라는 생각은 개발자의 가장 큰 착각입니다. 처음부터 엄격하게 관리하는 것이, 나중에 버그를 찾느라 밤을 새우는 것보다 100배 경제적입니다.

TIP 요약: 작은 프로젝트라도 npx tsc --init으로 시작하고, Target(최신), Module(NodeNext), Strict(True) 이 세 가지만 기억하세요. 이것만으로도 여러분의 프로젝트는 구글이나 메타(Facebook) 부럽지 않은 튼튼한 기초를 갖추게 됩니다.

1-3-1. TypeScript 설정 (tsconfig.json) - 아키텍처 심층 분석

  1. 은유(Metaphor): 건물의 설계 규격과 "헌법(憲法)"

아파트 단지를 지을 때, 모든 건물의 자재 규격이 같아야 하고 배선은 통일된 규칙을 따라야 합니다. tsconfig.json은 이 프로젝트가 어떤 규칙으로 지어지고, 최종적으로 어떤 결과물(JavaScript)로 번역될지를 정하는 최상위 법전이자 설계 도면입니다. 이 도면이 틀리면 아무리 코드를 잘 짜도 집이 무너집니다.

  1. 개념(Concept): TypeScript 컴파일러 설정 안내서

이 파일은 tsc(컴파일러)에게 "이 프로젝트의 소스 코드는 여기에 있고, 번역된 결과물은 저기에 저장하고, 번역할 때는 이런 규칙을 지켜줘!"라고 상세히 지시하는 메뉴얼입니다. 단순한 설정 파일이 아니라, 프로젝트의 **정체성(ESM vs CJS)**을 결정짓는 핵심 문서입니다.

outDir (dist): 번역가 끝난 문서(결과물)를 차곡차곡 쌓아두는 '출고 창고'입니다. rootDir (src): 번역가가 작업해야 할 원본 원고가 들어있는 '원고 보관함'입니다. esModuleInterop : 서로 다른 통신 규격(ESM과 CJS)을 쓰는 부품들이 대화할 수 있게 해주는 '유니버설 어댑터'입니다. skipLibCheck: "이미 검증된 외부 서적까지 일일이 오타 검사를 하느라 시간을 낭비하지 않겠다"는 '검수 생략' 조항입니다.

  1. 코드(Code): 원본 tsconfig.json

{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src", "strict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, "resolveJsonModule": true, "noEmitOnError": true, "allowSyntheticDefaultImports": true

}, "include": ["src//*"], "exclude": [ "node_modules", "dist", "src//.test.ts", "src/**/.test.tsx", "src/**/test-helpers.ts" ] }