icestark
icestark copied to clipboard
【icestark-module】加载 Runtime 依赖的时候没有正确识别在沙箱中添加的对象
Bug Report
What is the current behavior?
微模块在加载 runtime.json 的依赖时,会按照顺序依次在沙箱中加载依赖,并且提取出在依赖加载后新增在 window
对象上的属性;然后以提取出的属性注入到新的沙箱中继续加载下一个依赖,提取新增的属性。全部加载完成后,就可以获得配置在 Runtime 中依赖属性 deps。
https://github.com/ice-lab/icestark/blob/a6981bd305f21a6cd6b8ad4897b870710a8d63a2/packages/sandbox/src/index.ts#L97-L114
在沙箱中创建的 sandbox 中对于 window
对象配置的 Proxy
,在 set
拦截中,对于新增的属性,方法仅在原 window
对象上不存在该属性的时候会将该属性添加到 propertyAdded
中;而对于原来就存在于 window
对象上的属性,实际上沙箱中 window
对象的该属性已经变成了新的值而不是原有的值,但是这个属性并未标记为新添加的。这也意味着通过 propertyAdded
并不能获取这次解析执行 js 文件向 window
对象(沙箱)上挂载的属性。
进而这种不符合直觉的操作会导致一些问题。
the steps to reproduce
例如:宿主环境使用了 React,但是这个 React 中部分属性存在缺失 React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_cancelCallback
,实际上我配置的模块的 runtime 中声明了 React 16.14.0 和 ReactDOM 16.14.0 的资源文件,模块在解析 React 16.14.0的资源文件时,React 对象上确实存在 __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_cancelCallback
这个属性,但是因为宿主环境中存在 React 属性,这个通过 runtime 配置的 React 未被提取出来,进而不能作为解析下一个 js 文件的沙箱的注入变量,致使在解析 ReactDOM 16.14.0 的时候,使用的仍然是宿主环境中的缺少属性的 React 对象。然后 ReactDOM 16.14.0 加载过程中需要调用 React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_cancelCallback
,因此沙箱中抛出 TypeError: Cannot read properties of undefined (reading 'unstable_cancelCallback')
的错误,导致模块无法被加载。
What is the expected behavior?
对于 window 上存在的,但是在沙箱执行过程中向 window 上写入的属性也视作是新增属性propertyAdded
。同样在清理沙箱的时候也应该是先清理新增属性propertyAdded
然后恢复现场。(L218 ↔ L221)
https://github.com/ice-lab/icestark/blob/a6981bd305f21a6cd6b8ad4897b870710a8d63a2/packages/sandbox/src/index.ts#L206-L225
propertyAdded
主要用于新增 window 变量的记录,在卸载沙箱时可以移除多余的变量
上述复现的逻辑可能引起的原因是目前沙箱的劫持仅到 window.a
如果添加变量为 window.a.b
b 属性的新增时无法劫持获取的
https://github.com/ice-lab/icestark/blob/a6981bd305f21a6cd6b8ad4897b870710a8d63a2/packages/sandbox/src/index.ts#L99-L103
这里是根据沙箱外的 window 对象中有某个属性,对于没有的属性才会被标记为 propertyAdded
,但是实际上在沙箱中使用的是新的属性target[p] = value
没错,propertyAdded
仅用于恢复沙箱执行前的场景 实际获取都从 target
获取,所有的 set 最终都反映到 target
上
那对于 window 上属性的修改也应该体现在 propertyAdded
上,就举上面 React 的例子,如果我的宿主环境是 React16.6.0 版本,我的模块的依赖版本是 React16.14.0,在加载 runtime.json 依赖的时候,按照现在的逻辑使用的仍然是宿主环境的 React16.6.0 来加载 依赖中的 ReactDOM16.14.0, 我认为这样是不对的
提了一个 PR #612,可以看看