Node 개념 찾아보기
짧은 예제에서 만난 언어·실행 환경·모듈·npm·파일·타입 개념을 확인합니다.
실습 중 필요한 부분만 읽는다. 처음부터 모두 외우지 않는다. 코드 속 입력·출력은 ASCII로 통일하고, 한글과 바이트 변환은 다음 통신 단원에서 다룬다.
1. 언어와 실행 환경
| 언어 | 실행 환경·구현체 예 |
|---|---|
| JavaScript | 브라우저의 JavaScript 환경, Node.js |
| Python | CPython |
| Java | 컴파일된 바이트코드를 실행하는 JVM |
JavaScript·Python·Java는 프로그래밍 언어다. Node.js는 다른 언어가 아니라 JavaScript 실행 환경이다. npm은 패키지와 실행 명령을 관리하는 도구다. TypeScript는 JavaScript에 타입 문법을 더하고 검사 도구를 제공한다. 위 표는 역할을 비교하며 내부 구조가 같다는 뜻은 아니다.
2. 같은 언어, 다른 API
변수·함수·배열·객체·Promise는 JavaScript 기능이다. document로 웹 페이지를 다루거나 node:fs로 파일을 다루는 기능은 환경이 제공한다.
console.log(typeof document);Node에서는 undefined가 나온다. typeof로 확인하므로 없는 이름을 직접 사용하는 오류는 발생하지 않는다. 브라우저에서도 파일 관련 기능이 있지만 Node와 API와 권한이 다르다.
3. 파일과 프로세스
코드는 파일에 저장되어 있다. node 01-runtime/hello.mjs Sam을 실행하면 Node가 코드를 읽어 실행한다. 실행 중인 프로그램은 운영체제에서 프로세스로 관리한다.
프로그램이 종료되어도 코드 파일은 남는다. 코드를 바꾼 후 다시 실행해야 새 내용을 확인할 수 있다.
4. 인자와 경로
process.argv는 실행 명령의 인자 배열이다. 이 수업의 직접 실행에서 첫 항목은 Node 실행 파일, 두 번째는 코드 파일, 그 뒤가 우리가 전달한 값이다.
node 01-runtime/hello.mjs Samprocess.argv[2]는 문자열 Sam이다. 인자로 7을 써도 처음에는 문자열이다.
| 상대 경로 | 기준 |
|---|---|
터미널의 cd | 현재 작업 폴더 |
import "./notes.mjs" | import를 쓴 코드 파일의 위치 |
writeFile("notes.txt", text) | 현재 작업 폴더 |
이번 파일 예제는 단원 루트에서 실행한다. 파일 경로를 자동으로 조정하는 보조 코드는 없다.
5. 함수·객체·배열
function formatNote(note) {
return `${note.id}. ${note.text}`;
}
const note = { id: 1, text: "Hello" };
console.log(formatNote(note));객체가 입력으로 들어가고 문자열이 반환된다. return은 호출한 곳으로 값을 돌려준다. console.log는 관찰할 출력을 만든다.
const notes = [
{ id: 1, text: "Learn JavaScript" },
{ id: 2, text: "Run with Node" },
];객체는 한 항목의 속성, 배열은 여러 항목을 표현한다. for...of로 객체를 하나씩 꺼내 함수에 전달할 수 있다.
6. 모듈 세 종류
./notes.mjs: 직접 작성한 파일의 상대 경로.node:fs/promises: Node에 포함된 내장 모듈.lesson-label: 설치 후 패키지 이름으로 가져오는 모듈.
export로 내보내고 import로 가져온다. 모든 import에 npm 설치가 필요한 것은 아니다. .mjs는 ESM 모듈 형식으로 해석된다.
7. package.json은 왜 필요한가?
JavaScript 파일 하나는 package.json 없이 실행할 수 있다. 프로젝트의 명령과 의존성을 함께 공유하려면 기록할 곳이 필요하다.
| 필드 | 역할 |
|---|---|
name | 프로젝트·패키지 이름 |
private | npm에 실수로 게시하는 것을 막음, 소스를 숨기는 설정은 아님 |
type: module | 해당 범위의 .js를 ESM으로 해석 |
scripts | 실행 명령에 붙인 이름 |
dependencies | 실행 코드에서 사용하는 패키지 |
devDependencies | 타입 검사 등 개발에 사용하는 도구 |
package.json은 JSON 문법이다. 주석이나 불필요한 마지막 쉼표를 넣지 않는다. .mjs는 type 필드 없이도 ESM이다.
8. npm run은 등록된 명령을 실행한다
{
"scripts": {
"hello": "node 01-runtime/hello.mjs"
}
}npm run hello -- Sam은 등록한 명령 뒤에 Sam을 전달한다. dev·build라는 이름에 고정된 기능이 있는 것은 아니다. 이 자료에는 dev가 없으므로 실제 scripts를 읽어야 한다.
9. 설치와 공유
package.json: 필요한 의존성을 선언한다.package-lock.json: 구체적인 버전과 의존성 구조를 기록한다.node_modules: 설치된 코드 또는 로컬 패키지 연결이 놓인다.
의존성을 추가·변경할 때 npm install, 받은 프로젝트의 잠금 파일대로 새로 설치할 때 npm ci를 사용한다. npm ci는 package.json과 잠금 파일이 맞지 않으면 실패한다.
lesson-label은 file:03-package/lesson-label로 연결하는 로컬 수업 패키지다. TypeScript와 @types/node는 레지스트리에서 설치한다. @types/node는 Node의 API 타입 정보이며 Node 자체를 설치하는 패키지가 아니다.
소스와 설정·잠금 파일·로컬 패키지는 공유한다. node_modules와 dist는 각각 설치와 빌드로 만든다. notes.txt·notes.json은 개인별 연습 파일이므로 배포물에서 제외한다.
10. 이벤트와 비동기는 같은 말일까?
이벤트는 일이 발생했을 때 실행할 함수를 등록하는 방식이다. on으로 등록한 뒤 emit으로 발생시킨다. 이번 EventEmitter의 리스너는 emit을 호출하는 동안 동기적으로 실행된다.
비동기는 결과가 나중에 준비되는 작업의 완료를 다루는 방식이다. 이벤트를 사용했다고 반드시 비동기로 실행되는 것은 아니다. 이후 소켓의 data는 네트워크 데이터가 도착할 때 발생한다.
fn은 함수 값이고 fn()은 그 함수를 호출하는 표현이다. 콜백·리스너·핸들러는 함수가 전달되는 방식·등록된 자리·맡은 역할을 각각 설명하는 말이며, 같은 함수에 겹쳐 쓸 수 있다. 대리자·코루틴·스레드까지 더 넓은 비교는 선택 · 실행 용어 지도에서 필요할 때 찾아본다.
11. Promise와 await
Promise는 작업의 완료 또는 실패를 다루는 객체다. await 뒤의 코드는 결과가 준비된 후 이어진다. 전체 프로세스의 모든 일을 멈추는 명령은 아니다.
order.mjs에서 await를 제거하면 result는 결과 문자열이 아니라 Promise다. 이미 시작한 타이머가 취소되는 것은 아니다.
12. 파일 쓰기와 읽기
import { writeFile } from "node:fs/promises";
await writeFile("notes.txt", "Hello Node");
console.log("Saved");쓰기 작업이 완료된 후 Saved를 출력한다. 다음 프로세스가 파일을 읽어도 같은 문장이 남는다. 동일한 파일에 다시 쓰면 덮어쓴다.
읽기의 "utf8" 옵션은 바이트를 문자열로 읽게 한다. ASCII 문자는 UTF-8에서도 같은 한 바이트로 표현되므로 여기서는 문자열 읽기에만 집중한다. 한글을 넣었을 때 글자 수와 바이트 수가 다른 이유는 통신 단원에서 별도로 확인한다.
13. JSON: 객체와 텍스트 사이
객체 배열 → JSON.stringify → 텍스트 → 파일
파일 → 텍스트 → JSON.parse → 값JSON은 객체 자체가 아니라 데이터를 표현하는 텍스트 형식이다. JSON.parse는 JSON 문법을 해석하지만 원하는 객체 구조인지까지 확인해 주지는 않는다.
이 단계에서는 우리가 만든 배열을 그대로 저장하고 읽는다. 명령 파서·폴더 생성·자동 복구·입력 검증은 추가하지 않는다.
14. 오류 메시지를 읽기
파일이 없을 때 readFile은 실패한다. 이 예제는 실패를 잡지 않으므로 오류가 그대로 표시된다. 오류 읽기는 지금도 연습하고, 복구 기능의 구현은 나중에 한다.
- 현재 폴더와 실행 명령을 확인한다.
- 오류 종류와 파일·줄을 찾는다.
- 원인 한 가지를 고친다.
- 다시 실행해 결과를 확인한다.
15. TypeScript: 값의 모양을 검사하기
type Note = { id: number; text: string };
function formatNote(note: Note): string {
return `${note.id}. ${note.text}`;
}숫자 id와 문자열 text가 필요하다는 약속을 표현한다. TS는 이 약속과 코드의 사용이 맞는지 검사한다. 배열·고급 타입·입력 검증을 모두 한 번에 추가할 필요는 없다.
16. 검사·변환·실행
| 명령 | 역할 |
|---|---|
npm run typecheck | 타입 검사, 파일 생성 없음 |
npm run build | 타입 검사 후 JavaScript 생성 |
npm run typed | 생성한 JavaScript를 Node로 실행 |
타입 표기는 생성된 JS에서 사라진다. 이번 수업은 tsc로 변환한 후 Node로 실행하는 경로 하나를 사용한다.
tsconfig.json의 rootDir·outDir는 소스·출력 위치, strict는 엄격한 검사, noEmitOnError는 오류가 있을 때 새 출력을 만들지 않는 설정이다. 과거 dist가 자동 삭제되는 것은 아니므로 빌드 성공 여부를 확인한다.
17. 선택: 타입 단언은 변환이 아니다
const value = JSON.parse("42") as string;실제 값은 숫자 42다. as string은 타입 검사기에게 하는 단언이며 값을 문자열로 바꾸지 않는다. toUpperCase()를 호출하면 TypeError가 난다.
safe-input.ts는 unknown으로 받고 typeof로 한 가지 조건만 확인한다. 이번 단원의 핵심은 타입 검사와 실행을 구분하는 것까지다. 다양한 입력의 검증은 나중에 요구사항을 정해 AI 코딩으로 확장한다.
18. 다음으로
파일에 쓰던 Hello를 다른 컴퓨터로 보내 본다. 같은 JavaScript로도 어떤 API를 사용하는지에 따라 파일·네트워크·화면을 다루게 된다.
공식 참고 자료
실행용 버전은 이 단원의 package.json·잠금 파일을 기준으로 한다.