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

143814_sTXx_2647760.png

这个错误的来自一个webpack引入一个webpack-dev-server模块导致了,具体原因不明确:

143928_rjkX_2647760.png

 

三、解决方案

修改文件:

[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;
    };

  

也就是说,我们其实可以手动指定打包之后的输出目录。

posted @ 2021-09-14 11:48  明明一颗大白菜  阅读(862)  评论(0编辑  收藏  举报
<-- -->