TypeScript Compile Process

์‹ ํƒœ์ผยท2024๋…„ 10์›” 16์ผ

๐Ÿ’ก ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์‹คํ–‰๋˜๊ธฐ๊นŒ์ง€์˜ ๊ณผ์ •์€ ํฌ๊ฒŒ Compile, Bundle, Deploy 3๋ฒˆ์˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฑฐ์นœ๋‹ค. ํ•œ ๋ฒˆ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™๋˜๋Š”์ง€ ํ•œ ๋ฒˆ ํ†บ์•„๋ณด์ž!

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ AST(Abstract Syntax Tree)


์šฐ์„  ๋ชจ๋“  ์ปดํŒŒ์ผ ๊ณผ์ •์˜ ๊ธฐ์ค€์ด ๋  ์ถ”์ƒ ๊ตฌ๋ฌธ ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค. ์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์ด ๋  ๋‘ ๊ฐ€์ง€๋Š” Scanner์™€ Parser์ด๋‹ค.

์ด๋“ค์€ ์ปดํŒŒ์ผ ๊ณผ์ •์— ๊ฐ ๊ตฌ๋ฌธ์„ ํ† ํฐ์œผ๋กœ ์ถ”์ถœํ•˜์—ฌ AST๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ๊นŒ์ง€์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ถ”์ƒ ๊ตฌ๋ฌธ ํŠธ๋ฆฌ (Abstract Syntax Tree)๋Š” ์†Œ์Šค ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒ๋˜๋Š” ๊ตฌ์กฐ๋ฅผ ํŠธ๋ฆฌ ํ˜•์‹์œผ๋กœ ๋‚˜ํƒ€๋‚ธ ๊ฒƒ์ด๋‹ค. ์ž์„ธํ•œ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์ถ”์ƒ์ ์ธ ๊ตฌ๋ฌธ์œผ๋กœ ๋‚˜ํƒ€๋‚ธ ํŠธ๋ฆฌ๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ๊ตฌ๋ฌธ ํŠธ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋ฉด ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ถ„์„, ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ํ•œ๋‹ค.

๋จผ์ € Scanner๊ฐ€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ์ž…๋ ฅ๋œ ์ฝ”๋“œ ๋ฌธ์ž์—ด์„ ๊ฐ๊ฐ ์˜ˆ์•ฝ์–ด, ์ฝœ๋ก , ๋ถ€ํ˜ธ ๋“ฑ์˜ ํ† ํฐ์œผ๋กœ ๋ถ„๋ฆฌ์‹œํ‚ค๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์œ„ ๊ทธ๋ฆผ์˜ Tokens๋Š” Scanner๋ฅผ ํ†ตํ•ด ๋ถ„๋ฆฌ๋œ ๊ฐ„๋‹จํ•œ ํ† ํฐ๋“ค์„ ๋ณด์—ฌ์ค€๋‹ค. (์ด ๊ณผ์ •์€ tokenizer๋ผ๊ณ  ํ•œ๋‹ค.)

Parser๋Š” Scanner๊ฐ€ ๋ถ„๋ฆฌํ•ด์ค€ ํ† ํฐ์„ ๊ตฌ๋ฌธ์˜ ๊ตฌ์กฐ์— ๋”ฐ๋ผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์ฝ”๋“œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ๋ฌธ๋ฒ•์ธ์ง€ ๋ถ„์„ํ•˜์—ฌ ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๋ฅผ ์žก์•„๋‚ด๋Š” ์—ญํ• ๋„ ๋งก๊ณ  ์žˆ๋‹ค.

ํƒ€์ž… ๊ฒ€์‚ฌ


ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๊ฐ€์žฅ ํฐ ์—ญํ• ์„ ํ•˜๋Š” ํƒ€์ž…๊ฒ€์‚ฌ ๋‹จ๊ณ„์ด๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ๋Š” binder, type system์˜ ํ•ต์‹ฌ์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋Š” type checker๊ฐ€ ๋“ฑ์žฅํ•œ๋‹ค.

