๋ฉ”์ธ ์ฝ˜ํ…์ธ ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
TypeScript ์†Œ์Šค ๋งต์„ ํ™œ์šฉํ•œ ํšจ๊ณผ์ ์ธ ๋””๋ฒ„๊น… ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

์†Œ์Šค ๋งต์ด๋ž€?

์†Œ์Šค ๋งต(Source Map)์€ ์ปดํŒŒ์ผ๋œ JavaScript ์ฝ”๋“œ๋ฅผ ์›๋ณธ TypeScript ์ฝ”๋“œ๋กœ ๋งคํ•‘ํ•˜๋Š” ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค์™€ ๋””๋ฒ„๊ฑฐ์—์„œ ์›๋ณธ TypeScript ์ฝ”๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ™œ์šฉ:
  • ์—๋Ÿฌ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค์—์„œ ์›๋ณธ TypeScript ์œ„์น˜ ํ™•์ธ
  • ๋””๋ฒ„๊ฑฐ์—์„œ TypeScript ์ฝ”๋“œ์— ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ์„ค์ •
  • ํ”„๋กœ๋•์…˜ ์—๋Ÿฌ๋ฅผ ์›๋ณธ ์ฝ”๋“œ์™€ ๋งคํ•‘

์†Œ์Šค ๋งต ํ™œ์„ฑํ™”

tsconfig.json ์„ค์ •

{
  "compilerOptions": {
    "sourceMap": true,           // ์†Œ์Šค ๋งต ์ƒ์„ฑ
    "inlineSourceMap": false,    // ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ƒ์„ฑ
    "inlineSources": false,      // ์›๋ณธ ์†Œ์Šค ํฌํ•จ ์•ˆ ํ•จ
    "outDir": "dist"
  }
}
์ƒ์„ฑ๋˜๋Š” ํŒŒ์ผ:
๐Ÿ“dist/
๐Ÿ“„JSindex.js
๐Ÿ“„MAPindex.js.map - ์†Œ์Šค ๋งต ํŒŒ์ผ
๐Ÿ“models/
๐Ÿ“„JSuser.model.js
๐Ÿ“„MAPuser.model.js.map

inlineSourceMap vs sourceMap

// โœ… ๊ถŒ์žฅ: ๋ณ„๋„ ํŒŒ์ผ (๊ฐœ๋ฐœ/ํ”„๋กœ๋•์…˜ ๋ชจ๋‘)
{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSourceMap": false
  }
}

// โŒ ์ธ๋ผ์ธ (๋ฒˆ๋“ค ํฌ๊ธฐ ์ฆ๊ฐ€)
{
  "compilerOptions": {
    "sourceMap": false,
    "inlineSourceMap": true  // .js ํŒŒ์ผ ๋‚ด ํฌํ•จ
  }
}

์—๋Ÿฌ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค

์†Œ์Šค ๋งต ์—†์ด

Error: User not found
    at UserModelClass.findById (dist/models/user.model.js:45:15)
    at processUser (dist/services/user.service.js:12:28)
    at async main (dist/index.js:8:20)
์ปดํŒŒ์ผ๋œ JavaScript ์œ„์น˜๋งŒ ํ‘œ์‹œ๋˜์–ด ๋””๋ฒ„๊น…์ด ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์†Œ์Šค ๋งต ์žˆ์„ ๋•Œ

Error: User not found
    at UserModelClass.findById (src/models/user.model.ts:32:11)
    at processUser (src/services/user.service.ts:8:24)
    at async main (src/index.ts:5:15)
์›๋ณธ TypeScript ํŒŒ์ผ๊ณผ ๋ผ์ธ ๋ฒˆํ˜ธ๋ฅผ ์ •ํ™•ํžˆ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

Node.js์—์„œ ์†Œ์Šค ๋งต ์‚ฌ์šฉ

โ€”enable-source-maps ํ”Œ๋ž˜๊ทธ

