Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack代码切割生成的js/css能够做到沙箱隔离吗? #62

Closed
oliverzy opened this issue Nov 10, 2020 · 14 comments
Closed

webpack代码切割生成的js/css能够做到沙箱隔离吗? #62

oliverzy opened this issue Nov 10, 2020 · 14 comments

Comments

@oliverzy
Copy link

如题,这些会直接操作document.head.appendChild这个能做到沙箱隔离吗?

@yisar
Copy link
Collaborator

yisar commented Nov 10, 2020

隔离的是window,document对象实际上会逃逸的,我们不可能连document都隔离

@oliverzy
Copy link
Author

了解,我看qiankun的做法好像是会劫持的方法来做的,https://github.com/umijs/qiankun/blob/e537996b481cf88caffe4b6116c3a865f3c3c9a9/src/sandbox/patchers/dynamicAppend/common.ts#L139
挺复杂的,挺琐碎的

@yisar
Copy link
Collaborator

yisar commented Nov 10, 2020

了解,我看qiankun的做法好像是会劫持的方法来做的

qiankun 这里的代码是动态插入 js 和 css,和 webpack 代码切割没啥关系吧

webpack 代码切割的 document.appendChild 是发生在哪里,我们其实可以等 webpack 执行完,再做 html 的解析的

@oliverzy
Copy link
Author

是发生在webpack生成的runtime代码里面的,当被切割出来的js和css需要加载的时候,就会执行,只要在项目里面用动态import语法,webpack就会编译成调用runtime里面的方法,最终就会appendchild

@yisar
Copy link
Collaborator

yisar commented Nov 10, 2020

是发生在webpack生成的runtime代码里面的

加入我们主要的 js 是 main.js 然后,里面用了 import 然后就,appendChild 就是在 main.js 中吗?

如果是发生在 main.js 中,那没有关系,main.js 中的 document 是会逃逸的……

劫持是不可能劫持的,比如同时有 vue 和 react 两个框架,两个框架都是用的同一个 document,逃逸过来的

白名单:https://github.com/berialjs/berial/blob/master/src/sandbox.ts#L28

或者你有什么隔离的思路吗?不同 app 用不同的 document 吗

@oliverzy
Copy link
Author

我理解这里的需求是微应用通过webpack或者手写的代码延迟加载一些js或者css文件,也希望框架能够把这些js在沙箱里面执行,css加到相应的shadowdom里面去。倒不是不同app用不同document对象

@yisar
Copy link
Collaborator

yisar commented Nov 10, 2020

也希望框架能够把这些js在沙箱里面执行

实际上你的理解是对的,import() 会引起逃逸,我对它做了限制,就是没想到 webpack 竟然直接 appendChild

https://github.com/berialjs/berial/blob/master/src/sandbox.ts#L139

我们不能禁用 appendChild,但是如果是劫持的话,有什么好的思路吗?

@yisar
Copy link
Collaborator

yisar commented Nov 10, 2020

在我的认知里,似乎有两种方法可以做这个事情

  1. 劫持 createElement

检查 createElement 的参数,如果是 script,那么则加到沙箱中……

  1. Mutation Observer

如果我们只是为了保护 head 那么可以使用 MO 监听 head 的变化,有 script 新增就加到沙箱里……

不知道 qiankun 咋做的,会不会有更好的方式::>_<::

@oliverzy
Copy link
Author

@yisar
Copy link
Collaborator

yisar commented Nov 10, 2020

@oliverzy

乾坤用的应该就是劫持createElement的方式

害,如果是这样的话,那就不如使用 MO 了,因为 Proxy 劫持 dom 树需要比较苛刻的封装,我在 fard 中干过这事

但是从 qiankun 源码来看,他们现在仍然偏向于一种 case by case 的 hack 方式……

我觉得 MO 更好,我们观察整个 document 对象,任何 shadow dom 之外的操作都会被另处理

new MutationObserver(mutations => {
	// do something
})).observe(document)

嗯……谢谢你提出这个问题,我觉得这样是最好的:

使用 Proxy 去劫持 window,使用 MutationObserver 观察 document

yisar added a commit that referenced this issue Nov 10, 2020
* document mutation observer

* fix type
@yisar
Copy link
Collaborator

yisar commented Nov 10, 2020

#63 pr 来了::>_<::

@yisar
Copy link
Collaborator

yisar commented Nov 11, 2020

最新代码使用了一个队列来模拟微任务的处理,每一轮如果有逃逸的js,则推到队列里递归到下一轮

我认为现在的思路还是很不错的,但是原生 import() 比较难办,仍然是禁止状态

俺先关掉 issue 啦,有问题再开新的

@yisar yisar closed this as completed Nov 11, 2020
@oliverzy
Copy link
Author

有个疑问,我看代码里面每次sandobox的run方法跑完之后都会创建一个新的沙盒吗,我的理解应该是属于同一个微应用的JS都运行在一个沙盒里面的

@yisar
Copy link
Collaborator

yisar commented Nov 13, 2020

我的理解应该是属于同一个微应用的JS都运行在一个沙盒里面的

沙箱只初始化创建一次,run 只是执行 js 然后将执行结果挂到 window 上,MutationObserver 是将逃逸的 js 塞回当前沙箱

但是我现在的实现,多实例的情况下还不是很好

所以我决定重构 berial,使用树状路由,走异步渲染管线(类似 react fiber):#66

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants