script-setup について
Vue 3 の単一ファイルコンポーネントと Composition API を使う開発者向けに、`<script setup>` の構文と使い方を解説します。テンプレートへのバインディング、Props、イベント、TypeScript の既定値を扱います。
主な機能
- 01トップレベルのバインディングをテンプレートで利用
- 02`defineProps()` と `defineEmits()` の使用
- 03`withDefaults()` による TypeScript の既定値設定
- 04インポートしたコンポーネントの登録省略
活用シーン
- 01Vue コンポーネント定義の定型コード削減
- 02コンポーネントの Props とイベントの宣言
- 03テンプレートでインポートしたコンポーネントを利用
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patternsdev/ skills --skill script-setupインストール後、Claude Code で/script-setupを入力して読み込まれたか確認します。
詳細
<script setup>
目次
<script setup> は、Vue の単一ファイルコンポーネントで Composition API を使うための、コンパイル時のシンタックスシュガーです。トップレベルのバインディングを明示的な return 文なしでテンプレートに自動公開することで、定型コードを削減します。
使用する場面
- Vue 3 で SFC と Composition API の両方を使う場合に、推奨構文として使用します
- コンポーネント定義の定型コードを減らすのに役立ちます
手順
<script>タグにsetup属性を追加します:<script setup>- トップレベルのバインディング(変数、関数、インポート)はテンプレートで自動的に使用可能になるため、
returnは不要です - props とイベントには
defineProps()とdefineEmits()を使用します(インポートは不要です) - TypeScript で props のデフォルト値を指定するには、
withDefaults()を使用します - インポートしたコンポーネントは、明示的に登録しなくてもテンプレートで自動的に使用可能になります
詳細
<script setup> の構文とその概要を詳しく見ていく前に、2 つの概念、単一ファイルコンポーネントとComposition APIを簡単におさらいしましょう。
Vue の SFC を使うと、1 つの .vue ファイル内にコンポーネントの HTML/CSS と JS をすべて定義できるため、ロジックをまとめられます。単一ファイルコンポーネントは、次の 3 つの部分で構成されます。
<template>
</template>
<script>
// JavaScript logic goes here
</script>
<style>
/* CSS styles go here */
</style>
<template> にはプレーンな HTML でコンポーネントのマークアップを記述し、<script> にはコンポーネント内のすべての JS ロジックを含むコンポーネントオブジェクトのコンストラクターをエクスポートし、<style> にはコンポーネントのすべてのスタイルを記述します。
Composition API は、Vue の主要な機能を表すスタンドアロン関数を提供します。これらの関数は主に、Composition API を使用するためのエントリーポイントとなる単一の setup() オプション内で使用します。
<script>
export default {
name: "MyComponent",
setup() {
// the setup function
},
};
</script>
Composition API が従来の Options API 構文に比べてどのような利点をもたらすかについて、詳しくはコンポーザブルガイドをお読みください。
<script setup>
<script setup> は、Composition API で Vue のオプションを定義する際に、より簡潔で効率的な構文を実現するコンパイル時のシンタックスシュガーです。Vue のドキュメントによると、SFC と Composition API の両方を使用する場合に推奨される構文です。
<script setup> ブロックを使うと、コンポーネントのロジックを 1 つのブロックにまとめられるため、明示的な setup() 関数が不要になります。<script setup> 構文を使うには、<script /> ブロックに setup 属性を追加するだけです。
<script setup>
// ...
</script>
次に、<script setup> で変わる主な構文上の違いを見ていきましょう。
return 文が不要
<script setup> 構文では、ブロックの末尾に return 文を定義する必要がありません。トップレベルで宣言したバインディング(関数、変数、インポートなど)は、すぐにテンプレートからアクセスして使用できます。
変更前
<template>
<div>
<p>Count: {{ count }}</p>
<p>Username: {{ state.username }}</p>
<button @click="increment">Increment Count</button>
</div>
</template>
<script>
import { ref, reactive, onMounted } from "vue";
setup() {
const count = ref(0);
const state = reactive({username: "John"});
const increment = () => {
count.value++;
};
onMounted(() => {
console.log("Component mounted");
});
return {
count,
state,
increment
};
},
</script>
変更後
<template>
<div>
<p>Count: {{ count }}</p>
<p>Username: {{ state.username }}</p>
<button @click="increment">Increment Count</button>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
const count = ref(0);
const state = reactive({ username: "John" });
const increment = () => {
count.value++;
};
onMounted(() => {
console.log("Component mounted");
});
</script>
ローカルでのコンポーネント登録が不要
コンポーネントのインポートは、components オプションで明示的に宣言しなくても、<script setup> ブロック内で自動的に認識、解決されます。
変更前
<template>
<ButtonComponent />
</template>
<script>
import ButtonComponent from "./components/ButtonComponent.vue";
export default {
setup() {
// the setup function
},
components: {
ButtonComponent,
},
};
</script>
変更後
<template>
<ButtonComponent />
</template>
<script setup>
import { ButtonComponent } from "./components/Button";
</script>
defineProps()
defineProps() 関数を使うと、<script setup> ブロック内で props に直接アクセスできます。
変更前
<template>
<button>{{ buttonText }}</button>
</template>
<script>
export default {
props: {
buttonText: String,
},
};
</script>
変更後
<template>
<button>{{ buttonText }}</button>
</template>
<script setup>
const { buttonText } = defineProps({
buttonText: String,
});
</script>
defineProps() を使うと、純粋な TypeScript で props の形状を宣言することもできます。
<template>
<button>{{ buttonText }}</button>
</template>
<script setup lang="ts">
const { buttonText } = defineProps<{ buttonText: string }>();
</script>
上記の型のみの宣言で props のデフォルト値を指定するには、コンパイラーマクロ withDefaults() を使用します。
<template>
<button>{{ buttonText }}</button>
</template>
<script setup lang="ts">
const { buttonText } = withDefaults(defineProps<{ buttonText: string }>(), {
buttonText: "Initial button text",
});
</script>
defineProps は <script setup> 内でのみ使用でき、インポートせずに利用できます。
defineEmits()
props と同様に、コンポーネント内で defineEmits() 関数を使うと、<script setup> ブロック内でカスタムイベントを直接発火できます。
変更前
<template>
<button @click="closeButton">Button Text</button>
</template>
<script>
export default {
emits: ["close"],
setup(props, { emit }) {
const closeButton = () => emit("close");
return {
closeButton,
};
},
};
</script>
After
<template>
<button @click="closeButton">Button Text</button>
</template>
<script setup>
const emit = defineEmits(["close"]);
const closeButton = () => emit("close");
</script>
defineProps と同様に、defineEmits は <script setup> 内でのみ使用できる特別なキーワードで、インポートせずに使用できます。また、TypeScript 環境で作業する場合は、型を直接渡すこともできます。
<template>
<button @click="closeButton">Button Text</button>
</template>
<script setup lang="ts">
const emit = defineEmits<{ (e: "close"): void }>(["close"]);
const closeButton = () => emit("close");
</script>
<script setup> と setup() の比較
返されるオプションが多く、ローカル登録された子コンポーネントも多数ある大規模なコンポーネントでは、<script setup> 構文によって多くの定型コードを削減できます。これにより、コンポーネントの定義がすっきりとして要点が明確になり、コードベースの可読性と保守性の向上にもつながります。
定型コードを削減できるだけでなく、<script setup> 構文は実行時のパフォーマンスと IDE の型推論のパフォーマンスを向上させ、TypeScript で props や発行されるイベントの形状を宣言できるようにします。
<script setup> 構文を使用する際に留意すべき変更点の一覧については、以下の公式 Vue ドキュメントを参照してください。