Skip to content

Instantly share code, notes, and snippets.

@leedc0101
Created May 14, 2026 01:32
Show Gist options
  • Select an option

  • Save leedc0101/0e5af11660b284fa1e8393819195e380 to your computer and use it in GitHub Desktop.

Select an option

Save leedc0101/0e5af11660b284fa1e8393819195e380 to your computer and use it in GitHub Desktop.
frontend-briefing-2026-05-14-KST

FE ๋ฐ์ผ๋ฆฌ ๋ธŒ๋ฆฌํ•‘ | 2026-05-14 KST

์˜ค๋Š˜ ์„ ๋ณ„ํ•œ ํ”„๋ก ํŠธ์—”๋“œ ์‹ค๋ฌด ๊ด€๋ จ ๊ธ€ 7๊ฐœ์˜ ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ/์š”์•ฝ ๋ชจ์Œ์ž…๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์š”์•ฝ

  1. ์˜ค๋Š˜์˜ ํฐ ํ๋ฆ„์€ โ€œ๋ฒ”์šฉ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๊ธฐ๋ณด๋‹ค ๋‚ด ์•ฑ์˜ ์‹ค์ œ shape์— ๋งž๊ฒŒ ์ค„์ด๊ณ  ํˆฌ์˜ํ•œ๋‹คโ€๋Š” ๊ด€์ ์ž…๋‹ˆ๋‹ค. Wasp์˜ TypeScript ์ „ํ™˜, Tanner Linsley์˜ React projection ๊ธ€์ด ๊ฐ™์€ ์ถ•์„ ๋ด…๋‹ˆ๋‹ค.
  2. ๋ธŒ๋ผ์šฐ์ € ํ”Œ๋žซํผ์€ ๋‹ค์‹œ ์„ ์–ธ์  HTML ์ชฝ์œผ๋กœ ์›€์ง์ž…๋‹ˆ๋‹ค. <install> ์š”์†Œ, ์ž‘์€ HTML ํŽ˜์ด์ง€ + View Transitions, HTML fraction ํ‘œํ˜„์ฒ˜๋Ÿผ JS๋ฅผ ์ค„์ด๋Š” ์„ ํƒ์ง€๊ฐ€ ๋Š˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์‹ค๋ฌด DX๋Š” ์ž‘์€ ๋งˆ์ฐฐ ์ œ๊ฑฐ๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. .filter(Boolean) ํƒ€์ž… ์ขํžˆ๊ธฐ, ์—๋””ํ„ฐ webview/extension ํ‘œ์ค€ํ™”์ฒ˜๋Ÿผ ๋ฐ˜๋ณต๋˜๋Š” friction์„ ๋„๊ตฌ๊ฐ€ ๋ฉ”์›Œ ์ฃผ๋Š” ํ๋ฆ„์ด ๋ณด์ž…๋‹ˆ๋‹ค.

์„ ๋ณ„ ๊ธฐ์ค€

HN, Reddit, Lobsters, DEV, GeekNews/RSS ๊ณ„์—ด์—์„œ ์ตœ๊ทผ ๋ฐ˜์‘์ด ์žˆ๊ฑฐ๋‚˜ FE ์‹ค๋ฌด ์˜ํ–ฅ์ด ํฐ ๊ธ€์„ ์šฐ์„ ํ–ˆ๊ณ , ๊ณต์‹ ๋ธŒ๋ผ์šฐ์ € ์—…๋ฐ์ดํŠธ 1๊ฐœ๋ฅผ ๋ณด์™„ํ–ˆ์Šต๋‹ˆ๋‹ค.

5๋…„๊ณผ 500๋งŒ ๋‹ฌ๋Ÿฌ ๋’ค์— ๊นจ๋‹ฌ์€ ๊ฒƒ: ์›น ๊ฐœ๋ฐœ์„ ์œ„ํ•ด ์ƒˆ ์–ธ์–ด๋ฅผ ๋งŒ๋“  ๊ฑด ์‹ค์ˆ˜์˜€๋‹ค

์š”์•ฝ ๋ฒˆ์—ญ

Wasp๋Š” React, Node.js, Prisma ์œ„์—์„œ ๋™์ž‘ํ•˜๋Š” ํ’€์Šคํƒ ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค. ์ฒ˜์Œ ๋ชฉํ‘œ๋Š” Rails๋‚˜ Laravel์ฒ˜๋Ÿผ ์•ฑ ์ „์ฒด ๊ตฌ์กฐ๋ฅผ ๋†’์€ ์ˆ˜์ค€์—์„œ ์„ ์–ธํ•˜๊ณ , ์‹ค์ œ ๊ตฌํ˜„์€ ๊ธฐ์กด JS ์Šคํƒ์— ๋งก๊ธฐ๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ธ์ฆ, ๋ผ์šฐํŠธ, ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€, cron job ๊ฐ™์€ ์š”๊ตฌ์‚ฌํ•ญ์„ ํ•œ ๊ณณ์— ์ ์œผ๋ฉด Wasp๊ฐ€ ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

์ดˆ๊ธฐ ํŒ€์€ ์ด ๋ฌธ์ œ๋ฅผ ํ’€๋ ค๋ฉด ์ƒˆ ์–ธ์–ด๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค. ๋ฌธ๋ฒ•์„ ์™„์ „ํžˆ ํ†ต์ œํ•˜๊ณ  ์‹ถ์—ˆ๊ณ , ์žฅ๊ธฐ์ ์œผ๋กœ๋Š” Node.js๋ฟ ์•„๋‹ˆ๋ผ Python ๊ฐ™์€ ๋‹ค๋ฅธ ๋Ÿฐํƒ€์ž„๊นŒ์ง€ ํฌ๊ด„ํ•˜๋Š” ๋ฒ”์šฉ ์ŠคํŽ™ ์–ธ์–ด๋ฅผ ์ƒ์ƒํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” โ€œ์ƒˆ ์–ธ์–ดโ€๋ผ๋Š” ํฌ์žฅ์ด ์ฑ„ํƒ์˜ ๊ฐ€์žฅ ํฐ ์žฅ๋ฒฝ์ด ๋๋‹ค. ๊ฐœ๋ฐœ์ž๋“ค์€ wasp-lang์„ ๋ณด๋ฉด JavaScript๋ฅผ ๋Œ€์ฒดํ•˜๋ ค๋Š” ์–ธ์–ด๋กœ ์˜คํ•ดํ–ˆ๊ณ , IDE ์ง€์›๊ณผ ์ƒํƒœ๊ณ„ ํ˜ธํ™˜์„ฑ์„ ๊ฑฑ์ •ํ–ˆ๋‹ค.