# Node.js 12.12.0 ์ด์ƒ
node --enable-source-maps dist/index.js
๋˜๋Š” package.json:
{
  "scripts": {
    "start": "node --enable-source-maps dist/index.js",
    "dev": "node --enable-source-maps --watch dist/index.js"
  }
}

tsx ์‚ฌ์šฉ (๊ถŒ์žฅ)

# tsx๋Š” ์ž๋™์œผ๋กœ ์†Œ์Šค ๋งต ์ง€์›
pnpm dev
Sonamu๋Š” tsx๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋ณ„๋„ ์„ค์ • ์—†์ด ์†Œ์Šค ๋งต์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

VSCode ๋””๋ฒ„๊ฑฐ ์„ค์ •

launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Sonamu Dev Server",
      "runtimeExecutable": "pnpm",
      "runtimeArgs": ["dev"],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal",
      "sourceMaps": true,
      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
      "skipFiles": [
        "<node_internals>/**",
        "node_modules/**"
      ]
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Run Test",
      "runtimeExecutable": "pnpm",
      "runtimeArgs": ["test", "${file}"],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal",
      "sourceMaps": true
    }
  ]
}

๋””๋ฒ„๊น… ๋‹จ๊ณ„

  1. ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ์„ค์ •
    • TypeScript ํŒŒ์ผ(.ts)์—์„œ ์ค„ ๋ฒˆํ˜ธ ์™ผ์ชฝ ํด๋ฆญ
  2. ๋””๋ฒ„๊ฑฐ ์‹œ์ž‘
    • F5 ๋˜๋Š” โ€œRun and Debugโ€ ํŒจ๋„์—์„œ ์‹คํ–‰
  3. ๋ณ€์ˆ˜ ๊ฒ€์‚ฌ
    • ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ์—์„œ ๋ฉˆ์ถ”๋ฉด ๋ณ€์ˆ˜ ๊ฐ’ ํ™•์ธ
    • Watch ํŒจ๋„์—์„œ ํ‘œํ˜„์‹ ํ‰๊ฐ€
  4. ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰
    • F10: Step Over (๋‹ค์Œ ์ค„)
    • F11: Step Into (ํ•จ์ˆ˜ ๋‚ด๋ถ€๋กœ)
    • Shift+F11: Step Out (ํ•จ์ˆ˜ ๋ฐ–์œผ๋กœ)

ํ”„๋กœ๋•์…˜ ์†Œ์Šค ๋งต

๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSources": false  // ์›๋ณธ ์†Œ์Šค ํฌํ•จ ์•ˆ ํ•จ
  }
}
ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์‹œ:
# ์†Œ์Šค ๋งต ํŒŒ์ผ ์ œ์™ธ
dist/
โ”œโ”€โ”€ index.js           โœ… ๋ฐฐํฌ
โ”œโ”€โ”€ index.js.map       โŒ ์ œ์™ธ (๋˜๋Š” ๋ณ„๋„ ์ €์žฅ)

์—๋Ÿฌ ์ถ”์  ์„œ๋น„์Šค ์—ฐ๋™

์†Œ์Šค ๋งต์„ Sentry ๊ฐ™์€ ์—๋Ÿฌ ์ถ”์  ์„œ๋น„์Šค์— ์—…๋กœ๋“œ:
# Sentry CLI ์˜ˆ์‹œ
sentry-cli releases files VERSION upload-sourcemaps ./dist

์†Œ์Šค ๋งต ๋ฌธ์ œ ํ•ด๊ฒฐ

1. ์†Œ์Šค ๋งต์ด ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ

ํ™•์ธ ์‚ฌํ•ญ:
# tsconfig.json ํ™•์ธ
cat tsconfig.json | grep sourceMap

# ๋นŒ๋“œ ํ›„ .map ํŒŒ์ผ ํ™•์ธ
ls -la dist/**/*.map
ํ•ด๊ฒฐ:
{
  "compilerOptions": {
    "sourceMap": true  // ๋ช…์‹œ์ ์œผ๋กœ ํ™œ์„ฑํ™”
  }
}

