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