ํฅ๋ฏธ๋กœ์šด ์ ์€ ์‚ฌ์šฉํ•ด ๋ณธ ๊ฐœ๋ฐœ์ž๋“ค์€ Wasp์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋ฅผ ์ข‹์•„ํ–ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ฌธ์ œ๋Š” ์–ธ์–ด๊ฐ€ ์•„๋‹ˆ๋ผ, ์•ฑ ์ „์ฒด๋ฅผ ๋†’์€ ์ˆ˜์ค€์—์„œ ์ดํ•ดํ•˜๋Š” ์ŠคํŽ™์ด์—ˆ๋‹ค. Wasp๊ฐ€ ์ปดํŒŒ์ผ ํƒ€์ž„์— ํŽ˜์ด์ง€, ๋ผ์šฐํŠธ, ์ฟผ๋ฆฌ, ์—”ํ‹ฐํ‹ฐ, ์ธ์ฆ ํ๋ฆ„์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ๋žŒ๊ณผ AI ๋ชจ๋‘ ์•ฑ ๊ตฌ์กฐ๋ฅผ ๋” ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ฆ‰ โ€œ์–ธ์–ดโ€๊ฐ€ ํ•ด์ž๊ฐ€ ์•„๋‹ˆ๋ผ โ€œ์•ฑ ์ „์ฒด๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ชจ๋ธโ€์ด ํ•ด์ž์˜€๋‹ค.

๊ฒฐ์ •์ ์ธ ๋ถ€๋‹ด์€ IDE ์ง€์›์ด์—ˆ๋‹ค. ์˜ค๋Š˜๋‚  JS/TS ๊ฐœ๋ฐœ์ž๋Š” ์ž๋™์™„์„ฑ, ํƒ€์ž… ์ถ”๋ก , jump-to-definition, inline diagnostics ๊ฐ™์€ ๊ฒฝํ—˜์„ ๋‹น์—ฐํ•˜๊ฒŒ ๊ธฐ๋Œ€ํ•œ๋‹ค. ์ปค์Šคํ…€ ์–ธ์–ด์—์„œ ์ด ์ˆ˜์ค€์˜ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋ ค๋ฉด ์ž์ฒด language server์™€ VS Code extension์„ ๋งŒ๋“ค์–ด์•ผ ํ–ˆ๊ณ , Prisma DSL๊ณผ React/Node ํŒŒ์ผ ์ฐธ์กฐ๊นŒ์ง€ ์—ฎ์ด๋ฉด์„œ ๋์—†์ด edge case๊ฐ€ ์ƒ๊ฒผ๋‹ค.

๊ทธ๋ž˜์„œ Wasp๋Š” ์ปค์Šคํ…€ DSL์„ TypeScript ๊ธฐ๋ฐ˜ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ฐ”๊พธ๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋‚ด๋ถ€ ์ปดํŒŒ์ผ๋Ÿฌ์™€ ์•ฑ ์ƒ์„ฑ ๋ฐฉ์‹์€ ์œ ์ง€ํ•˜๋˜, ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ ์ŠคํŽ™์„ main.wasp.ts ๊ฐ™์€ TypeScript ํŒŒ์ผ๋กœ ์ž‘์„ฑํ•˜๊ฒŒ ํ•˜๋Š” ๋ณ€ํ™”๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ฐœ๋ฐœ์ž๋Š” ์ต์ˆ™ํ•œ TS ๋„๊ตฌ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๊ณ , Wasp๋Š” ์—ฌ์ „ํžˆ ์•ฑ ์ „์ฒด ๊ตฌ์กฐ๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ดํ•ดํ•œ๋‹ค.

์‹ค๋ฌด ํฌ์ธํŠธ

ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋‚ด๋ถ€ ํ”Œ๋žซํผ์„ ๋งŒ๋“ค ๋•Œ โ€œ์ƒˆ ๋ฌธ๋ฒ•โ€์€ ๊ฐ•๋ ฅํ•ด ๋ณด์ด์ง€๋งŒ, ์ฑ„ํƒ ๋น„์šฉ๊ณผ tooling ๋น„์šฉ์„ ๊ฐ™์ด ๋งŒ๋“ ๋‹ค. ์‹ค๋ฌด ํŒ€์ด๋ผ๋ฉด DSL์„ ๋„์ž…ํ•˜๊ธฐ ์ „์— TypeScript embedded DSL, config-as-code, schema ๊ธฐ๋ฐ˜ ์„ ์–ธ ๊ฐ™์€ ๋Œ€์•ˆ์„ ๋จผ์ € ๊ฒ€ํ† ํ•˜๋Š” ํŽธ์ด ์•ˆ์ „ํ•˜๋‹ค. ํ•ต์‹ฌ์€ ๋ฌธ๋ฒ•์˜ ๋…์ฐฝ์„ฑ์ด ์•„๋‹ˆ๋ผ, ํŒ€๊ณผ ๋„๊ตฌ๊ฐ€ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ ์ˆ˜์ค€ ์•ฑ ๋ชจ๋ธ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.

React๋ฅผ โ€˜ํˆฌ์˜โ€™ํ•˜๊ธฐ: ์•ฑ์˜ ์‹ค์ œ ๋ชจ์–‘์— ๋งž์ถ˜ ๊ฒฝ๋Ÿ‰ ๋Ÿฐํƒ€์ž„ ์‹คํ—˜

์š”์•ฝ ๋ฒˆ์—ญ

