阿里云开放平台微前端方案的沙箱实现

导读 微前端已经成为前端领域如今比较火爆的话题,关于微前端价值的讨论,可以参考克军的《拥抱云时代的前端开发框架——微前端》。微前端在技术方面,有一个始终绕不过去话题就是前端沙箱。本篇具体探讨一下,在微前端领域如何实现前端沙箱。 背景 应用沙箱可能是微前端技术体系里面最有意思的部分。一般来说沙箱是微前端技术体系中不是必须要做的事情,因为如果规范做的足够好,是能够避免掉一些变量冲突读写,CSS 样式冲突的情况。但是如果你在一个足够大的体系中,总不能仅仅通过规范来保证应用的可靠性,还是需要技术手段去治理运行时的一些冲突问题,这个也是沙箱方案成为微前端技术体系的一部分原因。 首先纵观各类技术方案,有一个大前提决定了这个沙箱如何做:最终微应用是 单实例 or 多实例 存在宿主应用中。这个直接决定了这个沙箱的复杂度和技术方案。 • 单实例:同一个时刻只有一个微应用实例存在,此刻浏览器所有浏览器资源都是这个应用独占的,方案要解决的很大程度是应用切换的时候的清理和现场恢复。比较轻量,实现起来也简单。 • 多实例:资源不是应用独占,就要解决资源共享的情况,比如路由,样式,全局变量读写,DOM. 可能需要考虑的情况比较多,实现较为复杂。 最开始我们的想法是: 从业务场景:我们可能存在的情况是当用户操作一个产品 A 的同时和另一个产品 B 发生了关联操作,需要唤醒应用 B 做操作。虽然从产品维度可以规避掉,比如先切到 B, 然后切回 A, 但是从某种程度上因为技术的原因,我们限制了产品交互的发挥。 从技术角度:解决了多实例当然单实例的场景也不在话下,并且单实例的方案某种程度上给编码上带来了一定复杂度,比如业务代码需要自己做业务上下文的切换。 最近 qiankun 2 也转变了思路从单实例的支持到开始支持多实例,多多少少也侧面说明了,多实例是一个值得投入和技术攻克的场景。 基于上面的考量,我们就开始了我们 Browser VM 沙箱的实现探索。总结起来可以用下图表示:

JavaScript 沙箱实现 沙箱环境构造 要实现沙箱,我们需要隔离掉浏览器的原生对象,但是如何隔离,建立一个沙箱环境呢?Node 中 有 vm 模块,来实现类似的能力,但是浏览器就不行了,但是我们可以利用了闭包的能力,利用变量作用域去模拟一个沙箱环境,比如下面的代码: function foo(window) { console.log(window.document); } foo({ document: {}; }); 比如这段代码的输出一定是 {}. 而不是原生浏览器的 document. 所以 ConsoleOS 实现了一个 wepback 的插件在应用代码构建的时候给子应用代码加上一层 wrap 代码,创建一个闭包,把需要隔离的浏览器原生对象变成从下面函数闭包中获取的,从而我们可以在应用加载的时候,传入模拟掉的 window,document 之类的对象。 // 打包代码 __CONSOLE_OS_GLOBAL_HOOK__(id, function (require, module, exports, {window, document, location, history}) { /* 打包代码 */ }) function __CONSOLE_OS_GLOBAL_HOOK__(id, entry) { entry(require, module, exports, {window, document, location, history}) } 当然也可以不靠工程化的手段来实现,也可以通过请求脚本,然后在运行时拼接这段代码,然后eval 或者 new Function, 来达到相同的目的。 原生对象模拟 沙箱隔离能力有了,剩下的问题就是如何实现这一堆浏览器的原生对象了。最开始的想法是我们根据 ECMA 的规范实现(现在仍然有类似的想法),但是发现成本太高。不过在我们各种实验之后,发现了一个很“取巧”的做法,我们可以 new iframe 对象,把里面的原生浏览器对象通过 contentWindow 取出来,应为这些对象天然隔离,就省去了自己实现的成本。 const iframe = document.createElement( 'iframe' ); 当然里面有很多的细节需要考量,比如: 只有同域的 iframe 才能取出对应的的 contentWindow. 所以需要提供一个宿主应用空的同域URL来作为这个 iframe 初始加载的 URL. 当然根据 HTML 的规范 这个 URL 用了 about:blank 一定保证保证同域,也不会发生资源加载,但是会发生关联的 和 这个iframe 中关联的 history 不能被操作,这个时候路由的变换只能变成 hash 模式。 如下图所示,我们取出对应的 iframe 中原生的对象之后,就会对特定需要隔离的对象生成对应的 Proxy, 然后对一些属性获取和属性设置,做上一些特定的设置,比如 window.document 需要返回特定的沙箱 document 而不是当前浏览器的document. class Window { constructor(options, context, frame) { return new Proxy(frame.contentWindow, { set(target, name, value) { target[name] = value; return true; }, get(target, name) { switch( name ) { case 'document': return context.document; default: } if( typeof target[ name ] === 'function' && /^[a-z]/.test( name ) ){ return target[ name ].bind && target[ name ].bind( target ); }else{ return target[ name ]; } } }); } } 对于每一个对象的实现这里不讲细节了,有兴趣可以看看我们的开源之后的代码,点击前往>>> 但是为了文档能够被加载在同一个 DOM 树上,对于 document, 大部分的 DOM 操作的属性和方法还是直接用的宿主浏览器中的 document 的属性和方法。 由于子应用有自己的沙箱环境,之前所有独占式的资源现在都变成了应用独享(尤其是 location, history),所以子应用也能同时被加载. 并且对于一些变量的我们还能在 proxy 中设置一些访问权限的事情,从而限制子应用的能力,比如 Cookie, LocalStoage 读写。 当这个 iframe 被移除时,写在 window 的变量和设置的一些 timeout 时间也会一并被移除。(当然 DOM 事件需要沙箱记录,然后在宿主中移除)。 总结一下,我们的沙箱可以做到如下的特性:

CSS 隔离 CSS 隔离方案相对来说比较常规,常见的有: • CSS Module • 添加 css 的 namespace • Dynamic StyleSheet • Shadow DOM CSS Module or CSS Namespace: 通过修改基础组件样式前缀来实现框架和微应用依赖基础组件样式的隔离性(依赖于工程上 CSS 的预处理器编译和运行时基础组件库配置),同时避免全局样式的书写(依赖于约定或工程 lint 手段)。 Dynamic StyleSheet: 隔离方式是通过js运行时动态加载卸载微应用样式表来避免样式的冲突,局限性一是在于站点框架本身或其部件(header/menu/footer)与当前运行的微应用间仍存在样式冲突的可能性,二是没有办法支持多个微应用同时运行显示的情况。 Shadow DOM: 优点是浏览器级别提供的样式隔离能力,可以做到完全隔离。缺点在于,目前兼容性还是够不太好,并且改造会涉及到旧应用的业务代码的改造,对子应用侵入性比较高。 最终经过实践,我们选择的方式是 CSS Module + 添加 CSS 的 namespace。CSS module 保证的是应用业务样式不冲突,Namespace 保证公共库不冲突。我们实现了一个 postcss 插件,会在应用构建的时候给所有的样式都加上应用前缀包括应用公共库的 CSS。(这样方便做到同一个 组件库 新旧版本样式的兼容)。如下图所示: // 宿主 host app .next-btn { color: #eee; } // 子应用 sub app aliyun-slb .next-btn { color: #eee; } //宿主中生成的节点 <aliyun-slb> <!-- 子应用的节点 --> </aliyun-slb> 这样实现的好处在于: • 每个应用都有 namespace, 可以多实例共存。 • 不依赖特定的 CSS 预处理器。 • 对于同一个库不同版本的 CSS(如 fusion1 和 fusion2), 可以做到彻底隔离。 • 鉴于上面 JS 沙箱的存在,对于一些弹窗类的组件,这个微应用获取的 body 实际上是宿主生成的节点,所以弹窗会被添加到微应用的节点(也就是上面的 aliyun-slb)这个节点,样式不会失效。 不过也会有一些问题,比如: • 嵌套应用组件样式优先级的问题。(由于 CSS module 的存在,一般只会发生在公共 css 样式中,这个就是只能尽量避免嵌套)。 • fusion 不同版本库公用字体的问题。(目前解法比较hack, 工程化手段替换掉了 next 字体的名字)。 如何和其他体系结合 一般来说,所以如果看完上面的文章,觉得这个沙箱方案不错,但是又有自己的微前端体系了,想套用咋办? 目前 ConsoleOS 的代码已经在 Github 上开源这里不妨可以尝试试用一下,点击前往>>> JS 沙箱部分: 如果看懂了上面关于原理的介绍可以看到其实沙箱实现包括两个层面 • 原生浏览器对象的模拟(Browser-VM)的部分 • 如何构建一个闭包环境的部分。 Browser-VM 可以直接用起来,这部分完全是通用普适的。 但是涉及到闭包构建的这部分,每个微前端体系不太一致,可能需要改造比如: import { createContext, removeContext } from '@alicloud/console-os-browser-vm'; const context = await createContext(); const run = window.eval(` (() => function({window, history, locaiton, document}) { window.test = 1; })() `) run(context); console.log(context.window.test); console.log(window.test); // 操作虚拟化浏览器对象 context.history.pushState(null, null, '/test'); context.locaiton.hash = 'foo' // 销毁一个 context await removeContext( context ); 当然可以直接选择沙箱提供好的 evalScripts 方法: import { evalScripts } from '@alicloud/console-os-browser-vm'; const context = evalScripts('window.test = 1;') console.log(window.test === undefined) // true CSS 沙箱 如果用webpack 构建,可以直接配置如下: const postcssWrap = require('@alicloud/console-toolkit-plugin-os/lib/postcssWrap') // 下面是 webpack config { test: /\.css$/, use: [ 'style-loader', { loader: 'postcss-loader', options: { plugins: [ // 加入插件 postcssWrap({ stackableRoot: '.prefix', repeat: 1 }) ], }, }, 'css-loader', ], exclude: /^node_modules$/, } Try Live Demo 与其干巴巴的看文章,直接试试在线 Demo 可能更有体感一些,或者试试生产环境的例子, 阿里云企业工作台 - 工具应用中心 , 是阿里云集成三方应用提供云管能力。这里每个应用都是一个微应用,里面涵盖了 React, Vue, Angular 三大技术栈。

 

