react/jsx-runtime抛错导致项目异常
背景
目前主要是B端的开发,系统都是微前端模式,会有主子应用之分。需要先加载主应用,然后再加载子应用,由于主应用都是基于React开发的,为了更好的性能,由主应用暴露react
、react-dom
这些公共库,然后子应用将这些依赖配置为external,构建时就不会重复打包了。
问题
配置external之后,本地开发时,发现项目竟然有问题:
TypeError: Cannot read properties of undefined (reading 'getStackAddendum')
出现一个TypeError的异常导致整个子应用都运行不起来。
分析
首先是debug一下有异常的代码,发现缺少 ReactDebugCurrentFrame
属性,导致出现异常。
把 Webpack中的external配置移除,重新启动项目,项目正常。故大致问题应该是版本原因,external的是一个production版本的react
,而本地启动时,因为process.env.NODE_ENV
为development
故加载的了
react-jsx-runtime.development.js
这个文件,导致异常。
修改一下node_modules中的这个文件 node_modules/react/jsx-runtime.js
不区分环境,都使用 cjs/react-jsx-runtime.production.min.js
。
然后加上 external
配置,重新启动项目,发现一切正常。 故证实了react的production版本和jsx-runtime.development不匹配会出现问题。
解决方案
知道问题后,我尝试过三个方案,其中有两个是可用的:
方案一:设置NODE_ENV为production (不可用)
看react的实现会根据 process.env.NODE_ENV
判断引用的文件,那我们将这个设置为 production
不就可以引用production版本的jsx-runtime了么? 修改这个变量可以通过 # DefinePlugin 实现:
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
});
这个思路确实没有毛病,但修改之后会引入的新的问题,而且也不好评估影响的访问,故没有继续探索,直接放弃这个方案。
方案二:区分环境,本地开发移除external配置(推荐)
因为是 react 的 production 版本和 jsx-runtime的development不兼容会有问题,那我们如果能将这两个版本统一一下不就好了么。线上使用的肯定是production版本,不会遇到问题,那么我们本地继续使用 development 版本就好了。
具体做法是通过判断 NODE_ENV
如果是本地环境即:
if (process.env.NODE_ENV === 'development') {
delete external.react;
delete external['react-dom'];
}
这样可以兼顾本地开发的效率(develop版本会议一些提醒,例如list需要写唯一的key等),和线上的体验。
但有个一悲伤的场景,如果项目使用 Webpack 的module federation加载组件的话,这个解法会有问题,故请看第三种方式。
方案三:乾坤大挪移,替换development版本为production版本 (可用)
方案一想都统一为production版本但确失败了,但还有一个方式可以实现。Webpack在构建过程中会执行不同的plugin,正好有一个官方的plugin可以构建时替换资源路径——# NormalModuleReplacementPlugin
因此可以用这个插件来替换development版本为production版本:
if (process.env.NODE_ENV === 'development') {
config.plugins?.push(
new webpack.NormalModuleReplacementPlugin(
/\/cjs\/react-jsx-runtime.development.js/,
(resource) => {
resource.request = resource.request.replace(
'react-jsx-runtime.development',
'react-jsx-runtime.production.min'
);
}
)
);
}
但这种方式缺失了React最佳实践的检测,虽然检测出来东西我们不一定改。
总结
因为一个external引发了各种问题,不同问题会有不同的解法,问题不重要,重要的是知道怎么分析问题。能准确定义问题,其实解决方案就不远了。
转载自:https://juejin.cn/post/7185140351303483450