Tanner Linsley๋Š” TanStack Start๋ฅผ ๋งŒ๋“ค๋ฉฐ React์˜ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค ํฌ๊ธฐ๊ฐ€ ๊ณ„์† ๋งˆ์Œ์— ๊ฑธ๋ ธ๋‹ค๊ณ  ๋งํ•œ๋‹ค. Vite๋กœ ๋ฒˆ๋“ค๋งํ•˜๋ฉด React๋Š” ์•ฑ ์ฝ”๋“œ๊ฐ€ ํ•˜๋‚˜๋„ ์‹คํ–‰๋˜๊ธฐ ์ „๋ถ€ํ„ฐ ์•ฝ 60KB gzip์„ ์ฐจ์ง€ํ•œ๋‹ค. TanStack Router, Query, Store, Form, Virtual์„ ๋ชจ๋‘ ํ•ฉ์นœ ๊ฒƒ๋ณด๋‹ค โ€œ์ œ๊ฑฐํ•  ์ˆ˜ ์—†๋Š” ๊ฐ€์žฅ ์ž‘์€ ์กฐ๊ฐโ€์ธ React๊ฐ€ ๋” ์ปธ๋‹ค๋Š” ์ ์ด ๋ฌธ์ œ์˜ ์ถœ๋ฐœ์ ์ด๋‹ค.

์ฒ˜์Œ ๋– ์˜ฌ๋ฆฐ ํ•ด๋ฒ•์€ Preact์˜€๋‹ค. ํ•˜์ง€๋งŒ preact/compat์€ React 19์˜ use() ์˜๋ฏธ๋ก , server actions, portals, error boundaries, hydration edge์™€ ์ถฉ๋ถ„ํžˆ ๋งž์ง€ ์•Š์•˜๋‹ค. ๊ณ„์† shim์„ ์Œ“๋Š” ๋ฐฉ์‹์ด ๋๊ณ , ๊ทธ๋Š” ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๋ณด๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. ํ•„์š”ํ•œ ๊ฒƒ์€ Preact๊ฐ€ ์•„๋‹ˆ๋ผ โ€œReact์˜ ๊ณต๊ฐœ API๋ฅผ ํŠน์ • ๋ฒ”์œ„์— ๋งž๊ฒŒ ๋‹ค์‹œ ํˆฌ์˜ํ•œ ๊ตฌํ˜„โ€์ด์—ˆ๋‹ค.

๊ธ€์˜ ํ•ต์‹ฌ ๋น„์œ ๋Š” โ€œ์ฝ”๋“œ๋Š” materialized viewโ€๋ผ๋Š” ๊ด€์ ์ด๋‹ค. ์˜ˆ์ „์—๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์ƒ์„ฑํ•˜๋Š” ๋น„์šฉ์ด ๋„ˆ๋ฌด ์ปค์„œ ์ฝ”๋“œ ์ž์ฒด๋ฅผ ์ง„์‹ค์˜ ์›์ฒœ์ฒ˜๋Ÿผ ๋‹ค๋ค˜๋‹ค. ํ•˜์ง€๋งŒ AI coding agent๊ฐ€ ์ถฉ๋ถ„ํžˆ ์‹ธ๊ณ  ๋นจ๋ผ์ง€๋ฉด, ์•Œ๊ณ ๋ฆฌ์ฆ˜ยทํ”„๋กœํ† ์ฝœยทsemantic contract ๊ฐ™์€ ์•„์ด๋””์–ด๊ฐ€ base table์ด ๋˜๊ณ , ์ฝ”๋“œ๋Š” ๊ทธ ์•„์ด๋””์–ด์˜ ์—ฌ๋Ÿฌ projection ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Š” React์˜ public API๋ฅผ base table๋กœ ๋ณด๊ณ , TanStack Start์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ๊ตฌํ˜„ํ•œ ๋Ÿฐํƒ€์ž„์„ ๋งŒ๋“ค์—ˆ๋‹ค. concurrent rendering, time slicing, lane scheduler, React DevTools, ์ผ๋ถ€ Flight client machinery๋Š” ์ œ์™ธํ–ˆ๋‹ค. ๋Œ€์‹  element model, hooks, keyed diffing, SSR streaming, Suspense, hydration ๋“ฑ ํ•„์š”ํ•œ ํ•ต์‹ฌ ํ‘œ๋ฉด์€ ๋งž์ท„๋‹ค. ๊ธฐ๋Šฅ์€ core์™€ toggleable feature๋กœ ๋‚˜๋ˆ , portal/context/suspense/memo/forwardRef/lazy/class components/hydration ๋“ฑ์„ ์•ฑ ํ•„์š”์— ๋”ฐ๋ผ stub ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ๋‹ค.

์ธก์ • ๊ฒฐ๊ณผ๋Š” ๊ณผ๊ฐํ•˜๋‹ค. React 19 ๊ธฐ์ค€ react-dom/client๋Š” ์•ฝ 60.3KB gzip์ธ๋ฐ, projection full์€ 9.39KB, nano๋Š” 7.08KB ์ˆ˜์ค€์ด๋‹ค. ๊ฐœ์ธ ์‚ฌ์ดํŠธ์™€ tanstack.com์—์„œ ์‹ค์ œ๋กœ ๋Œ๋ ค ๋ณธ ๊ฒฐ๊ณผ JS ์ „์†ก๋Ÿ‰๊ณผ FCP๊ฐ€ ์ค„์—ˆ๊ณ , TanStack ๊ทœ๋ชจ ์•ฑ์—์„œ๋„ ๋Œ€๋ถ€๋ถ„ parity ์ด์ƒ์„ ๋ณด์˜€๋‹ค. ๋‹จ, RSC-heavy ํŽ˜์ด์ง€์˜ LCP๋Š” ์ผ๋ถ€ ์•…ํ™”๋๊ณ  ์ด๋Š” known regression์œผ๋กœ ๋‚จ๊ฒผ๋‹ค.

