问题描述
问题的具体描述
在 createProxyWindow 函数中,proxyWindow 的 get 拦截器第一行就是:
get: (target: microAppWindowType, key: PropertyKey): unknown => {
throttleDeferForSetAppName(appName) // <--- 罪魁祸首
// ... 后续逻辑
}
无论访问什么属性(即使该属性在 target 上存在,或者是 __MICRO_APP_ 开头的内部变量),都会先执行 throttleDeferForSetAppName。而在底层实现中,这个函数会调用 defer(微任务),导致 Zone.js 监控到异步并触发变更检测,变更检测再次访问 window,形成死循环。
由于这是框架底层 Proxy 的硬编码逻辑,通过常规 options 配置(如 plugins 或 escapeProperties)是无法拦截这第一行代码的执行的。
复现步骤
- pipe管道里面去windows上拿变量,然后这个window被微前端框架代理了,里面有个defer的微任务,触发这个后就会导致主应用的全局的那个zone有微任务的队列。
- 这里结束不了,继续触发管道,管道逻辑里又去拿windows上的变量,然后就一直循环。
上传截图
请上传代码截图、控制台、终端等截图以帮助我们了解您的问题。
src/libs/utils.ts (或对应编译后的文件) 中的 defer 函数
建议:
以下是三种深度解决方案:
方案一:修改源码(通过 patch-package)—— 最推荐
这是最彻底的办法。你需要修改 micro-app 源码中 defer 的实现,或者在调用处强制使用原生 Promise。
- 修改
src/libs/utils.ts (或对应编译后的文件) 中的 defer 函数:
// 将原来的 Promise.resolve().then(fn)
// 改为使用 rawWindow 上的原生 Promise
export function defer (fn: Function): void {
const nativePromise = (window as any).rawWindow?.Promise || (window as any).__zone_symbol__Promise || Promise;
nativePromise.resolve().then(fn);
}
或者直接修改 createProxyWindow:
// 在 micro-app 源码的 get 拦截器中
get: (target: microAppWindowType, key: PropertyKey): unknown => {
// 如果是 Zone.js 相关的 key,直接跳过 throttleDefer
if (typeof key === 'string' && key.startsWith('__zone_symbol__')) {
return Reflect.get(rawWindow, key);
}
throttleDeferForSetAppName(appName);
// ...
}
复现仓库
请提供一个精简的代码仓库,然后上传到自己的 github,以帮助我们复现您的问题。
环境信息
- micro-app版本:1.0.0-rc.26
- 主应用前端框架&版本:angular17
- 子应用前端框架&版本:angular20
- 构建工具&版本:webpack
问题描述
无论访问什么属性(即使该属性在
target上存在,或者是__MICRO_APP_开头的内部变量),都会先执行throttleDeferForSetAppName。而在底层实现中,这个函数会调用defer(微任务),导致 Zone.js 监控到异步并触发变更检测,变更检测再次访问window,形成死循环。由于这是框架底层 Proxy 的硬编码逻辑,通过常规
options配置(如plugins或escapeProperties)是无法拦截这第一行代码的执行的。复现步骤
上传截图
建议:
以下是三种深度解决方案:
方案一:修改源码(通过
patch-package)—— 最推荐这是最彻底的办法。你需要修改
micro-app源码中defer的实现,或者在调用处强制使用原生 Promise。src/libs/utils.ts(或对应编译后的文件) 中的defer函数:或者直接修改
createProxyWindow:复现仓库
环境信息