Binder๋Š” ์ „์ฒด AST๋ฅผ ์ฝ์–ด์„œ ํƒ€์ž… ๊ฒ€์‚ฌ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๊ณผ์ •์ด๋‹ค. ๊ฐ ์˜์—ญ ๋ณ„๋กœ identifier๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ  ์‹๋ณ„์ž๊ฐ€ ์–ด๋А ์œ„์น˜์— ์ •์˜๋˜์—ˆ๋Š”์ง€ ์–ด๋–ค ํ”Œ๋ž˜๊ทธ๋ฅผ ์ ์šฉํ•  ๊ฒƒ์ธ์ง€ ์„ ํƒํ•˜์—ฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค. ์ด๋ ‡๊ฒŒ ์„ค์ •๋œ Symbol: primary building block of the TypeScript semantic system์€ symbol table์— HashMap์œผ๋กœ ์ €์žฅ๋œ๋‹ค. ์ด๋Š” ์ดํ›„ ๋‹จ๊ณ„์—์„œ ์ฝ”๋“œ ๋ถ„์„์„ ์ง„ํ–‰ํ•  ๋•Œ ๊ธฐ์ค€์ด ๋œ๋‹ค. ์•„๋ž˜๋Š” ํ•จ์ˆ˜์™€ ๋ณ€์ˆ˜๋ฅผ symbol๋กœ ๊ฐ„๋‹จํžˆ ํ‘œํ˜„ํ•˜๊ณ  ์žˆ๋‹ค.

functionName
FunctionDeclaration
Flags: Function

variableName
VariableDeclaration
Flags: BlockScopedVariable

๋˜ํ•œ binder๋Š” Flow nodes๋กœ ๋ณ€์ˆ˜๋ฅผ ์ถ”์ ํ•œ๋‹ค.

์ฝ”๋“œ์˜ ๋ถ„๊ธฐ์ ์ด ๋˜๋Š” ํ๋ฆ„ ์กฐ๊ฑด๋ถ€, ์ฆ‰ Flow Conditional์„ ๊ธฐ์ค€์œผ๋กœ ์˜์—ญ์„ ์ •ํ•˜์—ฌ Flow Container๋ฅผ ์ง€์ •ํ•œ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ๊ฒ€์‚ฌํ•  ๋…ธ๋“œ๋กœ๋ถ€ํ„ฐ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ์ฐพ์•„๊ฐ€๋ฉฐ ์—ญ๋ฐฉํ–ฅ์œผ๋กœ ์ฐพ์•„๊ฐ€๋ฉฐ ๋ณ€์ˆ˜์™€ ํƒ€์ž…์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜๋Š” Typescript Playground์—์„œ ์ง€์›ํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ํ™•์ธํ•œ Flow Graph์ด๋‹ค.

TypeChecker๋Š” ์œ„์—์„œ ๋งŒ๋“ค์–ด ๋‚ธ AST์™€ Symbols table์„ ๊ธฐ์ค€์œผ๋กœ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์‹œํ–‰ํ•œ๋‹ค. ๊ฒ€์‚ฌ๋Š” ๊ตฌ์กฐ์ ์œผ๋กœ ์ด๋ฃจ์–ด ์ง€๋ฉฐ ์™ธ๋ถ€์—์„œ ๋‚ด๋ถ€๋กœ ์ง„ํ–‰๋œ๋‹ค. ๋จผ์ € ์ด ๊ฐ’์ด object ํ˜•ํƒœ์ธ์ง€, ๋‹ค์Œ์€ ํ•„๋“œ, ๋งˆ์ง€๋ง‰์œผ๋กœ๋Š” ๊ฐ’์˜ ํƒ€์ž…์ด ์ผ์น˜ํ•˜๋Š”์ง€ ๋น„๊ตํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•˜๋Š” ํŠน์ง•์„ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๊ตฌ์กฐ์  ํƒ€์ดํ•‘์ด๋ผ๊ณ  ํ•œ๋‹ค.

{ age: number } = { age: 'nextree' }