์ค‘์š”ํ•œ ์ ์€ ์ด๊ฒƒ์„ โ€œ๋Œ€์ฒด Reactโ€๋กœ ๋งˆ์ผ€ํŒ…ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ํƒœ๋„๋‹ค. ํŠน์ • ์†Œ๋น„์ž์—๊ฒŒ ๋งž์ถ˜ projection์€ ๊ทธ ๋ฒ”์œ„์—์„œ๋งŒ ์˜๋ฏธ๊ฐ€ ์žˆ๊ณ , ์ผ๋ฐ˜ ๋ชฉ์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํฌ๊ธฐํ•  ์ˆ˜ ์—†๋Š” ๋ฒ”์šฉ์„ฑ์„ ๋‚ด๋ ค๋†“์•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ๋‹ค. ๊ธ€์€ React core๋ฅผ ๋ฐ”๊พธ์ž๋Š” ์ œ์•ˆ์ด๋ผ๊ธฐ๋ณด๋‹ค, AI ์‹œ๋Œ€์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์†Œ๋น„์ž๊ฐ€ ์ž๊ธฐ ์•ฑ์˜ shape๋ฅผ ๋” ์ ๊ทน์ ์œผ๋กœ ์ดํ•ดํ•˜๊ณ  ์ฑ…์ž„์ ธ์•ผ ํ•œ๋‹ค๋Š” ์ฃผ์žฅ์— ๊ฐ€๊น๋‹ค.

์‹ค๋ฌด ํฌ์ธํŠธ

๋‹น์žฅ ํŒ€ ์•ฑ์—์„œ React๋ฅผ ์ง์ ‘ ํˆฌ์˜ํ•˜์ž๋Š” ๋œป์€ ์•„๋‹ˆ๋‹ค. ๋‹ค๋งŒ โ€œ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ์“ฐ๋Š” ๊ธฐ๋Šฅ์€ ๋ฌด์—‡์ด๊ณ , ๋ฒ”์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์–ด๋–ค ๋น„์šฉ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋‚ด๊ณ  ์žˆ๋Š”๊ฐ€?โ€๋ฅผ ๋ฌผ์–ด๋ณผ ๊ฐ€์น˜๋Š” ์žˆ๋‹ค. ํŠนํžˆ ํ”„๋ ˆ์ž„์›Œํฌยท๋””์ž์ธ์‹œ์Šคํ…œยทSDK๋ฅผ ๋งŒ๋“œ๋Š” ํŒ€์ด๋ผ๋ฉด ๊ธฐ๋Šฅ ๋‹จ์œ„ opt-in, adapter layer, narrow runtime ๊ฐ™์€ ์„ค๊ณ„๋ฅผ ๋” ์ง„์ง€ํ•˜๊ฒŒ ๋ณผ ์‹œ์ ์ด๋‹ค.

์ƒˆ HTML <install> ์š”์†Œ๋กœ ์›น์•ฑ ์„ค์น˜ ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ

์š”์•ฝ ๋ฒˆ์—ญ

์›น์•ฑ ์„ค์น˜๋Š” ์ง€๊ธˆ๊นŒ์ง€ JavaScript์— ํฌ๊ฒŒ ์˜์กดํ–ˆ๋‹ค. beforeinstallprompt ์ด๋ฒคํŠธ๋ฅผ ์žก๊ณ , ์‚ฌ์šฉ์ž์˜ ํด๋ฆญ์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ์Šคํฌ๋ฆฝํŠธ ์•ˆ์—์„œ ์„ค์น˜ ํ๋ฆ„์„ ์ œ์–ดํ•ด์•ผ ํ–ˆ๋‹ค. Chrome/Edge๊ฐ€ ์‹คํ—˜ ์ค‘์ธ ์ƒˆ <install> HTML ์š”์†Œ๋Š” ์ด ๊ณผ์ •์„ ์„ ์–ธ์ ์œผ๋กœ ๋ฐ”๊พธ๋ ค๋Š” ์‹œ๋„๋‹ค. ํŽ˜์ด์ง€์— <install></install>์„ ๋„ฃ์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‹ ๋ขฐ ๊ฐ€๋Šฅํ•œ ์„ค์น˜ ๋ฒ„ํŠผ์„ ์ง์ ‘ ๋ Œ๋”๋งํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๋ฅด๋ฉด ๊ธฐ๋ณธ ์„ค์น˜ ํ”Œ๋กœ์šฐ๊ฐ€ ์—ด๋ฆฐ๋‹ค.

์ด ์š”์†Œ๋Š” permission UI์™€ ๋น„์Šทํ•œ ์ฒ ํ•™์„ ๊ฐ–๋Š”๋‹ค. ๋ฒ„ํŠผ์˜ ํ…์ŠคํŠธ, ์–ธ์–ด, ๋ชจ์–‘์„ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ†ต์ œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž์˜ ํด๋ฆญ์„ ๋” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งˆ์Œ๋Œ€๋กœ ๊พธ๋ฏผ ๋ฒ„ํŠผ๋ณด๋‹ค โ€œ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ณด์žฅํ•˜๋Š” ์„ค์น˜ affordanceโ€์— ๊ฐ€๊นŒ์šด ์…ˆ์ด๋‹ค.

ํ˜„์žฌ ํŽ˜์ด์ง€์˜ ์›น์•ฑ์„ ์„ค์น˜ํ•˜๋ ค๋ฉด manifest์— id๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๊ณ , HTML์—๋Š” <install></install> ํ•˜๋‚˜๋ฉด ๋œ๋‹ค. ๋‹ค๋ฅธ origin์˜ ์›น์•ฑ์„ ์„ค์น˜ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด installurl ์†์„ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค. ํ•„์š”ํ•˜๋ฉด manifestid๋กœ ๊ณ„์‚ฐ๋œ manifest id๋ฅผ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ์•ฑ ์นดํƒˆ๋กœ๊ทธ ํŽ˜์ด์ง€์—์„œ ์—ฌ๋Ÿฌ ์•ฑ์„ ๊ฐ๊ฐ์˜ ์„ค์น˜ ๋ฒ„ํŠผ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์—ผ๋‘์— ๋‘”๋‹ค.

