🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Q&A

1回答

8551閲覧

Vueの単一ファイルコンポーネントで"Failed to mount component: template or render function not defined"を解決したい

barbaz

総合スコア15

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

0グッド

1クリップ

投稿2019/12/01 11:14

長々と書きましたが、以下のような状況です。解決策などありますでしょうか?

事前の準備

まず、単一ファイルコンポーネントを使う前に、コンポーネントを使った簡単なサンプルを作成しました。

index.jsです。

js

1let test_comp = { 2 template: ` 3 <div> 4 <div>hello world</div> 5 </div> 6 ` 7}; 8 9const vm = new Vue({ 10 el: "#app", 11 components: { 12 "mycomp": test_comp, 13 }, 14});

次にindex.htmlです。

html

1<html> 2 <head> 3 <meta charset="utf8"> 4 </head> 5 <body> 6 <div id="app"> 7 <mycomp></mycomp> 8 </div> 9 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 10 <script src="index.js"></script> 11 </body> 12</html>

上記の例の場合、問題なくコンポーネントを使った表示(hello world)がされました。ここで、このコンポーネントを「単一ファイルコンポーネント」にしようとして、今回のエラーが発生しました。

問題のコード

単一ファイルコンポーネントを使う場合 webpack も必要とのことでしたので、以下のようにしました。

まず webpack.config.js です。

js

1const path = require('path'); 2const { VueLoaderPlugin } = require("vue-loader"); 3 4module.exports = { 5 mode: 'development', 6 entry: './src/index.js', 7 output: { 8 filename: 'index.js', 9 path: path.resolve(__dirname, 'dist'), 10 }, 11 plugins: [ 12 new VueLoaderPlugin(), 13 ], 14 module: { 15 rules: [ 16 { 17 test: /.vue$/, 18 use: ['vue-loader', 'style-loader',], 19 }, 20 { 21 test: /.(scss|css)/, 22 use: ['style-loader',] 23 } 24 ], 25 }, 26};

このときの package.json です。

json

1{ 2 "name": "vue_test", 3 "version": "1.0.0", 4 "description": "", 5 "main": "index.js", 6 "scripts": { 7 "test": "echo \"Error: no test specified\" && exit 1" 8 }, 9 "keywords": [], 10 "author": "", 11 "license": "ISC", 12 "devDependencies": { 13 "style-loader": "^1.0.1", 14 "vue": "^2.6.10", 15 "vue-loader": "^15.7.2", 16 "vue-template-compiler": "^2.6.10", 17 "webpack": "^4.41.2", 18 "webpack-cli": "^3.3.10" 19 } 20}

ここで、以下の hello_world.vue を追加しました。これは上記の index.js からコンポーネント部分を抜き出しただけです。

vue

1<template> 2 <div> 3 <div>hello world</div> 4 </div> 5</template> 6 7<script> 8</script> 9 10<style scoped> 11</style>

それによって index.js も以下のように変更しました。

js

1import test_comp from "./hello_world.vue" 2 3const vm = new Vue({ 4 el: "#app", 5 components: { 6 "mycomp": test_comp, 7 }, 8});

index.html は変更していませんが、一応載せます。

html

1<html> 2 <head> 3 <meta charset="utf8"> 4 </head> 5 <body> 6 <div id="app"> 7 <mycomp></mycomp> 8 </div> 9 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 10 <script src="index.js"></script> 11 </body> 12</html>

以上のファイルのディレクトリ構成はこんな感じです。

dist/ index.html src/ index.js hello_world.vue webpack.config.js package.json

ここで、npx webpackでビルド後、dist内にindex.jsが生成されました。ただ、dist/index.htmlを表示するとタイトルのエラーが出てしまいます。

試したこと

このエラーについて検索すると、require("hello_world.js").defaultのようにすると出てきたので、以下のように index.js を変更しましたが同じエラーが発生しました。

js

1const test_comp = require('./hello_world.vue').default; 2 3const vm = new Vue({ 4 el: "#app", 5 components: { 6 "mycomp": test_comp, 7 }, 8});

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

これで直るかはわからないのですが

components ではなく
template プロパティまたは render プロパティを定義してみてください。

1. 変更点

以下 render プロパティを定義する方法を書きます。

1.1. JavaScript ファイル

javascript

1// 2// 変更前 3// 4import test_comp from "./hello_world.vue" 5 6const vm = new Vue({ 7 el: "#app", 8 components: { 9 "mycomp": test_comp, 10 }, 11});

javascript

1// 2// 変更後 3// 4import test_comp from "./hello_world.vue" 5 6const vm = new Vue({ 7 el: "#app", 8 // components: { 9 // "mycomp": test_comp, 10 // }, 11 render: h => h(test_comp) 12});

1.2. HTML ファイル

<!-- 変更前 --> <html> <head> <meta charset="utf8"> </head> <body> <div id="app"> <mycomp></mycomp> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="index.js"></script> </body> </html>
<!-- 変更後 --> <html> <head> <meta charset="utf8"> </head> <body> <div id="app"> <!-- <mycomp></mycomp> --> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="index.js"></script> </body> </html>

2. 補足

2.1. エラーについて

components プロパティを使う書き方は、正しい様に自分も思えるのですが。もし上記の解決策で通るなら Webpack でコンパイルする場合は、template プロパティまたは render プロパティの指定が、必要になるのだと思われます。

"コンポーネントのマウントに失敗しました: template または render 関数が未定義です。"
"Failed to mount component: template or render function not defined"

2.2. 優先順位

id=app で指定したものの配下は消されてしまうようです。なので id=app は子要素を持たない様に注意してください。

The render function has priority over the render function compiled from template option or in-DOM HTML template of the mounting element which is specified by the el option.
https://vuejs.org/v2/api/#render

2.3. 描画関数

render 関数, 日本語訳で描画関数とよく書かれています。

javascript

1 // #app で指定されたタグが App タグになる。 2 render: h => h(App)

javascript

1 // # app で指定された DOM が div タグになる 2 render: h => h(div)

SFC の template タグで囲んでいるものも実際には関数で書くことができます。
細かいことをするときに必要になるそうです。

投稿2019/12/01 14:19

編集2019/12/01 14:33
nico25

総合スコア830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

barbaz

2019/12/01 23:08 編集

回答ありがとうございました。 ご指摘の通り render 関数を使い、index.js を以下のようにしました。 ```js import test_comp from "./hello_world.vue" const vm = new Vue({ el: "#app", render: h => h(test_comp), }); ``` さらに index.html の子要素を取り除いてみました。結果としては、最初と同じエラーが出てしまいました。
nico25

2019/12/02 01:53

再度、render 関数を使用するべき他にも箇所がないか 確認しましたが見当たりませんでした。 心苦しいですが、差し当たって他に思い当たるものがありません... orz
barbaz

2019/12/02 14:06

いえいえ、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問