【问题标题】:Failed to mount component on new laravel 5.5 project无法在新的 laravel 5.5 项目上挂载组件
【发布时间】:2018-03-01 05:32:17
【问题描述】:

我和一个同事在使用 vue js 时,在新旧 laravel 项目中一直遇到问题,因为我们每次在浏览器控制台中都会收到以下错误

>`[Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <Example>
       <Root>
warn @ app.js:32173
mountComponent @ app.js:34241
Vue$3.$mount @ app.js:39678
Vue$3.$mount @ app.js:41868
init @ app.js:35260
createComponent @ app.js:36909
createElm @ app.js:36852
createChildren @ app.js:36980
createElm @ app.js:36885
patch @ app.js:37394
Vue._update @ app.js:34147
updateComponent @ app.js:34271
get @ app.js:34614
Watcher @ app.js:34603
mountComponent @ app.js:34275
Vue$3.$mount @ app.js:39678
Vue$3.$mount @ app.js:41868
Vue._init @ app.js:36000
Vue$3 @ app.js:36085
(anonymous) @ app.js:802
__webpack_require__ @ app.js:20
(anonymous) @ app.js:775
__webpack_require__ @ app.js:20
(anonymous) @ app.js:63
(anonymous) @ app.js:66`

即使在使用默认 Example.vue 的新 laravel 项目中也会发生这种情况

我当前的代码如下

例子.vue

<template>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-default">
                    <div class="panel-heading">Example Component</div>

                    <div class="panel-body">
                        I'm an example component!
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        mounted() {
            console.log('Component mounted.')
        }
    }
</script>

assets/js/app.js

/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');

window.Vue = require('vue');

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

Vue.component('example', require('./components/Example.vue'));

const app = new Vue({
    el: '#app'
});

assets/js/bootstrap.js

window._ = require('lodash');

/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

try {
    window.$ = window.jQuery = require('jquery');

    require('bootstrap-sass');
} catch (e) {}

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allows your team to easily build robust real-time web applications.
 */

// import Echo from 'laravel-echo'

// window.Pusher = require('pusher-js');

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: 'your-pusher-key'
// });

welcome.blade.php

<!doctype html>
<html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" value="{{csrf_token()}}">
        <title>Laravel</title>

        <!-- Fonts -->
        <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
        <link rel="stylesheet" type="text/css" href="/css/app.css">
        <!-- Styles -->

    </head>
    <body>

        <div id="app">
            <example></example>
        </div>
        <script type="text/javascript" src="/js/app.js"></script>
    </body>
</html>

webpack.mix.js

let mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css');

package.json

{
  "private": true,
  "scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch-poll": "npm run watch -- --watch-poll",
    "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "prod": "npm run production",
    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  },
  "devDependencies": {
    "axios": "^0.16.2",
    "bootstrap-sass": "^3.3.7",
    "cross-env": "^5.0.1",
    "jquery": "^3.1.1",
    "laravel-mix": "^1.0",
    "lodash": "^4.17.4",
    "vue": "^2.1.10"
  },
  "dependencies": {
    "cross-env": "^5.0.5",
    "vee-validate": "^2.0.0-rc.17"
  }
}

【问题讨论】:

  • 请您显示您的代码,即您初始化Vue 实例的位置以及元素安装位置的html?
  • 愚蠢的问题,但您是否确保Example.vue 组件实际上在./components 目录中,而不是assets/js/component.vue
  • 是的 app.js 和 bootstrap.js 在 assets/js 中,Example.js 在 assets/js/components 中
  • 我认为我应该提到我正在使用 npm 5.4.2 和节点 8.5.0
  • 你在使用 Laravel Mix 和默认的 webpack 配置吗?

标签: laravel vue.js


【解决方案1】:

如果您没有更改任何内容并且正确捆绑和安装了 JavaScript,那么问题可能在于默认的 Laravel 实现。

您收到的错误消息意味着您很可能将运行时构建(没有模板编译器的 vue)导入到需要模板编译器的应用程序中。

为了更好地理解这一点,Vue 将所有内容编译为渲染函数(本质上是网页的纯 JavaScript 表示)。使用 single file components 时,您最终会得到一个安装到 Vue 实例的基本组件,它提供您所有的视图,所以,我们会得到这样的结果:

components/App.vue

<template>
  <div>
    I'm a base component
    <!-- vue-router will mount components here -->
    <router-view></router-view>
  </div>
</template>

app.js

import App from './components/App.vue' 

// "h" is just a standard taken from JSX
new Vue({
  render: h => h(App)
}).$mount("#app");

app.blade.php

<html>
  <head>
    <!-- head stuff -->
  </head>
  <body>
    <div id="app"></div>
    <script src="app.js"></script>
  </body>
</html>

这里重要的是app.blade.php 仅充当整个应用程序的安装点,App.vue 充当基础组件,轮流服务于其他所有视图(通常通过vue-router 完成) .为了让它工作,我们需要通过 webpack 将我们的资产编译成app.js,它为我们创建了所有的渲染函数,所以我们不需要编译器,因为一切都已经编译好了。剩下要做的就是在routes/web.php 中创建一个路由来提供索引刀片文件。这实际上是在设置一个 SPA。

Laravel 鼓励你做的是直接在你的标记中添加 Vue 组件并全局注册组件,所以你会这样做:

app.js

Vue.component('my-component', require('./components/My-component.vue'));

const app = new Vue({
    el: '#app'
});

index.blade.php

<html>
  <head>
    <!-- head stuff -->
  </head>
  <body>
    <div id="app">
      <my-component></my-component>
    </div>
    <script src="app.js"></script>
  </body>
</html>

因为我们已经将组件添加到标记中,所以我们需要模板编译器在运行时将 app div 标签之间的位编译成渲染函数。所以,我们需要导入 vue + 编译器,这是 Laravel Mix应该为你做的,通过给 Vue 的 runtime + compiler 版本起别名(你可以找到如何做到这一点的细节 in the docs)。

老实说,我不是 Laravel Mix 的粉丝,因为它抽象了作为开发人员需要了解的关键实现细节,例如,“Laravel Mix 是否正确地为 Vue + compiler 构建别名”?在你的情况下,它看起来不是。

最后,直接设置你自己的 webpack 配置通常更容易,这样你就可以完全控制你的配置,你可以使用 Vue 的 webpack simple 配置作为基础。

一旦你正确设置了 webpack,你只需将别名添加到 webpack 配置中,你就有了 runtime + compiler 构建:

 resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  }

我意识到我并没有真正考虑到您的具体问题。我很难相信 Webpack Mix 没有正确地为 vue + compiler 构建别名,但这就是该消息所暗示的。不过,希望这可以为您提供足够的信息来找出问题所在。

【讨论】:

  • 我会记住这一点,因为这是一些非常有用的信息。我会尝试看看我是否可以找到 laravel 的 webpack 的问题,因为它已经集成,如果我找不到问题,我会尝试你设置我自己的 webpack 配置的建议
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
  • 2018-02-08
相关资源
最近更新 更多