1. 程式人生 > 其它 >laravel中使用vue熱載入時 Cannot read property 'call' of undefined BUG解決方案

laravel中使用vue熱載入時 Cannot read property 'call' of undefined BUG解決方案

一、檔案初始化

[routes/web.php]

Route::group(['namespace' => 'Home'], function () {
    Route::get( '/', 'IndexController@index');
});

[app/Http/Controllers/Home/IndexController.php]

namespace App\Http\Controllers\Home;
 
class IndexController
{
    public function index () {
        return view('home.index');
    }
}

  

[resources/views/layouts/app.blade.php]

<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title> @yield('title', 'Laravel') </title>
</head>
<body>
<div id="app">
@yield('content')
</div>
<script src="{{ mix('/js/app.js') }}"></script>
</body>
</html>

  

[resources/views/home/index.blade.php]

@extends('layouts.app')

@section('content')
<example></example>
@endsection

  

[resources/assets/js/app.js]

import Vue from 'vue'
 
import Example from './components/example.vue'
 
Vue.component( 'example', Example)
 
new Vue({
    el: '#app'
})

  

[resources/assets/js/components/example.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>

  

[webpack.mix.js]

let mix = require('laravel-mix');
 
mix
    .js('resources/assets/js/app.js', 'public/js')
    .sass('resources/assets/sass/app.scss', 'public/css')

  

以上這個檔案狀況然後再執行以下命令:

php artisan serve
npm run hot

  

然後我們開啟頁面 http://localhost:8000/

這個時候,頁面是正常的vue和webapck-dev-server以及熱載入都是正常的。

二、程式碼分離(按官方文件分離後出現BUG)

但是,考慮到這樣開發之後,所有的vue程式碼全部打包到了 [public/js/app.js]這一個檔案中,所以開始考慮使用webpack的程式碼分離功能。

根據 laravel-mix的官方文件

https://github.com/JeffreyWay/laravel-mix/blob/master/docs/extract.md#library-code-splitting

然後我們修改檔案:

[webpack.mix.js]

let mix = require('laravel-mix');
 
mix
    .js('resources/assets/js/app.js', 'public/js')
    .extract(['vue'])
    .sass('resources/assets/sass/app.scss', 'public/css')

  

這樣修改之後,我們將 vue作為供應庫(第三方庫)打包在 [js/vendor.js] ,並同時生成 [js/manifest.js]

然後我們再將 manifest.js , vendor.js引入到模板:

[resources/views/layouts/app.blade.php]

<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title> @yield('title', 'Laravel') </title>
</head>
<body>
    <div id="app">
        @yield('content')
    </div>
    <script src="{{ mix('/js/manifest.js') }}"></script>
    <script src="{{ mix('/js/vendor.js') }}"></script>
    <script src="{{ mix('/js/app.js') }}"></script>
</body>
</html>

  

再重新執行以下命令:

php artisan serve
npm run hot

  

然後我們開啟頁面 http://localhost:8000/

此時我們發現控制檯會出現一個這樣的錯誤:Cannot read property 'call' of undefined

這個錯誤的來自一個webpack引入一個webpack-dev-server模組導致了,具體原因不明確:

三、解決方案

修改檔案:

[webpack.mix.js]

let mix = require('laravel-mix');
 
mix
    .js('resources/assets/js/app.js', 'public/js')
    .extract(['vue'], 'public/js/vendor.js')
    .sass('resources/assets/sass/app.scss', 'public/css')

  

然後重新執行

npm run hot

  

這個時候就沒問題。

關於mix.extract() 這個方法我們檢視原始碼是這樣的

 
    /**
     * Register vendor libs that should be extracted.
     * This helps drastically with long-term caching.
     *
     * @param {Array}  libs
     * @param {string} output
     */
    extract(libs, output) {
        Config.extractions.push({ libs, output });
 
        return this;
    };

  

也就是說,我們其實可以手動指定打包之後的輸出目錄。