原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/515943.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea全局搜索快捷鍵ctrl+shift+F失效

idea全局搜索快捷鍵ctrlshiftF失效 1.确认是否修改了默认的快捷键配置&#xff1a; file-settings-keymap,在右边的放大镜中搜索find in Path 确认快捷键设置的是&#xff1a;ctrlshiftF 2.快捷键冲突&#xff08;常见的就是和输入法快捷键冲突&#xff09; 以我的win10自带…

生产环境遇到难题,你是如何解决的?

文章目录1. 生产环境 cpu 飙高产生的原因&#xff1f;2. 生产环境如何排查cpu 飙高问题&#xff1f;3. 生产环境遇到了报错&#xff0c;你是如何定位解决的呢&#xff1f;4. 调用接口如果服务器端一直没有响应怎么解决&#xff1f;5. 你在开发过程中&#xff0c;遇到哪些难题&a…

OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略

作者 | 酒祝 阿里云技术专家 导读&#xff1a;OpenKruise 是阿里云开源的大规模应用自动化管理引擎&#xff0c;在功能上对标了 Kubernetes 原生的 Deployment/StatefulSet 等控制器&#xff0c;但 OpenKruise 提供了更多的增强功能如 优雅原地升级、发布优先级/打散策略、多可…

真正的程序员,从来不会告诉你这些事!

有没有发现&#xff0c;每个程序员都曾有过这样的疑问&#xff1a;我该从事什么技术方向&#xff1f;相信很多人都会跟你说&#xff1a;找个“钱景”好的&#xff0c;找个简单的&#xff0c;找个应用广的.....听着好像都很有道理&#xff0c;但很多人学了很久后才发现&#xff…

Idea更改console控制台 日志颜色(非插件)

Idea更改console控制台 日志颜色&#xff08;非插件&#xff09; file-setting-editor-color scheme-console colors 在右侧的选项中可以自定义更改颜色 我之前控制台日志都是亮青色。晃眼睛&#xff0c;就干脆把idea的亮青换成了黑色。 之前&#xff1a; 之后&#xff1a;…

流批一体机器学习算法平台

发布会传送门 产品详情 针对正在兴起的机器学习广泛而多样的应用场景&#xff0c;阿里巴巴计算平台基础算法团队在2017年开始基于Flink研发新一代的机器学习算法平台。该项目名称定为Alink&#xff0c;取自相关名称&#xff08;Alibaba, Algorithm, AI, Flink, Blink&#xf…

Linux 下 Tomcat /jboss内存大小配置

找到 TOMCAT_NOME/bin/catalina.sh 文件加入以下代码&#xff1a; JAVA_OPTS"-Xms256m -Xmx512m -Xss1024K -XX:PermSize128m -XX:MaxPermSize256m" 具体位置如下图&#xff1a; 参数解释&#xff1a; -Xms128m JVM初始分配的堆内存-Xmx512m JVM最大允许分配的堆内存…

扎心!天天写代码,方向真的对吗?

“每个人的时间都是有限的&#xff0c;在有限的时间里选择一项值得投入的技术会变得尤为重要。” 笔者从 2008 年开始工作到现在也有 12 个年头了&#xff0c;一路走来都在和数据打交道&#xff0c;做过很多大数据底层框架内核的开发&#xff08;Hadoop&#xff0c;Pig&#xf…

powerdesigner-建立数据库模型及全局脚本

powerdesigner 使用 文章目录powerdesigner 使用1. 建立数据库表模型2. 脚本统一修改表结构&#xff08;赋值默认字段、统一删除、统一修改&#xff09;2.1.统一添加默认字段&#xff1a;2.2.统一删除字段&#xff1a;2.3.统一修改表名称&#xff1a;2.4. 统一修改字段属性&…

