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; };
也就是說,我們其實可以手動指定打包之後的輸出目錄。