Vue3.4 변경점

dante Yoon·2024년 1월 22일
3

vue

목록 보기
5/5
post-thumbnail

안녕하세요, 단테입니다.
Vue3.4 🏀 슬램덩크 버전이 공개되었습니다.
오늘은 vue3.3과 비교해 어떠한 변경점이 있는지 알아보겠습니다.

슬램덩크

뷰는 각 마이너 버전마다 고유의 애니메이션 타이틀을 붙입니다. Vue2의 마지막 버전인 Vue2.7은 나루토가 버전 네이밍을 가져갔었습니다.

내부 퍼포먼스 개선

SFC

뷰는 컴포넌트 작성 시 Sigle File Component라는 형식으로 작성합니다. SFC는 *.vue와 같은 확장자 형식으로 컴포넌트를 작성하는 것을 말하며 스벨트와 유사하게 컴포넌트를 아래 세 가지 태그이상으로 나뉘어 작성하게 됩니다.

  • template
  • script
  • style

그 외 별도로 v18과 같은 별도의 플러그인 설치를 통해 SFC를 작성할 수 있습니다.

다음은 평범한 SFC의 모습입니다.

<template>
  <div>
    <h1>{{ title }}</h1>
    <button @click="incrementCount">Clicked {{ count }} times</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const title = 'Welcome to Vue 3.4';
const count = ref(0);

function incrementCount() {
  count.value++;
}
</script>

<style>
div {
  text-align: center;
  margin-top: 50px;
}
button {
  margin-top: 20px;
}
</style>

리엑트에서 JSX가 JS 함수로 변경되어 브라우저에서 실행되듯이
SFC가 자바스크립트로 변경되어 브라우저에서 화면을 그리기 위해서는 Vue 라이브러리 내부의 파서가 이 JS 함수로 변경해줘야 합니다.
Vue3.4에서는 이러한 Compiler의 재작성을 통해 비약적인 성능 향상이 이뤄졌습니다.

이러한 성능향상은 Regex를 기반으로 파싱되던 이전 버전의 Recursive descent parser 방식에서 htmlparser2 라이브러리를 사용한 유한상태머신(finite state machine)기반의 파싱 알고리즘을 도입해 이러졌습니다.

Recursive descent parser

해당 알고리즘에 대해서는 유튜브 영상을 첨부함으로 설명을 대체합니다.
https://www.youtube.com/watch?v=iddRD8tJi44

finite state machine tokenizer forked from htmlparser2

reactivity 시스템 개선

리엑트에서는 상태 업데이트시 해당 상태를 참조하는 컴포넌트가 리렌더링 되면서 항상 원본 상태 값으로 부터 파생된 derived나 computed값을 별도 함수 호출 없이도 컴포넌트 정의부 내부에서 사용할 수 있지만 Vue는 그렇게 작동하지 않고 명시적으로 computed 표기를 해주어야 derived된 값들을 사용할 수 있으며 watchEffect와 같은 상태 변경 리스너를 명시적으로 사용해주어야 합니다.

const count = ref(0)
const isEven = computed(() => count.value % 2 === 0)

watchEffect(() => console.log(isEven.value)) // logs true

count.value = 2 // logs true again

3.4 버전 미만에서는 watchEffect 내부에 선언된 isEven Ref<number>의 값이 변경되지 않아도 count.value 값이 변경되면 덩달아 호출되곤 했는데 이러한 부분이 불필요하게 호출되지 않게 변경되었습니다.

매크로

defineModel

뷰에서는 v-model을 통해 양방향 바인딩을 커스텀하게 각 SFC에서 정의할 수 있는데 3.3에서 experimental 기능으로 defineModel을 제공했었습니다. 이제 defineModel이 정식 피처로 변경되어 <script setup> 태그 내부에서 defineEmits, defineProps와 같이 간편하게 커스텀 v-model을 정의할 수 있게 되었습니다.

// ts
const modelValue = defineModel<string>();
// js
const modelValue = defineModel({ type: String});

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  }
});

const emit = defineEmits(['update:modelValue']);

... 

<input
	v-model="modelValue"
/>

Reactivity Transform

Vue3.3 -> Vue 3.4로 버전 업데이트할 때 주요하게 확인해야 할 점입니다.

RIP reactivity system

뷰에서 반응성 시스템은 javascript proxy를 사용하는데 반응성 변수를 읽을 때 다음처럼 *.value를 사용해야 합니다.

<script setup>
let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>

이렇게 .value를 스크립트 태그 내부에서 사용하는 것이 불편해서 매크로를 사용해 컴파일 타임에 자동으로 .value 값을 없애주게 코드를 사용할 수 있습니다.
아래에서 사용된 $ref()가 compile-time 매크로입니다.

<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>

여러 매크로 문법들

  • ref -> $ref
  • computed -> $computed
  • shallowRef -> $shallowRef
  • customRef -> $customRef
  • toRef -> $toRef

이러한 매크로 문법들이 vue3.4 부터는 글로벌로 사용될 수 있는 함수들에서 제외되었고 사용하기 위해서는 명시적으로 임포트해서 사용해야 합니다.

import { $ref } from 'vue/macros'

let count = $ref(0)

개발자 경험 개선

v-bind 축약 구문

항상 아래와 같이 사용했어야 했던 구문이

<img :id="id" :src="src" :alt="alt">

이렇게 간편하게 사용할 수 있게 되었습니다.

<img :id :src :alt>
profile
성장을 향한 작은 몸부림의 흔적들

0개의 댓글