场景

  • laravel5.7项目默认的laravel-mix编译
  • 异步路由,观察http异步组件加载成功,路由配置正确

@babel/plugin-syntax-dynamic-import 已正确安装配置并使用

  • 前端没有一个页面有显示内容,只要在路由出口区的部分全无显示

报错

  • 3个警告

app.js:42886 [vue-router] Failed to resolve async component default: TypeError: Cannot read property ‘call’ of undefined
app.js:42886 [vue-router] uncaught error during route navigation:
[vue-router] Failed to resolve async component default: TypeError: webpack_require(…) is not a function

  • 1个致命性错误

app.js:44767 TypeError: Cannot read property ‘call’ of undefined
at webpack_require (app.js:64)
at Object…/node_modules/css-loader/index.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/lib/loader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/global/Navigation.vue?vue&type=style&index=0&lang=scss&
(components-global-Navigation-vue~layouts-Layout-vue.js:172)

排错

  • js控制台报错,疑似js逻辑有问题,特别at __webpack_require__ (app.js:64),很显然这是一个webpack自带的模板代码导入,但改为同步代码后正常,排除,只能确认错误与异步行为相关
  • 警告信息is not a function,貌似vue-router异步组件被认为返回的不是一个函数?但network显示可以正常加载 ,返回状态都是200,说明异步组件在前端加载是ok的
  • 猜想*webpack_require* 这种地方报错,只能表明webpack某插件(可影响全局操作及相关loader运行)在某种(这里是异步执行)情况下执行,出现了异常,导致不能正常添加属性方法,从而有TypeError: Cannot read property ‘call’ of undefined的警告,检查流程如下
    • mix-manifest.json检查比对导入的路径信息与在服务器端的真实映射文件 ok
    • 查阅laravel-mix依赖的插件,关键主要信息如下
  "laravel-mix": {
            "version": "4.0.15",
            "dev": true,
            "requires": {
                "@babel/core": "^7.2.0",
                "@babel/plugin-proposal-object-rest-spread": "^7.2.0",
                "@babel/plugin-transform-runtime": "^7.2.0",
                "@babel/preset-env": "^7.2.0",
                "@babel/runtime": "^7.2.0",
                "extract-text-webpack-plugin": "v4.0.0-beta.0"
                "friendly-errors-webpack-plugin": "^1.6.1",
                "optimize-css-assets-webpack-plugin": "^5.0.1",
                "terser-webpack-plugin": "^1.1.0",
                "vue-loader": "^15.4.2",
                "webpack": "^4.27.1",
                "webpack-cli": "^3.1.2",
                "webpack-dev-server": "^3.1.14",
            }
        },

分析

  • Cannot read property 'call' of undefined警告信息为凭据,查询官方资源发现有一个关于extract-text-webpack-plugin的issue值得关注

TL;DR Use mini-css-extract-plugin instead ?
The webpack >= v4.0.0 ‘support’ for extract-text-webpack-plugin was moved to mini-css-extract-plugin as more lightweight approach for webpack >= v4.0.0 and ETWP entered maintenance mode. We are sorry for the inconvenience here, but ETWP reached a point where maintaining it become too much of a burden and it’s not the first time upgrading a major webpack version was complicated and cumbersome due to issues with ETWP. The mid-term plan is integrate CSS support directly into webpack to avoid this kind of issue in the future

  • 简单点讲:webpack4以上放弃了对extract-text-webpack-plugin插件的治疗,需要用`MiniCssExtractPlugin 来修复这个问题。判断可能是该插件在异步操作抽取css时,出错。
  • __webpack_require__依赖于mix-mainifest.json,而且webpack的一些内部引导代码会依据此内容,生成moduleid(模块标识),管理模块文件的加载顺序及引用次数。

解决

  • 基于上述两点有如下操作
  • 第一次使用laravel-mix操作只用同步形式生成CSS,不涉及js的编译操作
  • 二次编译生成的异步js,确保mix-mainifest.json只有纯js模块关联
  • 在入口html模板文件内,引入全局第一次编译的css就可以了

小结

  • 对于异步组件加载,需要加载css文件,但extract-text-webpack-plugin在异步中不给力的加载行为,会有Cannot read property 'call' of undefined警告,间接影响webpack的模板代码加载,最终出现__webpack_require__(...) is not a function,从而报致命错误Cannot read property 'call' of undefined

  • 所以如果不用替代插件,需要在__webpack_require__的导入内容内容上作手脚,将CSS相关的异步加载排除在外,不给webapck来处理加载,交给浏览器同步下载。

  • 附laravel-mix配置文件

const mix = require('laravel-mix');

// 先单独编译css,二次编译关闭,主要是避免mix配置对象污染
// mix.sass('resources/sass/app.scss', 'public/css')

mix.js('resources/js/app.js', 'public/js')
    .webpackConfig({
        output: {
            chunkFilename: 'js/[name].js'
        },
        module: {
            rules: [{
                    test: /\.jsx?$/,
                    exclude: /node_modules(?!\/foundation-sites)|bower_components/,
                    use: [{
                        loader: 'babel-loader',
                        // 使用mix默认配置babel,会读取项目根目录下的,babelrc配置(内支持import函数)
                        options: Config.babel()
                    }]
                }
            ]
        },
        // 配置路径别名
        resolve: {
            alias: {
                '@': path.resolve(__dirname, 'resources/sass')
            }
        }
    })
Logo

前往低代码交流专区

更多推荐