์œ„์™€ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ๊ฐ’์„ ๋น„๊ตํ•  ๋•Œ, TypeFlags.NumberLike์™€ โ€˜nextreeโ€™๋Š” TypeFlags.StringLiteral์ด๋ฏ€๋กœ false๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด๋‹ค.

์ด ๋น„๊ต๋Š” TypeFlags๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด Enum์€ Typescript ํŒŒ์ผ์˜ /src/compiler/types.ts์— ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉฐ, ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ํƒ€์ž…์„ ์ง€์ •ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ์— AST์˜ initializer์˜ ๊ฒฐ๊ณผ ๊ฐ’(โ€™Hello world!โ€™)์˜ ํƒ€์ž…์„ message์˜ type ์‹ ํ…์Šค๋กœ ๋Œ€์ž…ํ•œ๋‹ค.

const message = 'Hello World!';

transform


ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” compile Option์ด ํ•„์š”ํ•˜๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ์˜ต์…˜๋“ค์„ tsConfig.json ํŒŒ์ผ๋กœ ๊ด€๋ฆฌํ•  ๊ฒƒ์ด๋‹ค.

{
  "compilerOptions": {
    "module": "system",		// TSC๊ฐ€ ์ปดํŒŒ์ผํ•  ๋Œ€์ƒ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ
    "outDir": "dist",		// ์ƒ์„ฑ๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋””๋ ‰ํ„ฐ๋ฆฌ
    "target": "es2015",		// ์ปดํŒŒ์ผ ํ•  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฒ„์ „
  },
  "include": ["src/**/*"],  // typescript ๊ฐ€ ์ฐพ์„ ๋””๋ ‰ํ„ฐ๋ฆฌ
}

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—๋Š” AST๋ฅผ ํŒŒ์ผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋Š” emmiter๊ฐ€ ์žˆ๋‹ค. emitter์—๋Š” ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋Š”๋ฐ ์—ญํ• ๋กœ ๋‚˜๋ˆˆ ๊ฐ„๋‹จํ•œ ๋น„๊ต๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

emitter.tsdeclarationEmitter.ts
js code.d.ts code

emitter๋Š” AST์™€ Checker๋ฅผ ํ†ตํ•ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค.

๋จผ์ € ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ AST๋ฅผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ AST๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ AST์—์„œ ํƒ€์ž…์„ ๋‚˜ํƒ€๋‚ด๋Š” keyword ์‹ ํ…์Šค๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ณผ์ •์ด๋ผ๊ณ  ๋ง ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ ํ›„, ๊ฐ ๋ฌธ๋ฒ• ๋ฒ„์ „์— ๋”ฐ๋ผ Asset flag๋ฅผ ์ง€์ •ํ•œ๋‹ค. transformer๋Š” ์ด๋ ‡๊ฒŒ Asset, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•œ ํ›„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ(.js)๋ฅผ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค. ๋˜ํ•œ ํƒ€์ž…๋งŒ ์ •์˜ํ•ด ๋†“์€ type definition(.d.ts) ํŒŒ์ผ๋„ ํ•จ๊ป˜ ์ƒ์„ฑํ•œ๋‹ค.

// es2015 Asset
const message: string = โ€˜Hello worldโ€™;  // typescript code
console.log(message);                   // javascript code

// ์ƒ์„ฑ๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ
"use strict";
const message = 'Hello world';
console.log(message);

// ์ƒ์„ฑ๋œ DTS ์ฝ”๋“œ
declare const message: string;

์ด .d.tsํŒŒ์ผ์€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋งŒ๋“ค์–ด ๋‚ด๊ธฐ๋„ ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ์ด๋‹ค. ์ด ํŒŒ์ผ๋กœ ๋ณ€์ˆ˜ ์œ ํ˜•์„ ์ง€์ •ํ•ด ๋†“์œผ๋ฉด, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” .d.tsํŒŒ์ผ์„ ์ด์šฉํ•ด ํƒ€์ž… ์ถ”๋ก ์— ์ฐธ๊ณ ํ•œ๋‹ค.

profile
๋…ธ์›๊ฑฐ์ธ

0๊ฐœ์˜ ๋Œ“๊ธ€