์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” fallback content๊ฐ€ ๊ทธ๋Œ€๋กœ ํ‘œ์‹œ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด <install installurl="https://awesome-app.com/"><a href="https://awesome-app.com/">Launch Awesome App</a></install>์ฒ˜๋Ÿผ ์ž‘์„ฑํ•˜๋ฉด, ๋ฏธ์ง€์› ํ™˜๊ฒฝ์—์„œ๋„ ๋งํฌ๊ฐ€ ๋ณด์ธ๋‹ค. JavaScript๋กœ๋Š” HTMLInstallElement in window ์ฒดํฌ๋กœ ์ง€์› ์—ฌ๋ถ€๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์š”์†Œ๋Š” ์„ฑ๊ณต, ์ทจ์†Œ, validation ์ƒํƒœ ๋ณ€๊ฒฝ ๊ฐ™์€ ์ด๋ฒคํŠธ๋„ ์ œ๊ณตํ•œ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” promptaction, promptdismiss, validationstatuschanged๋ฅผ ํ†ตํ•ด ์„ค์น˜ ์„ฑ๊ณต/์ทจ์†Œ/์˜ค๋ฅ˜๋ฅผ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Chrome ๋˜๋Š” Edge 148 ์ด์ƒ์—์„œ๋Š” flag๋ฅผ ์ผœ๊ณ  ๋กœ์ปฌ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์‹ค์ œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์‹คํ—˜ํ•˜๋ ค๋ฉด origin trial์— ๋“ฑ๋กํ•ด์•ผ ํ•˜๋ฉฐ, Chrome/Edge 148๋ถ€ํ„ฐ 153๊นŒ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ™์€ ์˜์—ญ์—์„œ imperative API์ธ navigator.install()๋„ ๋ณ„๋„์˜ origin trial๋กœ ์‹คํ—˜ ์ค‘์ด๋‹ค. <install>์€ ์ตœ์†Œ ์ฝ”๋“œ์™€ ๋ธŒ๋ผ์šฐ์ € ์‹ ๋ขฐ UI์— ๊ฐ•ํ•˜๊ณ , navigator.install()์€ ์ปค์Šคํ…€ UI์™€ JS ์ค‘์‹ฌ ํ”Œ๋กœ์šฐ์— ๋” ์ ํ•ฉํ•˜๋‹ค.

์‹ค๋ฌด ํฌ์ธํŠธ

PWA ์„ค์น˜ UX๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ–ˆ๋˜ ํŒ€์ด๋ผ๋ฉด <install>์„ origin trial ์ˆ˜์ค€์—์„œ ์ฒดํฌํ•ด ๋ณผ ๋งŒํ•˜๋‹ค. ํŠนํžˆ ์•ฑ ๋งˆ์ผ“/๋Ÿฐ์ฒ˜/์‚ฌ๋‚ด ๋„๊ตฌ ํฌํ„ธ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ์›น์•ฑ์„ ์„ค์น˜์‹œํ‚ค๋Š” UI์—์„œ๋Š” JS ceremony๋ฅผ ์ค„์ด๊ณ  ๋ธŒ๋ผ์šฐ์ € ์‹ ๋ขฐ UI๋ฅผ ์–ป์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. ๋‹จ, ์•„์ง ์‹คํ—˜ ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ production default๋กœ ๋ณด๊ธฐ๋ณด๋‹ค๋Š” progressive enhancement ํ›„๋ณด๋กœ ๋ณด๋Š” ๊ฒŒ ๋งž๋‹ค.

TypeScript์—์„œ .filter(Boolean)์ด ํƒ€์ž…์„ ์ขํžˆ์ง€ ์•Š๋Š” ์ด์œ 

์š”์•ฝ ๋ฒˆ์—ญ

JavaScript์—์„œ๋Š” [1, 2, undefined, 4].filter(Boolean)์ด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค. ๋Ÿฐํƒ€์ž„์—์„œ๋Š” undefined๊ฐ€ ์ œ๊ฑฐ๋˜๊ณ  ์ˆซ์ž๋งŒ ๋‚จ๋Š”๋‹ค. ํ•˜์ง€๋งŒ TypeScript๋Š” ๊ทธ ๊ฒฐ๊ณผ ๋ฐฐ์—ด์˜ ์›์†Œ๊ฐ€ ์—ฌ์ „ํžˆ undefined์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ values.map(v => v * 2) ๊ฐ™์€ ์ฝ”๋“œ์—์„œ 'v' is possibly 'undefined' ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค.

์ด์œ ๋Š” TypeScript๊ฐ€ Boolean()์˜ ์˜๋ฏธ๋ฅผ ๊นŠ๊ฒŒ ๋ถ„์„ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. TypeScript์˜ narrowing์€ control-flow analysis, ์ธ์‹ ๊ฐ€๋Šฅํ•œ ๋ฌธ๋ฒ• ํŒจํ„ด, ๋ช…์‹œ์  type predicate์— ํฌ๊ฒŒ ์˜์กดํ•œ๋‹ค. .filter(Boolean)์„ ๋ณด๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๋Š” โ€œboolean์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜โ€ ์ •๋„๋กœ๋งŒ ์ดํ•ดํ•˜์ง€, โ€œnull/undefined๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ํ•„ํ„ฐโ€๋ผ๊ณ  ํ•ด์„ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋น„์Šทํ•˜๊ฒŒ !!value๋Š” truthiness check ํŒจํ„ด์œผ๋กœ ์ธ์‹๋ผ ํƒ€์ž…์ด ์ขํ˜€์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์ง€๋งŒ, Boolean(value)๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์— narrowing์ด ์ž˜ ๋˜์ง€ ์•Š๋Š”๋‹ค. ๋Ÿฐํƒ€์ž„ ๋™์ž‘์€ ๋น„์Šทํ•ด๋„ ์ปดํŒŒ์ผ๋Ÿฌ ๊ด€์ ์—์„œ๋Š” ๋‹ค๋ฅด๋‹ค.

TypeScript ์นœํ™”์ ์ธ ํ•ด๊ฒฐ์ฑ…์€ ๋ช…์‹œ์  type predicate๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ค.

const values = [1, 2, undefined, 4].filter(
  (x): x is NonNullable<typeof x> => Boolean(x)
);

์ด์ œ TypeScript๋Š” โ€œ์ด ํ•จ์ˆ˜๊ฐ€ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ฐ’์€ null/undefined๊ฐ€ ์•„๋‹ˆ๋‹คโ€๋ผ๋Š” ๊ด€๊ณ„๋ฅผ ์ดํ•ดํ•œ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ values.map(v => v * 2)๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ํ†ต๊ณผํ•œ๋‹ค.

