微前端qiankun问题You need to export the functional lifecycles in xxx entry终极解决方案

1,418 阅读4分钟

本文源自道招网的 # 微前端qiankun问题You need to export the functional lifecycles in xxx entry终极解决方案

背景

最近开启了自己Q2的OKR项目,将手上的后台系统,改成微前端模式,方便后续的维护。

目前这个后台系统(知识库管理后台)的部分页面也作为微前端微应用的一部分,嵌入另一个微前端的主应用(综合管理后台)里面的,也就是说它既作为微前端的微应用,也作为了微应用的主应用。

遇到问题

在调试过程中,我尝试将该项目在本地改造成主应用在本地跑起来,同时注册的微应用是它目前的线上版本,但是在实际调试过程中还是遇到了Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry

写本文章时测试发现没问题了。。。上班继续测试下。

Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry,我相信这个报错几乎所有接入微前端的同学都碰到过的。

解决过程

这个官网也给了很明确的解决方案。 官网FAQ

file

原理探索

我觉得应该重点关注图中我划线的1、2、5三点了。

概括来说主要有几点:

  • 看入口文件(也就是React或Vue项目的render根节点的那个文件)是否配置了bootstrapmount等生命周期函数,及时里面的内容是空的,仅一行console也行,但是必须要有。
  • 让qiankun打包后的哪个js文件是上述你暴露了生命周期的入口文件

因为qiankun一般是通过解析html的源代码中解析js,并试图读取哪个是entry。html中引入大于一个js的,就要格外注意entry的配置,方便主应用识别到。

file

上图就是知识库管理后台线上项目的html,可以看到上面引入了三个js,index.xx.js是项目入口,在html中标记了entry向主应用来表明它是entry文件。 作为上述综合管理后台的子应用时,一切正常,但是我在本地调试还是出问题了,Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry

在调试过程中发现qiankun会有三次尝试取出生命周期钩子途径

file

依此进行如下尝试:

  • 从js文件的exports中取
  • 以沙盒最后设置属性作为属性值在全局变量中取
  • 以appName作为属性值在全局变量中取

其中兜底的就是global[appName],这个就是我们在webpack的output里面配置的libraryfile

我看了看目前知识库管理后台的webpack配置(用的webpack4)file

跟文档基本一样,打包后会window下面挂载全局变量aiagentrobot_app,只不是项目里面的entry有多个请注意这一点

一切都很正确,为什么我在本地跑的时候还是出问题了?

那说明连最后兜底的window.aiagentrobot_app也没有兜住啊。 在控制台打印下结果,看看是否挂载了。file

熟悉react的会发现,这里面的都是react相关的方法啊。原来是把entry里面的common的内容挂载到window上了

我们这里探究区分不同的entry的必要性,只想办法怎么让webpack只把entry中的index部分内容挂载在window上。 单纯的webapck.config.js无法实现这样的效果,但是webpack不仅支持读取单个config,还支持读取多个config的数组的。

所以我们只用把自己的webpack.prod.config.js改成类似这样的

module.exports = [{
    entry: 'scrc/index.js',
    output: {
        path: path.join(__dirname, outDir),
        filename: "build.[name].[hash].js",
        chunkFilename: "chunk.[id].[hash].js",
        library: `aiagentrobot_app`,
        libraryTarget: "umd",
        jsonpFunction: `webpackJsonp_${packageJSON.name}`,
    }
}, {
    entry: {
        common: ['react', 'react-dom'],
        atd: ['antd'],
    },
    output: {
        path: path.join(__dirname, outDir),
        filename: "build.[name].[hash].js",
        chunkFilename: "chunk.[id].[hash].js",
    }
}]

也就是只针对你的入口文件加入output.library的相关配置

此时我们再在控制台打印下兜底的window.aiagentrobot_app,一切正常了。既然兜底的正常了,qiankun怎么也不会报错Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry了。

file

还有个疑惑点,就是为什么知识库管理后台作为微应用在综合管理后台下时没问题,同样作为微应用在知识库管理后台本地环境时不行呢? 我本地是怎么注册微应用的

{
    name: 'aiagentrobot', 
    entry: '//aigatewaycms.fat19.qa.nt.ctripcorp.com',
    container: '#test_app',
    activeRule: '/cms/',
}

我尝试在综合管理后台的控制台打印兜底的window.aiagentrobot_app

file

输出的是一个dom节点,原来综合管理后台作为主应用在注册微应用的时候把container的节点也用了跟aiagentrobot_app同样的名字。。。这样给掩盖了重要的调试信息啊。 知识库管理后台在注册微应用给不会采用这种方式,好歹换个id的名字啊。