2. ์Šคํƒ ํŠธ๋ ˆ์ด์Šค๊ฐ€ ์—ฌ์ „ํžˆ .js ํŒŒ์ผ์„ ๊ฐ€๋ฆฌํ‚ด

์›์ธ: Node.js๊ฐ€ ์†Œ์Šค ๋งต์„ ์ธ์‹ํ•˜์ง€ ๋ชปํ•จ ํ•ด๊ฒฐ:
# --enable-source-maps ํ”Œ๋ž˜๊ทธ ์ถ”๊ฐ€
node --enable-source-maps dist/index.js

# ๋˜๋Š” tsx ์‚ฌ์šฉ (์ž๋™ ์ง€์›)
pnpm tsx dist/index.js

3. VSCode ๋””๋ฒ„๊ฑฐ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š์Œ

ํ™•์ธ ์‚ฌํ•ญ:
// launch.json
{
  "sourceMaps": true,  // ํ™œ์„ฑํ™” ํ™•์ธ
  "outFiles": [
    "${workspaceFolder}/dist/**/*.js"  // ์˜ฌ๋ฐ”๋ฅธ ๊ฒฝ๋กœ
  ]
}
ํ•ด๊ฒฐ:
  1. .vscode/launch.json ์žฌ์„ค์ •
  2. TypeScript ์„œ๋ฒ„ ์žฌ์‹œ์ž‘: Cmd+Shift+P โ†’ โ€œTypeScript: Restart TS Serverโ€
  3. ๋””๋ฒ„๊ฑฐ ์žฌ์‹œ์ž‘

4. ์ž˜๋ชป๋œ ๋ผ์ธ ๋ฒˆํ˜ธ

์›์ธ: ์†Œ์Šค ๋งต๊ณผ ์ฝ”๋“œ๊ฐ€ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์Œ ํ•ด๊ฒฐ:
# ํด๋ฆฐ ๋นŒ๋“œ
rm -rf dist/
pnpm build

# ๋˜๋Š” ๊ฐœ๋ฐœ ๋ชจ๋“œ ์žฌ์‹œ์ž‘
pnpm dev

์†Œ์Šค ๋งต ๊ฒ€์ฆ

์ˆ˜๋™ ๊ฒ€์ฆ

# ์†Œ์Šค ๋งต ํŒŒ์ผ ํ™•์ธ
cat dist/index.js.map | jq .sources

# ์ถœ๋ ฅ ์˜ˆ์‹œ:
# [
#   "../src/index.ts",
#   "../src/models/user.model.ts"
# ]

source-map ํŒจํ‚ค์ง€๋กœ ๊ฒ€์ฆ

import { SourceMapConsumer } from "source-map";
import fs from "fs";

const rawSourceMap = JSON.parse(
  fs.readFileSync("dist/index.js.map", "utf-8")
);

SourceMapConsumer.with(rawSourceMap, null, (consumer) => {
  // ์ปดํŒŒ์ผ๋œ ์œ„์น˜ -> ์›๋ณธ ์œ„์น˜
  const pos = consumer.originalPositionFor({
    line: 45,
    column: 15
  });
  
  console.log(pos);
  // {
  //   source: '../src/index.ts',
  //   line: 32,
  //   column: 11,
  //   name: 'findUser'
  // }
});

๋ธŒ๋ผ์šฐ์ €์—์„œ ์†Œ์Šค ๋งต

Vite ๊ฐœ๋ฐœ ์„œ๋ฒ„

Vite๋Š” ์ž๋™์œผ๋กœ ์†Œ์Šค ๋งต์„ ์ƒ์„ฑํ•˜๊ณ  ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:
// vite.config.ts
export default defineConfig({
  build: {
    sourcemap: true  // ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—๋„ ํฌํ•จ
  }
});