๊ธ€์“ด์ด๋Š” ์ด ํŒจํ„ด์ด ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ˜๋ณต๋˜๋Š” ๊ฒƒ์„ ๋ณด๊ณ  AST ๊ธฐ๋ฐ˜ ์ž๋™ ์ˆ˜์ • ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. .filter(Boolean)์„ ์ฐพ์•„ ์œ„์™€ ๊ฐ™์€ type predicate ํ˜•ํƒœ๋กœ ๋ฐ”๊พธ๋Š” CLI๋‹ค. ํ•ต์‹ฌ์€ ๋ฌธ์ž์—ด ์น˜ํ™˜์ด ์•„๋‹ˆ๋ผ, TypeScript diagnostics์™€ AST node๋ฅผ ์ดํ•ดํ•ด ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ณ  ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๋ณ€ํ™˜์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.

์‹ค๋ฌด ํฌ์ธํŠธ

.filter(Boolean)์€ ๊ฐ„๊ฒฐํ•˜์ง€๋งŒ strict TypeScript์—์„œ๋Š” friction์„ ๋งŒ๋“ ๋‹ค. ๊ณตํ†ต ์œ ํ‹ธ๋กœ isNonNullable ํƒ€์ž… ๊ฐ€๋“œ๋ฅผ ์ •์˜ํ•ด ์“ฐ๊ฑฐ๋‚˜, lint/fixer๋กœ ์ž๋™ ๊ต์ •ํ•˜๋Š” ํŽธ์ด ์ข‹๋‹ค. ์ž‘์€ ํƒ€์ž… ๋งˆ์ฐฐ๋„ ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด์— ์Œ“์ด๋ฉด ๊ฝค ํฐ ์ƒ์‚ฐ์„ฑ ๋น„์šฉ์ด ๋œ๋‹ค.

JS๋ฅผ ์ค„์ด๊ณ  HTML ํŽ˜์ด์ง€๋กœ ๋˜๋Œ๋ฆฌ๊ธฐ

์š”์•ฝ ๋ฒˆ์—ญ

Jim Nielsen์€ ์•„์ด์ฝ˜ ์‚ฌ์ดํŠธ์—์„œ ์•„์ด์ฝ˜ ํฌ๊ธฐ๋ฅผ ๋ฐ”๊พธ๋Š” ์ž‘์€ ์œ„์ ฏ์„ ์šด์˜ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ๊ธฐ์กด ๊ตฌํ˜„์€ web component๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. <icon-list size="md"> ๊ฐ™์€ custom element๊ฐ€ ์žˆ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ํฌ๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด JavaScript๊ฐ€ size ์†์„ฑ์„ ๋ฐ”๊พผ๋‹ค. ์ดํ›„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹ ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ์™€ src ๋“ฑ์„ ์—…๋ฐ์ดํŠธํ–ˆ๋‹ค.

๊ธฐ๋Šฅ์€ ์ž˜ ๋™์ž‘ํ–ˆ์ง€๋งŒ, ๋ฌธ์ œ๋Š” ์‚ฌ์ดํŠธ๊ฐ€ ๊ฑฐ์˜ ์ „๋ถ€ pre-rendered static page์˜€๋‹ค๋Š” ์ ์ด๋‹ค. ์ด ์ž‘์€ ์ƒํ˜ธ์ž‘์šฉ ๋•Œ๋ฌธ์— ์„œ๋ฒ„ ๋ Œ๋”๋ง์— ์“ฐ๋Š” ํ…œํ”Œ๋ฆฟ ๋กœ์ง๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๋„ ์ค‘๋ณตํ•ด์„œ ๋ณด๋‚ด์•ผ ํ–ˆ๋‹ค. ์„œ๋ฒ„ ์ชฝ ๋ Œ๋”๋ง์„ ์กฐ๊ธˆ ๋ฐ”๊ฟจ๋Š”๋ฐ ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง ์—…๋ฐ์ดํŠธ๋ฅผ ์žŠ์œผ๋ฉด ๋ฏธ๋ฌ˜ํ•˜๊ฒŒ ๊นจ์ง€๋Š” ์œ ์ง€๋ณด์ˆ˜ ๋ถ€๋‹ด๋„ ์ƒ๊ฒผ๋‹ค.

๊ทธ๋ž˜์„œ ๊ทธ๋Š” ์งˆ๋ฌธ์„ ๋ฐ”๊ฟจ๋‹ค. โ€œํด๋ฆญ โ†’ JS ์‹คํ–‰ โ†’ ํ˜„์žฌ ํŽ˜์ด์ง€ DOM ๋ณ€๊ฒฝโ€ ๋Œ€์‹  โ€œํด๋ฆญ โ†’ ๋‹ค๋ฅธ HTML ํŽ˜์ด์ง€๋กœ navigationโ€์ด๋ฉด ์–ด๋–จ๊นŒ? ์ฆ‰ /colors/red/ ํ•œ ํŽ˜์ด์ง€์—์„œ JS๋กœ ๋„ค ๊ฐ€์ง€ ํฌ๊ธฐ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋Œ€์‹ , /colors/red/{sm|md|lg|xl}์ฒ˜๋Ÿผ ๋„ค ๊ฐœ์˜ HTML ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋‘๋Š” ๋ฐฉ์‹์ด๋‹ค.

์‹œ๋„ํ•ด ๋ณด๋‹ˆ ๊ฒฐ๊ณผ๋Š” ์ข‹์•˜๋‹ค. CSS View Transitions๋ฅผ ๋”ํ•˜์ž ์•„์ด์ฝ˜ ์‚ฌ์ด ์ „ํ™˜ ํšจ๊ณผ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ƒ๊ฒผ๋‹ค. ํฅ๋ฏธ๋กœ์šด ์ ์€ ๋” ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ๋„ฃ์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํด๋ผ์ด์–ธํŠธ JS๋ฅผ ์ œ๊ฑฐํ–ˆ๋Š”๋ฐ UX๊ฐ€ ์ข‹์•„์กŒ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

