タイトル: Emitted value instead of an instance of Error
SEOタイトル: 【Vue.jsエラー】Emitted value instead of an instance of Error
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="1" cellspacing="1" style="width:1000px">
<thead><tr><th style="background-color:#f39c12;color:#ffffff;text-align:left">この記事の要点</th></tr></thead>
<tbody><tr><td style="background-color:#fef9e7"><ul>
<li><code>(Emitted value instead of an instance of Error)</code> は<strong>Vue.js のコンポーネントテンプレートエラー</strong></li>
<li>原因: Vue 2 系の制約「<code><template></code> 直下に複数ルート要素」</li>
<li>対処: ルート要素を 1 つだけにする(<code><div></code> 等でラップ)</li>
<li><strong>Vue 3 ではマルチルート OK</strong>: Vue 3 へ移行すれば解消</li>
<li>Vue 2 でも <code>functional component</code> や JSX なら複数ルート可</li>
</ul></td></tr></tbody>
</table>
<p> </p>
<h2>エラーの状況</h2>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code>(Emitted value instead of an instance of Error)
Error compiling template:
<template>
<div>...</div>
<div>...</div>
</template>
- Component template should contain exactly one root element.
If you are using v-if on multiple elements, use v-else-if to chain them instead.</code></pre>
<p>Vue 2 系の制約: 1 つのコンポーネントテンプレートには<strong>ルート要素が 1 つだけ</strong>でなければなりません。</p>
<h2>原因と対処</h2>
<h3>原因 1: 複数のルート要素</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- ダメな例 -->
<template>
<div class="header">ヘッダー</div>
<div class="body">本文</div>
<div class="footer">フッター</div>
</template>
<!-- 修正: 1 つの親要素でラップ -->
<template>
<div class="wrapper">
<div class="header">ヘッダー</div>
<div class="body">本文</div>
<div class="footer">フッター</div>
</div>
</template></code></pre>
<h3>原因 2: 条件分岐で複数ルート</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- ダメな例 -->
<template>
<div v-if="isLoggedIn">ようこそ</div>
<div v-else>ログインしてください</div>
</template>
<!-- これは実は OK -->
<!-- v-if と v-else は単一ルートとして扱われる -->
<!-- ダメな例 (条件複数) -->
<template>
<div v-if="status === 'loading'">読込中</div>
<div v-if="status === 'success'">完了</div> <!-- ← v-else-if にすべき -->
<div v-if="status === 'error'">エラー</div>
</template>
<!-- 修正: v-else-if でチェーン -->
<template>
<div v-if="status === 'loading'">読込中</div>
<div v-else-if="status === 'success'">完了</div>
<div v-else-if="status === 'error'">エラー</div>
</template></code></pre>
<h3>原因 3: コメントが影響することも</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- ダメな例 (古い Vue だとコメントも要素扱い) -->
<template>
<!-- コメント -->
<div>本体</div>
</template>
<!-- 修正 -->
<template>
<div>
<!-- コメント -->
本体
</div>
</template></code></pre>
<h3>原因 4: 改行 / テキストノードが混在</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- ダメな例 -->
<template>
テキスト
<div>div</div>
</template>
<!-- 修正 -->
<template>
<div>
テキスト
<div>div</div>
</div>
</template></code></pre>
<h2>Vue 3 ではマルチルート可</h2>
<p>Vue 3 から「Fragments」が導入され、複数ルート要素 OK になりました:</p>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- Vue 3 ではこれが OK -->
<template>
<header>ヘッダー</header>
<main>本文</main>
<footer>フッター</footer>
</template></code></pre>
<h3>属性の継承注意</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- 親から渡される属性は明示的に -->
<template>
<header v-bind="$attrs">ヘッダー</header> <!-- どこに属性を付けるか明示 -->
<main>本文</main>
</template>
<script setup>
defineOptions({
inheritAttrs: false // 暗黙の継承を無効化
});
</script></code></pre>
<h2>Vue 2 で複数ルートを扱う方法</h2>
<h3>① Functional Component</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- Vue 2 の functional component -->
<template functional>
<div>
<slot />
<slot name="footer" />
</div>
</template>
<!-- render 関数で複数子要素を返す -->
<script>
export default {
functional: true,
render(h, context) {
return [
h("header", "ヘッダー"),
h("main", context.slots().default),
h("footer", "フッター")
];
}
};
</script></code></pre>
<h3>② JSX で複数ルート (Babel + jsx プラグイン)</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code>export default {
render() {
return [
<header>ヘッダー</header>,
<main>本文</main>,
<footer>フッター</footer>
];
}
};</code></pre>
<h3>③ <template> タグ複数(v-for / v-if のみ)</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- v-for を template で囲める(要素を出力しない) -->
<template>
<ul>
<template v-for="item in items" :key="item.id">
<li>{{ item.name }}</li>
<li class="meta">{{ item.meta }}</li>
</template>
</ul>
</template></code></pre>
<h2>関連エラー</h2>
<table border="1" cellpadding="1" cellspacing="1" style="width:1000px">
<thead><tr><th>エラー</th><th>意味</th></tr></thead>
<tbody>
<tr><td>Component template should contain exactly one root element</td><td>同じエラー(このページ)</td></tr>
<tr><td>v-if/v-else-if/v-else used on different elements</td><td>v-if/v-else が別要素にある</td></tr>
<tr><td>Multiple root nodes returned from render function</td><td>render() が配列を返すが Vue 2</td></tr>
<tr><td>Failed to mount component: template or render function not defined</td><td>template も render() もない</td></tr>
<tr><td>Cannot read property of undefined (in template)</td><td>data 未定義 or 非同期未完了でアクセス</td></tr>
</tbody>
</table>
<h2>Vue 2 → 3 移行のメリット</h2>
<ul>
<li><strong>Fragments</strong>: 複数ルート可、不要な wrapper div 削減</li>
<li><strong>Composition API</strong>: ロジック再利用がより柔軟</li>
<li><strong>パフォーマンス向上</strong>: 仮想 DOM の最適化</li>
<li><strong>TypeScript サポート強化</strong></li>
<li><strong>Vite 連携</strong>: ビルド高速化</li>
<li><strong>Vue 2 は 2024-01 EOL</strong>: セキュリティパッチも終了、移行推奨</li>
</ul>
<h2>関連記事</h2>
<ul>
<li><a href="/article/21291">ライフサイクルフック</a></li>
<li><a href="/article/21292">$nextTick の使い方</a></li>
</ul>