에반 유는 Vue.js를 접근성과 개발자 경험 중심으로 설계했습니다. 이러한 선택들이 기업형 절차 없이도 확장 가능한 생태계를 어떻게 만들어냈는지 알아보세요.

Vue.js는 매우 개인적인 기원 이야기를 가지고 있습니다. 에반 유는 더 큰 프레임워크를 사용하면서 자신이 원하던 도구를 직접 만들었습니다. 동기는 "다음 큰 것"이 아니라, 컴포넌트 기반 UI의 강력한 부분은 살리되 일상 작업에서 불필요한 마찰을 제거하는 것이었습니다.
그 의도는 지금도 Vue의 핵심 가치에 드러납니다: 접근성(낮은 진입 장벽), 사용성(일상적인 개발 경험의 매끄러움), 그리고 실용성(필요할 때 파워를 제공하되 불필요한 의례를 강요하지 않음).
Vue가 말하는 접근성은 모든 것을 새로 배우게 만들지 않고도 빠르게 결과를 얻을 수 있음을 의미합니다. HTML, CSS, JavaScript를 알고 있다면 Vue는 이러한 기술의 자연스러운 확장처럼 느껴지도록 설계됩니다. 읽기 쉬운 템플릿, 명확한 오류 메시지, 그리고 "헬로 월드"가 곧 아키텍처 논쟁이 되지 않는 경로 등이 포함됩니다.
**사용성(ergonomics)**은 그 다음 단계입니다: 애플리케이션이 커질수록 정신적 부담을 줄여 주는 작은 설계 선택들입니다. 합리적인 기본값, 일관된 패턴, 그리고 일반적인 작업을 쉽게 해 주는 API들이 그것입니다. 목표는 단순합니다: 도구와 씨름하는 시간이 아니라 제품 작업에 더 많은 시간을 쓰는 것.
Vue의 설계는 실용적입니다: 명료성과 개발자 경험을 우선하면서도 진지한 애플리케이션을 지원합니다.
그 균형에는 트레이드오프가 따릅니다. Vue는 종종 고도로 추상화된 패턴보다 명시적이고 읽기 쉬운 패턴을 선호하며, 하나의 절대적 아키텍처를 강요하지 않고 유연성을 유지하려고 합니다. 툴링, 라우팅, 상태관리, 메타프레임워크 등 생태계가 확장되면서 원래의 단순성을 유지하면서도 주류 규모를 지원하는 것이 도전 과제가 되었습니다.
이 글에서는 그러한 선택들이 Vue의 핵심 기능, 툴링의 진화, 그리고 그 주위에 성장한 생태계에 어떻게 반영되었는지—또한 더 많은 구조나 엄격한 관습이 필요할 때의 한계점도 살펴봅니다.
Vue의 접근성은 단순히 초심자 친화적이라는 의미를 넘어서는 의도적인 설계 선택입니다: 첫걸음을 친숙하게 느끼게 하고, 실제로 필요해질 때까지 다음 단계들은 선택 사항으로 남겨두는 것입니다.
평범한 언어로 말하면, Vue는 전체 아키텍처의 대대적 개편 없이 기능을 하나씩 추가하듯 도입할 수 있게 해 줍니다.
하나의 상호작용 위젯(가격 계산기, 필터 패널, 회원가입 모달 등)으로 시작할 수 있고, 그 위젯은 서버 렌더링 HTML, 레거시 jQuery, 혹은 다른 UI 레이어와 공존할 수 있습니다. Vue는 첫날부터 페이지 전체가 "Vue 앱"이 될 것을 요구하지 않습니다.
필요가 커지면 같은 코드베이스를 확장할 수 있습니다:
학습 곡선은 당신이 해결하려는 문제에 맞춰집니다. 생산적이 되기 위해 모든 것을 미리 배울 필요가 없습니다.
많은 프런트엔드 재작성 프로젝트는 초기 단계에서 너무 많은 결정을 강제하기 때문에 시작 전에 실패합니다: 파일 구조, 상태 관리 패턴, 빌드 툴링, 엄격한 컨벤션, "하나의 정답" 등.
Vue는 그 압박을 줄여 줍니다. 합리적인 기본 경험을 제공하지만 무거운 스택을 즉시 선택하도록 요구하지 않습니다. 팀은 먼저 가치를 빠르게 제공한 뒤 실제 사용을 바탕으로 표준화를 점진적으로 진행할 수 있습니다—성능 요구, 팀 규모, 제품 복잡도를 기반으로 초기에 예측해서 결정할 필요가 없습니다.
친숙한 진입점과 선택 가능한 복잡성의 조합이 Vue를 환영받으면서도 제한적이지 않게 느껴지도록 만듭니다.
Vue가 인기를 얻은 이유 중 하나는 전사적 도박을 하지 않아도 시도해 볼 수 있다는 점입니다. 작게 시작해 가치를 증명하고, 의미가 있을 때만 확장할 수 있습니다—기존 코드베이스를 짓밟지 않고도 말이죠.
가장 가벼운 시작은 CDN 스크립트 태그입니다: 기존 페이지에 Vue를 추가하고 단일 요소에 마운트하면 됩니다. 폼을 보강하거나 동적인 테이블을 추가하거나 마케팅 페이지의 상호작용을 업그레이드할 때 백엔드나 빌드 설정을 바꿀 필요가 없습니다.
현대적인 워크플로우를 원한다면 Vite 기반 앱이 빠른 개발 시작과 합리적인 기본값을 제공합니다. 독립형 Vue 앱을 만들거나 서버 렌더링된 페이지 전반에 여러 Vue "아일랜드"를 마운트할 수 있습니다.
세 번째 경로는 그 사이 어딘가입니다: 기존 앱에 Vue를 한 페이지(또는 한 컴포넌트)씩 통합하는 방식. 팀들은 종종 jQuery 위젯이나 brittle한 바닐라 스크립트를 Vue 컴포넌트로 교체하면서 패턴을 표준화합니다.
Vue의 핵심 개념—컴포넌트, 템플릿, 반응형 상태—은 초반에 접근하기 쉽지만 나중에 무용지물이 되지 않습니다. 프로젝트가 성장함에 따라 라우팅, 공유 상태, 더 구조화된 아키텍처를 실제 필요에 따라 도입할 수 있습니다. 복잡성을 미리 비용으로 지불할 필요가 없습니다.
점진적 도입은 현실의 제약에 맞습니다: 레거시 페이지와 새로운 화면의 공존, 여러 팀, 다른 릴리스 주기. Vue는 서버 프레임워크, 오래된 프런트엔드 코드, 혹은 다른 UI 레이어와 공존하면서 조각별로 마이그레이션할 수 있습니다. 그렇게 하면 "재작성"은 위험한 올오어낫싱이 아니라 일련의 작은 업그레이드가 됩니다.
Vue의 기본 작성 스타일은 의도적으로 친숙합니다: HTML과 같은 템플릿을 쓰고, 적은 수의 디렉티브를 사용하며 실제 로직은 JavaScript에 둡니다. 서버 렌더링 앱이나 jQuery 시대의 UI 작업을 하던 개발자에게는 새로운 이데올로기가 아니라 연속선상에 있는 것으로 느껴지는 경우가 많습니다.
Vue 템플릿은 표준 HTML처럼 보이지만, 일반적인 UI 요구를 위한 작은 어휘를 추가합니다:
v-if / v-else로 조건부 렌더링v-for로 목록 처리v-bind(종종 :로 축약)로 동적 속성 바인딩v-on(종종 @로 축약)로 이벤트 처리이 디렉티브들은 명시적이고 일관되기 때문에 템플릿은 중첩된 함수 호출의 퍼즐이 아니라 UI의 설명처럼 읽힙니다.
SFC는 템플릿, 로직, 스타일을 하나로 묶어 사람들이 UI를 생각하는 방식(컴포넌트 단위)과 잘 맞습니다.
<template>
<button :disabled="loading" @click="submit">Save</button>
<template>
<script setup>
const loading = ref(false)
function submit() {}
</script>
<style scoped>
button { font-weight: 600; }
</style>
이 형식은 컨텍스트 전환을 줄여 줍니다. "이 클래스는 어디에 정의되어 있나?"나 "클릭 시 어떤 핸들러가 실행되나?" 같은 일상적 질문에 답을 찾기 위해 여러 파일을 뒤질 필요가 줄어듭니다.
실무에서는 더 많은 사람이 동일한 코드베이스에 기여할수록 SFC 구조를 일관되게 유지하기 위해 규약(및 린팅)을 활용하는 경향이 있습니다.
<style scoped>는 CSS를 컴포넌트로 제한해 작은 수정이 관련 없는 화면을 망가뜨리는 것을 막아 줍니다. 마크업, 동작, 스타일의 동료 배치는 빠른 반복과 자신 있는 리팩터링을 지원합니다—바로 이런 사용자 경험의 측면들이 프레임워크를 일상적으로 자연스럽게 느껴지게 합니다.
Vue의 리액티비티는 일상적 관점에서 이해하기 가장 쉽습니다: 어떤 상태(데이터)를 가지고 있고, 그 상태가 바뀌면 UI가 그에 맞게 갱신됩니다. 버튼 클릭 후 카운터를 다시 그리라고 직접 지시하는 대신 숫자를 바꾸면 Vue가 그 값을 사용하는 모든 곳에 반영합니다.
예측 가능성은 유지보수를 쉽게 만듭니다. 업데이트가 일관되면 "왜 이 컴포넌트가 바뀌었나?"라는 질문에 DOM 조작을 여기저기 찾아다니기보다 상태 변화로 역추적할 수 있습니다.
Vue의 리액티비티 시스템은 템플릿의 어떤 부분이 어떤 상태에 의존하는지 추적합니다. 이를 통해 프레임워크는 필요한 부분만 업데이트하고, 개발자는 인터페이스를 서술하는 데 집중할 수 있습니다.
두 가지 실용적인 도구가 실제 앱에서 이 모델을 유용하게 만듭니다:
Computed(계산된 값): 도출된 상태 용입니다. 다른 데이터의 함수로 표현할 수 있다면 computed에 두세요(필터된 리스트, 합계, 전체 이름, 폼 유효성 등). Computed는 자동으로 동기화되며 템플릿에서 평범한 값처럼 읽힙니다.
Watchers(감시자): 부수 효과 용입니다—값의 변화가 어떤 동작을 트리거해야 할 때(드래프트 저장, 쿼리 변경 시 API 호출, localStorage 동기화, 라우트 변경에 반응 등).
간단한 규칙: 결과물이 화면에 표시되거나 바인딩되는 값이라면 computed를, 데이터 변화에 따라 "무언가를 해야 한다면" watcher를 사용하세요.
Composition API는 특정한 확장 문제를 해결하기 위해 도입되었습니다: 컴포넌트가 "몇 개의 옵션과 몇 가지 메서드"를 넘어서 읽기 어려워질 때, 어떻게 컴포넌트를 읽기 좋게 유지할 것인가? 큰 컴포넌트에서는 Options API가 관련 로직을 data, methods, computed, watcher에 흩어지게 할 수 있습니다. Composition API는 기능 단위(예: "검색", "페이지네이션", "드래프트 저장")로 코드를 그룹화해 관련 부분이 서로 가까이 있게 합니다.
목표는 Options API를 대체하려는 것이 아니었습니다. 대신 Vue가 더 잘 확장되게 하는 것이 목적이었습니다—특히 많은 컴포넌트에서 로직을 재사용해야 할 때나 컴포넌트가 복잡해질 때 유리합니다.
Composition API로 당신은:
Options API는 여전히 단순한 UI에 매우 적합합니다: 읽기 쉽고 구조적이며 다양한 경험을 가진 팀에 친숙합니다. Composition API는 컴포넌트에 여러 관심사가 있을 때(폼 + 페칭 + UI 상태 등) 혹은 화면 간 동작을 공유하고자 할 때 빛을 발합니다.
많은 팀이 두 방식을 혼합합니다: 글이 읽기 좋은 곳에서는 Options API를 사용하고, 재사용성과 조직화가 중요해질 때 Composition API를 사용합니다.
composable은 상태와 동작을 묶는 함수일 뿐입니다.
// useToggle.js
import { ref } from 'vue'
export function useToggle(initial = false) {
const on = ref(initial)
const toggle = () => (on.value = !on.value)
return { on, toggle }
}
폼: 유효성 검사와 더티 상태는 useForm()에 담을 수 있습니다.
페칭: 로딩, 에러, 캐싱 패턴을 useFetch()로 감쌀 수 있습니다.
UI 동작: 드롭다운 열림/닫힘, 키보드 단축키, 혹은 "외부 클릭" 로직 같은 것은 한 번 공유하면 어디서나 재사용하기 좋습니다.
Vue의 사용성은 "마법"이라기보다 사람들이 이미 UI를 생각하는 방식과 맞아떨어지는 규약에 가깝습니다: 데이터 입력 → UI 출력 → 사용자 이벤트 처리. 프레임워크는 깔끔하고 읽기 쉬운 기본선을 유도한 뒤, 커스텀이 필요할 때는 비켜섭니다.
일반적인 Vue 컴포넌트는 작고 명확하게 유지될 수 있습니다: 마크업은 템플릿에, 상태와 로직은 스크립트에, 필요하면 스타일을 추가합니다. 빌드를 시작하려고 서드파티 헬퍼를 잔뜩 모아야 할 필요가 거의 없습니다.
동시에 Vue는 잘못된 함정에 빠뜨리지 않습니다. 순수 JavaScript를 계속 사용할 수 있고, 점진적으로 TypeScript를 도입할 수 있으며, 동적 케이스에는 렌더 함수로 전환하거나 Options API에서 Composition API로 옮길 수도 있습니다. 기본값은 움직이게 하고, 탈출구는 나중에 재작성하는 비용을 줄여 줍니다.
Vue는 몇 가지 일관된 패턴으로 의례를 줄입니다:
v-bind/:와 v-model을 통한 선언적 바인딩으로 상태↔UI 연결을 간결하게 유지@click 등 이벤트 핸들링은 HTML처럼 읽히며 장황한 래퍼 코드를 줄임이런 규약들은 일상 업무에서 중요합니다: 건드려야 할 파일이 줄고, 암기해야 할 커스텀 패턴이 적으며, 스타일 결정에 드는 시간이 줄어듭니다.
대규모 팀은 더 많은 복잡성이 아니라 공유된 규칙을 필요로 합니다. Vue의 규약은 코드베이스 전반에 공통 언어가 됩니다: 일관된 컴포넌트 구조, 예측 가능한 데이터 흐름, 그리고 리뷰하기 좋은 템플릿 문법.
규모가 늘어나 더 엄격함이 필요하면 Vue는 접근 방식을 바꾸지 않고도 지원합니다: 타입이 지정된 props와 emits, 엄격한 린팅, 재사용을 장려하는 모듈형 composable 등으로 점진적 가드레일을 추가할 수 있습니다.
Vue의 초기 성장은 더 무거운 프런트엔드 도구 체인과 함께했습니다—webpack 설정, 긴 설치 시간, 결과를 보기까지 지연되는 개발 서버 등. Vue CLI는 그 시대를 더 쉽게 만들었지만 근본 현실은 남아 있었습니다: 프로젝트가 커질수록 콜드 스타트가 느려지고, 재빌드 비용이 커지고, 작은 변경조차 크게 느껴질 수 있었습니다.
툴링은 행동에 영향을 줍니다. 피드백 루프가 느리면 팀은 변경을 묶어 배치하고, 리팩터링을 미루고, 탐색적 개선을 꺼리게 됩니다. 시간이 흐르며 그 마찰은 품질에 은밀히 영향을 줍니다: "나중에 고치자"가 늘고, 작은 정리 작업이 줄고, 단순히 사이클을 다시 돌리는 게 귀찮아서 버그가 생존할 가능성이 높아집니다.
Vite(에반 유가 만든 도구)는 Vue의 철학에 부합하는 리셋이었습니다: 의례를 줄이고 워크플로우를 이해하기 쉽게 유지합니다.
개발 시 전체를 미리 번들하지 않고 브라우저의 네이티브 ES 모듈을 활용해 코드를 즉시 제공합니다. 종속성은 효율적으로 프리번들되어 개발 서버 시작이 빠르고 업데이트가 거의 즉시 반영됩니다.
프로덕션 빌드에서는 Vite가 Rollup 기반의 성숙한 번들링 방식을 사용하므로 "빠른 개발"이 곧 "위험한 배포"를 의미하지 않습니다. 빠른 반복을 하면서도 최적화된 자산을 배포할 수 있습니다.
변경 사항이 즉시 보이면 개발자는 더 작은 단계로 아이디어를 테스트합니다. 이는 더 깔끔한 컴포넌트, 더 자신 있는 수정, 그리고 빠른 리뷰 사이클을 장려합니다. 디자이너가 마크업을 손보고, QA가 문제를 재현하는 것도 더 쉬워집니다—프로젝트가 민감하고 깨지기 쉬운 대신 반응적이고 안정적으로 느껴집니다.
UI 접근법을 팀 전체로 평가할 때, 메인 레포와 분리된 빠른 프로토타이핑도 도움이 됩니다. 예를 들어 팀들은 Koder.ai 같은 플랫폼을 활용해 채팅 프롬프트에서 일시적인 프로토타입을 빠르게 띄운 뒤—소스 코드 내보내기, 스냅샷 캡처, 반복—본격적인 마이그레이션 전에 아이디어를 검증합니다. 프로덕션 프런트엔드가 Vue이더라도 빠른 프로토타입은 의사결정에서 구현까지의 사이클을 단축해 줍니다.
에반 유는 대형 프레임워크를 사용하면서 느낀 불편함을 해소하고자 Vue.js를 만들었습니다.
프로젝트의 "개인적 기원"은 Vue의 우선순위에 반영되어 있습니다: HTML/CSS/JS를 우선시하는 친숙함, 명확한 패턴, 확장해도 가벼운 워크플로우.
“접근성(approachability)”은 HTML, CSS, JavaScript를 확장하는 개념으로서 빠르게 생산성을 낼 수 있다는 뜻입니다.
실무적으로는 읽기 쉬운 템플릿, 일관된 디렉티브, 친절한 오류 메시지, 초기부터 전체 아키텍처를 강제하지 않는 온램프를 포함합니다.
실제 프로젝트에서 단계적으로 도입할 수 있다는 뜻입니다.
일반적인 진행 단계:
세 가지 실용적인 진입점:
가치가 증명되는 가장 작은 접근법을 선택한 뒤, 실사용 데이터에 따라 표준화하세요.
SFC는 템플릿, 로직, 스타일을 한 파일에 담아 컨텍스트 전환을 줄입니다.
일반적인 SFC의 이점:
이 방식은 반복 작업을 빠르게 하고 리팩터링 시 안전성을 높여줍니다.
스코프드 스타일은 CSS가 컴포넌트 밖으로 새어나가는 것을 줄여 줍니다.
실무적용:
물론 좋은 CSS 아키텍처의 대체제가 아니라 보완 수단입니다.
Vue의 정신 모델은 단순합니다: 상태(state)가 변경되면 → UI가 자동으로 업데이트된다.
이 방식은 이벤트 후 DOM을 수동으로 조작하는 대신 반응형 상태를 바꾸면 관련된 모든 표현이 갱신되므로, 동작을 추적하고 유지보수하기가 더 쉽습니다.
정리 규칙:
표현이나 바인딩을 위해 필요한 값이라면 우선 computed를 고려하세요. 부수 효과가 필요하면 watcher를 사용하세요.
두 API는 상호보완적입니다.
많은 팀이 혼용합니다: 단순 뷰는 Options API로, 재사용성·조직화가 필요할 때 Composition API로 전환합니다.
먼저 공식 빌딩 블록을 간단하게 적용하세요:
SEO/초기 로드 성능이 중요해지면 SSR(서버 사이드 렌더링)과 Nuxt를 고려하되, 이는 확장 단계에서 선택하는 옵션으로 보세요.