最后更新:2020-05-27 10:45:18 手机定位技术交流文章

介绍
微前端已经成为前端领域的热门话题。关于微前端价值的讨论,请参考克罗地亚军队的“拥抱云时代的前端开发框架——微前端”。就技术而言,有一个话题不能总是被忽略:前端沙箱。本文具体讨论了如何在微前端域中实现前端沙盒。
背景
应用沙箱可能是微前端技术系统中最有趣的部分。一般来说,沙盒在微前端技术系统中不是必须的,因为如果规范做得足够好,它可以避免一些变量与读写冲突和CSS样式冲突。然而,如果您在一个足够大的系统中,您不能仅仅通过规范来保证应用程序的可靠性,或者您仍然需要技术手段来解决运行时的一些冲突问题。这也是沙盒方案成为微型前端技术系统的部分原因。
首先,看看各种技术方案,有一个大前提决定了如何做这个沙箱:最终的微应用程序是单实例或多实例主机应用程序。这直接决定了这个沙箱的复杂性和技术方案。
单个实例:同时只存在一个微应用实例。此时,浏览器的所有浏览器资源都是该应用程序专有的。解决方案在很大程度上是在应用程序切换期间进行现场清理和恢复。它相对较轻,并且易于实现。
多实例:资源不是应用程序专有的,因此需要解决资源共享的情况,如路由、样式、全局变量读写、DOM。有许多情况可能需要考虑,并且实现更加复杂。
一开始,我们的想法是:
从业务场景来看:我们可能会遇到这样的情况:当一个用户操作一个产品A,并且与另一个产品B有关联的操作时,有必要唤醒应用程序B来执行该操作。虽然从产品维度上可以避免,比如先切到B,然后再切回A,但在一定程度上,由于技术原因,我们限制了产品之间的交互。
从技术角度来看,多个实例的解决方案肯定超出了单个实例的范围,单个实例方案在一定程度上给编码带来了复杂性,例如,业务代码需要自己切换业务上下文。
最近,钱坤2也改变了它的想法,从支持单个实例到支持多个实例。或多或少,它也说明了多个实例是一个值得投资和技术征服的场景。
基于以上考虑,我们开始了对浏览器虚拟机沙箱的探索。总而言之,它可以用下图来表示:

