Vue.js

[Vue.js] <script>가 <template>보다 위에 있어도 상관없을까?

캐럿노트 2025. 2. 7. 14:50

Intro

새로운 프로젝트는 Vue.js를 사용하게 되어 학습 중 자동완성으로 생성되는 코드 템플릿과 vue 시작시 기본으로 생성되는 HelloWorld.vue 파일의 구조가 달라 궁금증이 생겼다.

 

기본적으로 *.vue 파일 생성시 vueinit을 입력하면 자동완성으로 코드 템플릿을 사용할 수 있다.

vueinit 입력 후 자동완성

 

또한, VSCode 확장프로그램 중 Vue VSCode Snippets를 설치하면 아래와 같이 자동완성을 사용할 수 있다.

VSCode 확장 프로그램
여러 스타일의 코드 템플릿을 사용할 수 있다.

 

자세히 보면 모두 template → script → style 순으로 배치되어있다. 하지만 Vue 프로젝트 생성시 자동으로 생성된 HelloWorld.vue파일은 script → template → style 순이다.

// src/components/HelloWord.vue

<script setup lang="ts">
defineProps<{
  msg: string
}>()
</script>

<template>
  <div class="greetings">
    <h1 class="green">{{ msg }}</h1>
    <h3>
      You’ve successfully created a project with
      <a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
      <a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
    </h3>
  </div>
</template>

<style scoped>
h1 {
  font-weight: 500;
  font-size: 2.6rem;
  position: relative;
  top: -10px;
}

h3 {
  font-size: 1.2rem;
}

.greetings h1,
.greetings h3 {
  text-align: center;
}

@media (min-width: 1024px) {
  .greetings h1,
  .greetings h3 {
    text-align: left;
  }
}
</style>

Vue 공식 템플릿에서 <script>를 최상단에 배치한 이유

Vue 컴포넌트는 SFC(Single File Component) 방식으로 작성되며, <script>, <template>, <style>순서는 자유롭게 배치할 수 있다. Vue는 컴파일 과정에서 각 블록을 독립적으로 처리하기 때문에 순서에 따른 동작 변화는 발생하지 않는다. 하지만 다른 장점 때문에 script 태그를 상단에 배치한다.

 

📌 1. 가독성과 유지보수성 향상

  • Vue 3에서 script setup을 사용하면 로직이 매우 간결해지기 때문에, 먼저 읽는 것이 자연스러워진다.
  • 컴포넌트의 데이터와 로직이 위에 있으면 "이 컴포넌트가 무엇을 하는지" 먼저 파악할 수 있다.
  • React나 JavaScript의 일반적인 코드 구조처럼, 데이터 및 함수 선언 → UI 정의 (JSX 또는 템플릿) 순서가 직관적이다.
<script setup>
const message = "Hello, Vue!";
</script>

<template>
  <h1>{{ message }}</h1>
</template>

이렇게 하면, message가 무엇인지 먼저 확인한 후에 템플릿을 이해할 수 있어서 직관이다.

 

📌 2. 타입스크립트와 코드 자동 완성 지원이 더 잘 된다

  • Vue 3 + TypeScript 프로젝트에서는 script가 위에 있어야 IDE(예: VS Code)의 자동완성 기능이 더 원활하게 동작한다.
  • <script setup> 스타일의 SFC(Single File Component)에서 defineProps나 defineEmits 같은 Composition API 함수를 먼저 정의한 후, 이를 template에서 사용하면 더 빠르게 코드 검증 가능하다.
<script setup lang="ts">
defineProps<{ msg: string }>();
</script>

<template>
  <h1>{{ msg }}</h1>
</template>

이렇게 하면, TypeScript가 msg가 string 타입인지 즉시 확인 가능하다.

 

📌 3. 렌더링 최적화 (컴파일러 관점에서 더 효율적)

  • Vue 3의 Composition API (script setup) 방식에서는 컴파일러가 먼저 <script> 내용을 분석하고 최적화한 후, <template>을 처리한다.
  • script를 먼저 배치하면 Vue 내부에서 변수를 더 빨리 분석할 수 있어 최적화가 쉬워진다.
<script setup>
const count = 0;
</script>

<template>
  <p>{{ count }}</p>
</template>