霍因科技获首届全国信创产业生态创新奖

近日&#xff0c;2020首届全国信创产业生态创新大赛颁奖盛典在北京信创园举办&#xff0c;霍因科技提交的“霍因科技-信创云统一存储和数据湖方案”荣获生态创新奖&#xff0c;这彰显了霍因科技在以数据存储技术推动信息技术应用创新产业方面的卓越成就。 据悉&#xff0c;首届…

国际免费版 新冠疫情数据分析APP正式发布!

简介 在今年2月初&#xff0c;SLS 已经发布针对新冠病毒肺炎疫情国内动态展示分析 APP&#xff0c;目前该能力全面开放给政府、社区、第三方平台和开放者进行广泛应用&#xff0c;完全免费开放。还没有关注过的同学可以通过以下链接了解背景&#xff1a; 新冠病毒疫情分析 AP…

powerdesigner生成表sql语句时,统一添加默认字段(生成时间、生成人等)

powerdesigner生成表sql语句时&#xff0c;统一添加默认字段 文章目录powerdesigner生成表sql语句时&#xff0c;统一添加默认字段方式一&#xff1a;配置创建表默认字段&#xff1a;方法二&#xff1a;创建表模型后执行vb语句推荐方法一&#xff1a;对pd表模型结构不侵入&…

Cloud Native Infrastructures Meetup 北京 | 活动安排

OpenAnolis社区首场线下meetup将联合Open Infrastructure基金会亮相北京&#xff0c;来自阿里云、蚂蚁集团&#xff0c;Intel&#xff0c;中国移动&#xff0c;红帽等公司的技术专家将围绕内核、容器及虚拟化等云原生基础设施技术展开探讨&#xff0c;解析相关开源技术内幕及社…

阿里云专家赵伟教你在CDN边缘节点上构建多层纵深防护体系

网络安全态势严峻&#xff0c;常见的五大网络攻击风险类型 赵伟认为&#xff0c;企业线上服务所面临的安全风险&#xff0c;主要来自以下五个方面&#xff1a; DDoS攻击 DDoS攻击类型已有20多年历史&#xff0c;它攻击方式简单直接&#xff0c;通过伪造报文直接拥塞企业上联带…

java并发编程面试

文章目录1.为什么要使用线程池&#xff1f;2.你们哪些地方会使用到线程池&#xff1f;3.线程池有哪些作用&#xff1f;4.线程池的创建方式&#xff1f;5.线程池底层是如何实现复用的&#xff1f;6.ThreadPoolExecutor 核心参数有哪些 &#xff1f;7.线程池创建的线程会一直在运…

下一代云原生应用制品管理平台,容器镜像服务企业版优惠进行时

随着越来越多的企业拥抱容器、拥抱云原生技术&#xff0c;享受技术带来的弹性、敏捷、可移植的便利&#xff0c;但是在实现容器技术生产落地时&#xff0c;很难规避以下痛点问题&#xff1a; &#xff11;、 运维复杂度&#xff1a;需要自建一个高可用的镜像服务去面对峰值流量…

软件设计师 - 系统测试

软件测试的目的&#xff1a;发现尽可能多的缺陷&#xff0c;而不是为了证明软件的正确性&#xff1b; 白盒测试&#xff1a; 语句覆盖每个可执行语句都被执行到判定覆盖&#xff08;分支覆盖&#xff09;每个语句至少执行一次&#xff0c;且每个判定的可能结果都至少执行一次条…

从移动广告业务“长出”的新增长点,汇量科技进军云服务

10 年前&#xff0c;Netscape 创始人、硅谷著名投资人马克安德森表示“软件正在吞噬世界”&#xff0c;这只说了故事的一半&#xff0c;10 年过去&#xff0c;人们从不信任到得“云”者得天下&#xff0c;云服务成为正在吞噬世界的“大鱼”。 工业和信息化部在《推动企业上云实…

开放下载!《OSS运维基础实战手册》

作为一名云运维工程师&#xff0c;在攻克OSS的道路上难免会遇到"天花板"。放轻松&#xff0c;《OSS运维基础实战手册》帮你轻松解决&#xff01;本书透彻解析OSS核心概念&#xff0c;十二心法打开全新运维视角&#xff0c;力求帮助云运维工程师们打破能力上升瓶颈。 …

MQ相关面试题

文章目录你们项目中哪些地方有使用到 MQ &#xff1f;为什么需要使用 MQ&#xff1f;MQ 如何避免消息堆积的问题&#xff1f;MQ 宕机了消息是否会丢失呢&#xff1f;生产者投递消息&#xff0c;MQ 宕机了如何处理&#xff1f;MQ 如何保证消息顺序一致性问题?为什么保证了消息顺…