JavaScript沙盒实现
沙箱环境构建要实现沙箱,我们需要隔离浏览器的本机对象,但是如何隔离和构建沙箱环境呢?节点有一个虚拟机模块来实现类似的功能,但是浏览器没有,但是我们可以使用闭包功能并使用变量范围来模拟一个沙箱环境,比如下面的代码:
函数foo(窗口){ console.log(窗口.文档);} foo({ document:{ };});例如,此代码的输出必须是{}。它不是本机浏览器的文档。
因此,控制台实现了一个wepback插件,在构建应用程序代码时向子应用程序代码添加一层包装代码,创建一个闭包,并将要隔离的浏览器本机对象更改为下面的函数闭包,这样我们就可以在加载应用程序时传入模拟对象,如窗口和文档。
//包代码_ _ console _ os _ global _ hook _ _ (id,函数(required,module,exports,{window,document,location,History} {/* packing code */})函数_ _ console _ OS _ global _ hook _ _ (id,entry){ entry(required,module,exports,{window,document,location,History},当然,也可以在没有工程方法的情况下实现,或者通过请求脚本,在运行时拼接此代码,然后评估或新建函数。
由于本机对象模拟沙箱的隔离能力,剩下的问题是如何实现这一堆浏览器的本机对象。最初的想法是我们根据ECMA规范实现它(仍然有类似的想法),但是发现成本太高了。然而,在我们的各种实验之后,我们发现了一个非常“棘手”的方法。我们可以使用新的iframe对象通过contentWindow取出内部的本机浏览器对象,因为这些对象是自然隔离的,因此节省了我们自己实现的成本。
const iframe = document . CreateElement(' iframe ');当然,有许多细节需要考虑,例如:
只有同一个域的iframe才能检索相应的内容窗口。因此,有必要提供主机应用程序空的同一个域的URL,作为iframe最初加载的URL。当然,根据HTML规范,该URL使用about:blank来确保相同的域,并且不会发生资源加载,但是与该iframe相关联的历史不能被操作,并且路由转换此时只能被改变为散列模式。
如下图所示,在取出相应iframe中的原始对象后,我们将为要隔离的特定对象生成相应的代理,然后对一些属性获取和属性设置进行一些特定的设置,如window.document需要返回到特定的沙盒文档,而不是当前浏览器的文档。
类窗口{构造函数(选项,上下文,框架){返回新的代理(框架.内容窗口,{设置(目标,名称,值){目标
CSS隔离
Css隔离方案相对传统。常见的有:CSS模块添加CSS名称空间动态样式表阴影DOM
CSS模块或CSS命名空间:通过修改基本组件样式的前缀,可以根据基本组件样式(取决于工程CSS的预处理器编译和运行时基本组件库的配置)隔离框架和微应用程序,同时避免编写全局样式(取决于约定或工程lint方法)。
动态样式表:隔离方法是通过js运行时动态加载和卸载微应用程序样式表,以避免样式冲突。第一个限制是,在站点框架本身或其页眉/菜单/页脚与当前运行的微应用程序之间仍然存在风格冲突的可能性。第二个限制是没有办法支持多个微应用程序同时运行和显示。
影子DOM:优点是浏览器级提供的风格隔离能力,可以完全隔离。缺点是目前兼容性还不是很好,转换将涉及到旧应用程序的业务代码的转换,这会对子应用程序造成更大的干扰。
最后,经过实践,我们选择了CSS模块+来添加CSS名称空间。CSS模块保证应用程序业务风格不冲突,命名空间保证公共库不冲突。我们已经实现了一个postcss插件,它将在构建应用程序时为所有样式添加前缀,包括应用程序公共库的css。(这有助于相同组件库的旧版本和新版本的兼容性)。如下图所示:
//主机应用程序。next-BTN { color:# eee;}//子app aliyun-SLB . next-BTN { color:# eee;}//在主机中生成的节点。& lt!--子应用程序节点->;& lt/aliyun-slb>。这种实现的优点是每个应用程序都有一个名称空间,并且可以与多个实例共存。不依赖于特定的CSS预处理器。对于同一库中不同版本的CSS(如fusion1和fusion2),可以实现完全隔离。鉴于以上JS沙盒的存在,对于弹出窗口类的一些组件,这个微应用程序获得的主体实际上是宿主生成的节点,所以弹出窗口将被添加到微应用程序的节点(即上面的aliyun-slb),样式不会失败。
然而,也存在一些问题,例如嵌套应用程序组件样式的优先级。(由于css模块的存在,它通常只出现在常见的CSS样式中,这是为了尽可能避免嵌套)。融合库不同版本中常见字体的问题。(当前的解决方案是hack,下一个字体的名称已经被工程方法所取代)。
如何与其他系统结合
一般来说,如果你看看上面的张文,觉得这个沙盒方案不错,但是你有自己的微前端系统,你想做什么?
目前,控制台的代码在Github上已经是开源的了。在这里,您可以尝试一下,然后单击“转到”>>。>。
JS沙箱部分:如果您理解了上面关于原理的介绍,您可以看到沙箱实现实际上包括两个级别
本地浏览器对象的浏览器-虚拟机部分如何构建封闭环境的一部分?
浏览器虚拟机可以直接使用,这是完全通用的。然而,当涉及到封闭结构的这一部分时,每个微前端系统并不十分一致,并且可能需要修改,例如:
从“@ alicloud/console-OS-browser-VM”导入{ createContext,RemoveContext };const上下文= wait CreateContext();const run = window . eval(`()= & gt。函数({window,history,locaiton,document }){ window . test = 1;})()`)运行(上下文);控制台.日志(上下文.窗口.测试);控制台.日志(窗口.测试);//操作虚拟化浏览器对象上下文. history.pushstate (null,null,'/test ');哈希= ' foo '//销毁上下文感知removecontext(上下文);当然,您可以直接选择沙箱提供的评估脚本方法:
从“@ alicloud/console-OS-browser-VM”导入{ EVALScript };const context = EVALScript(' window . test = 1;')console . log(window . test = = = undefined)//truce cs沙盒如果用webpack构建,可以直接配置如下:
constpostcswrap = require(' @ alicloud/console-toolkit-plugin-OS/lib/postscswrap ')//下面是webpack配置{test:/。css $/,使用:['style-loader ',{loader:' postcss-loader ',选项:{ plugins:[//add plugins post CSS wrap({ stack root:'。前缀',重复:1})],},' css-loader ',' exclude://node _ modules $/,} trylivedemo
与其干巴巴地看着张文,不如直接尝试在线演示,或者尝试一个生产环境的例子,这可能更有体感。阿里云企业工作台-工具应用中心是阿里云集成三方应用提供的云管理能力。这里的每个应用程序都是一个微型应用程序,涵盖了反应、真空、角度技术堆栈。
本文由 在线网速测试 整理编辑,转载请注明出处。