Chrome DevTools

  1. ์†Œ์Šค ํƒญ ์—ด๊ธฐ
    • F12 โ†’ Sources ํƒญ
  2. TypeScript ํŒŒ์ผ ํ™•์ธ
    • webpack:// ๋˜๋Š” src/ ์•„๋ž˜ .ts ํŒŒ์ผ
  3. ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ์„ค์ •
    • TypeScript ํŒŒ์ผ์—์„œ ์ค„ ๋ฒˆํ˜ธ ํด๋ฆญ
  4. ๋””๋ฒ„๊น…
    • ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจํ•˜์—ฌ ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ๋„๋‹ฌ

Best Practices

1. ํ•ญ์ƒ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ํ™œ์„ฑํ™”

{
  "compilerOptions": {
    "sourceMap": true  // ๊ฐœ๋ฐœ ์‹œ ํ•„์ˆ˜
  }
}

2. Git์—์„œ .map ํŒŒ์ผ ์ œ์™ธ

# ์†Œ์Šค ๋งต์€ ๋นŒ๋“œ ์‹œ ์ƒ์„ฑ
dist/**/*.map

# ํ”„๋กœ๋•์…˜ ์†Œ์Šค ๋งต์€ ๋ณ„๋„ ๊ด€๋ฆฌ
production-sourcemaps/

3. ํ”„๋กœ๋•์…˜์—์„œ ์„ ํƒ์  ์‚ฌ์šฉ

// ํ™˜๊ฒฝ๋ณ„ tsconfig
// tsconfig.prod.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "sourceMap": false  // ํ”„๋กœ๋•์…˜์—์„œ๋Š” ๋น„ํ™œ์„ฑํ™”
  }
}
// package.json
{
  "scripts": {
    "build:dev": "tsc",
    "build:prod": "tsc -p tsconfig.prod.json"
  }
}

4. ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ํ†ตํ•ฉ

ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์†Œ์Šค ๋งต์„ ์—๋Ÿฌ ์ถ”์  ์„œ๋น„์Šค์—๋งŒ ์ œ๊ณต:
// ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์›๋ณธ ์œ„์น˜ ๋งคํ•‘
import { SourceMapConsumer } from "source-map";

async function mapError(error: Error) {
  // ์Šคํƒ ํŠธ๋ ˆ์ด์Šค ํŒŒ์‹ฑ
  const match = error.stack?.match(/dist\/(.+):(\d+):(\d+)/);
  if (!match) return error;
  
  const [, file, line, column] = match;
  const mapFile = `sourcemaps/${file}.map`;
  
  // ์†Œ์Šค ๋งต์œผ๋กœ ์›๋ณธ ์œ„์น˜ ์ฐพ๊ธฐ
  const rawMap = JSON.parse(fs.readFileSync(mapFile, "utf-8"));
  const consumer = await new SourceMapConsumer(rawMap);
  
  const original = consumer.originalPositionFor({
    line: parseInt(line),
    column: parseInt(column)
  });
  
  return {
    ...error,
    originalFile: original.source,
    originalLine: original.line,
    originalColumn: original.column
  };
}

๊ด€๋ จ ๋„๊ตฌ

1. source-map-support

๋Ÿฐํƒ€์ž„์— ์†Œ์Šค ๋งต ์ž๋™ ์ ์šฉ:
pnpm add source-map-support
// index.ts ์ƒ๋‹จ
import "source-map-support/register";

2. @esbuild-kit/core-utils

esbuild ๊ธฐ๋ฐ˜ ๋นŒ๋“œ ๋„๊ตฌ์˜ ์†Œ์Šค ๋งต ์ง€์›:
import { installSourceMapSupport } from "@esbuild-kit/core-utils";
installSourceMapSupport();

3. Chrome DevTools

  • Elements ํƒญ์—์„œ ์ปดํŒŒ์ผ๋œ CSS๋ฅผ ์›๋ณธ SCSS/LESS๋กœ ๋งคํ•‘
  • Network ํƒญ์—์„œ ์†Œ์Šค ๋งต ๋‹ค์šด๋กœ๋“œ ํ™•์ธ
  • Console์—์„œ ์›๋ณธ ํŒŒ์ผ ๋งํฌ ํด๋ฆญ

๊ด€๋ จ ๋ฌธ์„œ