๊ธ€์˜ ๋ฉ”์‹œ์ง€๋Š” ๋‹จ์ˆœํ•˜๋‹ค. ์›น ํ”Œ๋žซํผ์— CSS View Transitions ๊ฐ™์€ ๊ฐ•๋ ฅํ•œ primitive๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด์„œ, ์˜ˆ์ „์—๋Š” JS๋กœ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋˜ ์ธํ„ฐ๋ž™์…˜์„ navigation๊ณผ HTML๋กœ ๋‹ค์‹œ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์„ SPA ์•ˆ์˜ ์ƒํƒœ ์ „ํ™˜์œผ๋กœ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†๋‹ค.

์‹ค๋ฌด ํฌ์ธํŠธ

์ •์  ์‚ฌ์ดํŠธ, ๋ฌธ์„œ, ์นดํƒˆ๋กœ๊ทธ, ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ, ํ•„ํ„ฐ/์ •๋ ฌ UI ์ค‘ ์ผ๋ถ€๋Š” โ€œ์ƒํƒœ ๋ณ€๊ฒฝโ€์ด ์•„๋‹ˆ๋ผ โ€œํŽ˜์ด์ง€ ์ด๋™โ€์œผ๋กœ ์ฒ˜๋ฆฌํ•ด๋„ UX๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ข‹๋‹ค. View Transitions๋ฅผ ํ•จ๊ป˜ ์“ฐ๋ฉด ์ „ํ™˜๋„ ๋ถ€๋“œ๋Ÿฝ๋‹ค. ํŠนํžˆ ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง ๋กœ์ง์ด ์„œ๋ฒ„ ํ…œํ”Œ๋ฆฟ๊ณผ ์ค‘๋ณต๋  ๋•Œ๋Š” HTML ํŽ˜์ด์ง€๋ฅผ ๋” ๋งŒ๋“œ๋Š” ์„ ํƒ์ด ์˜คํžˆ๋ ค ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๋‹ค.

HTML์—์„œ ๋ถ„์ˆ˜๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•

์š”์•ฝ ๋ฒˆ์—ญ

๊ธ€์“ด์ด๋Š” ํ„ดํ…Œ์ด๋ธ” ๊ด€๋ จ ๊ธ€์„ ์“ฐ๋‹ค๊ฐ€ โ€œ33๊ณผ 1/3โ€ ๊ฐ™์€ ๋ถ„์ˆ˜๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ํ•„์š”๊ฐ€ ์ƒ๊ฒผ๋‹ค. ํ‰์†Œ์—๋Š” ๋ถ„์ˆ˜๋ฅผ ์ง์ ‘ ์“ธ ์ผ์ด ๊ฑฐ์˜ ์—†์—ˆ์ง€๋งŒ, ์›น ๋ฌธ์„œ์—์„œ๋Š” ๊ฐ€๋…์„ฑ๊ณผ ์˜๋ฏธ๋ฅผ ๊ฐ™์ด ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๋ถ„์ž, fraction slash, ๋ถ„๋ชจ๋ฅผ ์กฐํ•ฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ผ๋ฐ˜ / ๋Œ€์‹  ์œ ๋‹ˆ์ฝ”๋“œ fraction slash โ„๋ฅผ ์“ฐ๋ฉด ์‹œ๊ฐ์ ์œผ๋กœ ๋” ์ ์ ˆํ•˜๊ณ , ํ•„์š”ํ•˜๋ฉด ์‹œ๊ฐ ๋ณด์กฐ๊ฐ€ ์–ด๋ ค์šด ๋…์ž๋ฅผ ์œ„ํ•ด ์„ค๋ช…์šฉ ํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด 1โ„3 ๊ฐ™์€ ํ˜•ํƒœ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ HTML์˜ vulgar fraction entity๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ค. HTML์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ถ„์ˆ˜ ๋ฌธ์ž entity๊ฐ€ ์žˆ๋‹ค.

  • &frac12; โ†’ ยฝ
  • &frac13; โ†’ โ…“
  • &frac23; โ†’ โ…”
  • &frac14; โ†’ ยผ
  • &frac34; โ†’ ยพ
  • &frac15; โ†’ โ…•
  • &frac25; โ†’ โ…–
  • &frac35; โ†’ โ…—
  • &frac45; โ†’ โ…˜
  • &frac16; โ†’ โ…™
  • &frac56; โ†’ โ…š
  • &frac18; โ†’ โ…›
  • &frac38; โ†’ โ…œ
  • &frac58; โ†’ โ…
  • &frac78; โ†’ โ…ž

๊ธ€ ์ž์ฒด๋Š” ์งง์ง€๋งŒ, HTML ๋ฌธ์„œ ์ž‘์„ฑ์—์„œ ๋†“์น˜๊ธฐ ์‰ฌ์šด ๋””ํ…Œ์ผ์„ ๋ณด์—ฌ์ค€๋‹ค. ๋ชจ๋“  ํ‘œํ˜„์„ CSS๋‚˜ JS๋กœ ์กฐ๋ฆฝํ•˜์ง€ ์•Š์•„๋„, Unicode์™€ HTML entity๊ฐ€ ์ด๋ฏธ ์ œ๊ณตํ•˜๋Š” ์˜๋ฏธ ์žˆ๋Š” ํ‘œํ˜„์ด ์žˆ๋‹ค.

์‹ค๋ฌด ํฌ์ธํŠธ

๋ฌธ์„œ/์ฝ˜ํ…์ธ  UI์—์„œ๋Š” ์ž‘์€ typographic detail์ด ํ’ˆ์งˆ์„ ๋งŒ๋“ ๋‹ค. ๊ฐ€๊ฒฉ, ์น˜์ˆ˜, ๋ ˆ์‹œํ”ผ, ์Œ์•…/์˜์ƒ ์ŠคํŽ™์ฒ˜๋Ÿผ ๋ถ„์ˆ˜๊ฐ€ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š” ์„œ๋น„์Šค๋ผ๋ฉด entity์™€ ์ ‘๊ทผ์„ฑ ํ‘œํ˜„์„ ์ •๋ฆฌํ•ด ๋””์ž์ธ ์‹œ์Šคํ…œ ๋ฌธ์„œ์— ๋„ฃ์–ด๋‘˜ ๋งŒํ•˜๋‹ค.

