Nuxt/VueでdefineProps・defineEmitsのimportが不要な理由

この記事で解決できるお悩み
  • defineProps や defineEmits をなぜimportせずに使えるのか疑問に思っている
  • Compiler Macros(コンパイラマクロ)という言葉を見かけたが、何のことか分からない

Vue 3 の <script setup> を書いていると、defineProps や defineEmits が 何もimportしていないのに使えることに気づきます。 通常、外部の関数を使う場合は import { ref } from 'vue' のように明示的なimportが必要なはずです。 なぜこれらだけimportが不要なのでしょうか?

その答えが Compiler Macros(コンパイラマクロ) という仕組みです。 この記事では、Compiler Macrosとは何か・何のために存在するのかを、解説します。

目次

defineProps・defineEmitsにimportが不要な理由

結論: defineProps と defineEmits は、実行時に呼び出される通常の関数ではなく、 コンパイル時にVueコンパイラが変換するマクロ(Compiler Macros) だからです。 実際のJavaScript関数として存在しないため、importする必要がありません。

通常の関数(例:ref)は、ブラウザでのJavaScript実行時にも実体として存在する関数です。

// ref は実行時に存在するので import が必要
import { ref } from 'vue'

const count = ref(0)

一方、defineProps や defineEmits は <script setup> の中でしか使えません。 コンパイラがコードをビルドする段階で別のコードに変換されてしまうため、 ブラウザが実行するJavaScriptには残っていないのです。

// ✅ import なしで使える
<script setup>
const props = defineProps({
  title: String,
  count: Number
})

const emit = defineEmits(['update', 'delete'])
</script>

もし <script setup> の外で使おうとするとエラーになります。これがマクロである証拠です。

Compiler Macros(コンパイラマクロ)とは

Compiler Macros(コンパイラマクロ)とは、VueのSFCコンパイラ(Single File Componentのビルドツール)が 特別に認識し、コンパイル時に別のコードへと変換するシンタックスのことです。

プログラミングにおける「マクロ」とは、もともと「コード変換の仕組み」を指します。 CやLispでのマクロが有名ですが、Vueにおいても同様に「書いたコードが別のコードに変換される」という動作をします。

主なCompiler Macros一覧

スクロールできます
マクロ名役割使用可能な場所
defineProps()コンポーネントのpropsを定義する<script setup> のみ
defineEmits()コンポーネントが発行するイベントを定義する<script setup> のみ
defineExpose()親コンポーネントへ公開するプロパティを指定する<script setup> のみ
withDefaults()definePropsにデフォルト値を設定する<script setup> のみ
defineOptions()コンポーネントオプション(name等)を定義する<script setup> のみ
(Vue 3.3+)

Compiler Macrosは何のためにあるのか

Compiler Macrosが存在する理由は主に2つです。

① <script setup> をシンプルに書けるようにするため

<script setup> が登場する前は、defineComponent を使ってより冗長な書き方をする必要がありました。

// <script setup> 以前の書き方
export default defineComponent({
  props: {
    title: String,
    count: Number
  },
  emits: ['update', 'delete'],
  setup(props, { emit }) {
    // ロジック...
    return {}
  }
})

Compiler Macrosによって、同じことをより直感的に書けるようになりました。

// <script setup> + Compiler Macros を使った書き方
<script setup>
const props = defineProps({
  title: String,
  count: Number
})

const emit = defineEmits(['update', 'delete'])
</script>

記述量が減るだけでなく、TypeScriptとの親和性も上がり、型推論も効きやすくなっています。

② コンパイル時の型安全を実現するため

TypeScriptを使う場合、defineProps にジェネリクスで型を渡すことができます。 これはコンパイル時のみ意味を持つ記法であり、まさにマクロならではの表現です。

<script setup lang="ts">
// ジェネリクスによる型定義(TypeScript専用の書き方)
const props = defineProps<{
  title: string
  count: number
}>()
</script>

通常の関数では、ジェネリクスは実行時の型情報として扱われます。 しかしコンパイラマクロとして処理することで、 型情報をそのままコンポーネントのpropsバリデーションに変換できるのです。

注意:<script setup> 以外では使えない

Compiler Macrosはあくまでコンパイラが処理する特殊な構文です。 <script setup> の外や、通常の .js / .ts ファイルでは使用できません。

// ❌ これはエラーになる
import { defineProps } from 'vue' // defineProps は export されていない

// ❌ <script setup> 以外では使えない
<script>
export default {
  setup() {
    const props = defineProps({ title: String }) // エラー
  }
}
</script>

NuxtでもCompiler Macrosは同じように使える

NuxtはVue 3をベースにしているため、Compiler Macrosはまったく同じように使用できます。 さらにNuxtは独自の自動インポート機能も持っており、 ref や computed といった Vue Composition API の関数も 明示的なimportなしで使えるケースがあります。

ただし、これはNuxtの「Auto Import」機能によるものであり、Compiler Macrosとは別の仕組みです。 混同しないよう注意しましょう。

まとめ

最後まで読んでいただき、ありがとうございました!

今回は、「Nuxt/VueでdefineProps・defineEmitsのimportが不要な理由」についてご紹介しました。

ポイントを整理すると、以下のとおりです。

  • defineProps / defineEmits はCompiler Macros(コンパイラマクロ)であり、コンパイル時に別のコードへ変換される
  • 実行時に実体として存在する関数ではないため、importは不要(というよりできない)
  • Compiler Macrosは <script setup> 構文を簡潔に書けるようにするために設計されている
  • NuxtのAuto ImportとCompiler Macrosは別物であり、混同しないことが大切

「なんとなく使えてるからいいか」で済ませるのも一つの選択ですが、 こうした仕組みを理解しておくと、エラーの原因を特定したり、 より適切なコードを書いたりする力につながります。

この記事が気に入ったら
フォローしてね!

シェアしていただけると大変励みになります!
  • URLをコピーしました!
  • URLをコピーしました!
目次