변수 선언을 먼저 하면, Vue는 count가 반응형인지 여부를 미리 판단하여 최적화 가능하다. 하지만 Options API 에서는 컴파일 순서가 다르다.

 


🔍 Vue 3의 Composition API와 Options API에서 컴파일러 동작 방식 차이

Vue 3에서 Composition APIOptions API는 컴포넌트를 정의하는 방식이 다르기 때문에, Vue 컴파일러가 처리하는 순서도 차이가 있다.

 

📌 1. Composition API 방식의 컴파일 과정

Vue 3에서 Composition API(script setup)을 사용하면, 컴파일러가 먼저 <script setup> 블록을 처리한 후, <template>을 변환하는 최적화 과정을 거친다.

 

⚙️ 컴파일러의 동작 순서

  1. <script setup> 블록이 가장 먼저 실행된다.
  2. Vue는 setup() 내부의 변수, 함수, 반응형 데이터 등을 분석하여 템플릿에서 사용하는 변수 목록을 파악한다.
  3. 이후 <template>을 컴파일할 때, 필요한 변수만 최적화하여 렌더링 함수로 변환한다.
  4. 최적화된 렌더링 함수가 생성되어 가상 DOM(Virtual DOM)에서 사용된다.
// Composition API 형식
<script setup>
import { ref } from 'vue';

const count = ref(0);
const increment = () => count.value++;
</script>

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

<style>
</style>

즉, script setup 방식에서는 컴파일러가 먼저 <script setup>을 실행하고, 필요한 데이터만 setup() 함수로 자동 변환한 후, 템플릿을 처리하여 사용하지 않는 변수는 최적화(제거)하여 성능 향상이 이루어진다.

 

📌 2. Options API 방식의 컴파일 과정

Options API 방식에서는 data(), methods, computed, watch 등의 옵션을 사용해 컴포넌트를 정의한다. 이 방식에서는 Vue 컴파일러가 <template>을 먼저 분석한 후, 필요한 속성을 Options API에서 찾아 적용하는 과정으로 진행된다.

 

⚙️  컴파일러의 동작 순서

  1. Vue는 먼저 <template>을 스캔하여, 사용된 data(), computed, methods 등을 추출한다.
  2. 이후 export default {} 내부에서 data(), methods, computed 등의 속성을 찾는다.
  3. setup()을 자동 생성하지 않고, this를 사용하여 Vue 인스턴스에 직접 바인딩한다.
  4. 최적화 후 렌더링 함수를 생성한다.
// Options API 형식
<template>
  <button @click="increment">{{ count }}</button>
</template>

<script>
export default {
  data() {
    return { count: 0 };
  },
  methods: {
    increment() {
      this.count++;
    }
  }
};
</script>

<style>
</style>

 

Options API에서는 setup()이 자동 생성되지 않으며, this를 사용하여 데이터에 접근해야 하며 사용하지 않는 데이터도 제거되지 않아 script setup보다 최적화가 덜 된다.

 

Composition API vs Options API 컴파일 순서 차이점 정리

비교 항목 Composition API 방식 Options API 방식
컴파일 순서 <script setup> → <template> 변환 <template> 분석 후 export default {} 실행
데이터 분석 Vue가 setup()을 자동 생성 this 기반으로 직접 접근
렌더링 최적화 사용되지 않는 변수 제거됨 (트리 셰이킹 지원) 모든 데이터가 유지됨 (불필요한 데이터도 포함됨)
성능 최적화 템플릿에 필요한 데이터만 남기고 최적화됨 모든 data() 속성이 유지됨
사용법 this 없이 반응형 변수를 직접 선언 (ref, reactive) this를 통해 data() 값에 접근

 


✨결론

Composition API 방식을 사용하는 경우

  • <script>가 먼저 실행되어 템플릿을 최적화할 수 있기 때문에, <template> 보다 <script>을 상단에 배치하는 것이 유리하다.

Options API 방식을 사용하는 경우

  • <template>과 <script>를 독립적으로 분석 하기 때문에 순서에 따른 컴파일 속도에 큰 차이가 없다.
  • Options API에서는 data(), methods 등의 속성이 많아질 가능성이 높아 코드가 길어질 수 있다.
  • Vue 2 스타일을 유지하면서 UI 구조를 먼저 이해하는 것이 중요하므로,<template>을 상단에 배치하는 것이 일반적이다.