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;
};
也就是说,我们其实可以手动指定打包之后的输出目录。

浙公网安备 33010602011771号