VS Code webview์™€ ์—๋””ํ„ฐ ํ™•์žฅ ๋ฝ์ธ์„ ์ค„์ด๋ ค๋Š” OXP ์‹คํ—˜

์š”์•ฝ ๋ฒˆ์—ญ

๊ธ€์“ด์ด๋Š” ์›๋ž˜ ์ž์‹ ์˜ ์›Œํฌํ”Œ๋กœ ๋ณ‘๋ชฉ์„ ํ’€๊ธฐ ์œ„ํ•ด ์ƒˆ IDE๋ฅผ ๋งŒ๋“ค๋ ค ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ IDE UI๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด VS Code extension webview์™€ ์‹ธ์šฐ๋‹ค๊ฐ€, ๋” ํฐ ๋ฌธ์ œ๊ฐ€ โ€œ์—๋””ํ„ฐ ํ™•์žฅ vendor lock-inโ€์ด๋ผ๋Š” ๊ฒฐ๋ก ์— ๋„๋‹ฌํ–ˆ๋‹ค. ์˜ค๋Š˜๋‚  ๊ฐœ๋ฐœ ๋„๊ตฌ๋ฅผ ๋„๋ฆฌ ๋ฐฐํฌํ•˜๋ ค๋ฉด VS Code/Cursor์šฉ Electron/TypeScript ํ™•์žฅ๊ณผ JetBrains์šฉ Kotlin/JVM ํ™•์žฅ์„ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ๊ทธ๋Š” IDE ์ž์ฒด ๋Œ€์‹  OXP(Open eXtensions Protocol)๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ๋ชฉํ‘œ๋Š” React/WASM์œผ๋กœ ํ™•์žฅ์„ ํ•œ ๋ฒˆ ์ž‘์„ฑํ•˜๊ณ , ์—ฌ๋Ÿฌ ์ฃผ์š” ์—๋””ํ„ฐ์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ์ฒ˜๋Ÿผ ์‹คํ–‰ํ•˜๋Š” ๊ณตํ†ต ํ‘œ์ค€์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

OXP๋Š” ๋‹จ์ˆœ iframe ๊ธฐ๋ฐ˜ webview๊ฐ€ ์•„๋‹ˆ๋ผ secure WebAssembly sandbox์™€ IPC bridge๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์„ค๋ช…ํ•œ๋‹ค. React ์ฝ”๋“œ์—์„œ action์ด ๋ฐœ์ƒํ•˜๋ฉด OXP๊ฐ€ ์ด๋ฅผ ๋„ค์ดํ‹ฐ๋ธŒ IDE command๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค. VS Code์—์„œ๋Š” native extension API์— ์ง์ ‘ ๋ฐ”์ธ๋”ฉํ•˜๊ณ , JetBrains์—์„œ๋Š” JCEF๋ฅผ ํ†ตํ•ด ๋„ค์ดํ‹ฐ๋ธŒ floating OS window๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

๊ธ€์“ด์ด๋Š” ์ด host layer๊ฐ€ MCP ์„ค์ • ๋ฌธ์ œ๋„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ณธ๋‹ค. Cursor, Copilot, JetBrains์— ๊ฐ๊ฐ Model Context Protocol ์„œ๋ฒ„ ์„ค์ •์„ ์ˆ˜๋™์œผ๋กœ ๋„ฃ๋Š” ๋Œ€์‹ , OXP daemon์ด ์‹œ์Šคํ…œ ๋ ˆ๋ฒจ MCP router์ฒ˜๋Ÿผ ๋™์ž‘ํ•ด ๊ฐ์ง€ํ•œ IDE์— context๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค๋Š” ์•„์ด๋””์–ด๋‹ค.

ํ”„๋กœ์ ํŠธ๋Š” CLI์™€ ๋ฌธ์„œ๋ฅผ ๊ณต๊ฐœํ–ˆ๊ณ , npm i -g @oxprotocol/cli๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์†Œ๊ฐœํ•œ๋‹ค. ์•„์ง์€ ์ฃผ์žฅ๊ณผ ์ดˆ๊ธฐ ๊ตฌํ˜„์„ ๊ฒ€์ฆํ•ด์•ผ ํ•˜๋Š” ๋‹จ๊ณ„์ง€๋งŒ, ๊ฐœ๋ฐœ ๋„๊ตฌ UI๋ฅผ ์—๋””ํ„ฐ๋ณ„๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์ •๋ฉด์œผ๋กœ ๋‹ค๋ฃฌ๋‹ค๋Š” ์ ์—์„œ ํฅ๋ฏธ๋กญ๋‹ค.

์‹ค๋ฌด ํฌ์ธํŠธ

ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋Š” ์ด์ œ ๋ธŒ๋ผ์šฐ์ € ์•ฑ๋ฟ ์•„๋‹ˆ๋ผ IDE, MCP, devtool UI๊นŒ์ง€ React/WebAssembly ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค ์ผ์ด ๋Š˜๊ณ  ์žˆ๋‹ค. ๋‹ค๋งŒ โ€œํ•œ ๋ฒˆ ์ž‘์„ฑํ•ด ๋ชจ๋“  ์—๋””ํ„ฐ์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ์ฒ˜๋Ÿผ ์‹คํ–‰โ€์€ ๋‚œ๋„๊ฐ€ ๋†’์œผ๋ฏ€๋กœ, ์‹ค์ œ ๋„์ž… ์ „์—๋Š” sandbox ๋ณด์•ˆ, latency, API coverage, ๊ฐ ์—๋””ํ„ฐ UX ์ œ์•ฝ์„ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ์ง€๊ธˆ์€ production dependency๋ผ๊ธฐ๋ณด๋‹ค devtool ํ”Œ๋žซํผ ๋ฐฉํ–ฅ์„ฑ์„ ๋ณด์—ฌ์ฃผ๋Š” ์‹ ํ˜ธ๋กœ ๋ณด๋Š” ๊ฒŒ ์ ์ ˆํ•˜๋‹ค.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment