PAAS

1,800 阅读8分钟

我理解的PaaS

IaaS:基础设施服务,Infrastructure-as-a-service

PaaS:平台服务,Platform-as-a-service

SaaS:软件服务,Software-as-a-service

借用阮一峰博客中提到的例子:卖披萨来说明这个事

你可以从头到尾,自己生产披萨,但是这样比较麻烦,需要准备的东西多,因此你决定外包一部分工作,采用他人的服务。你有三个方案。

方案1: IaaS, 他人提供厨房、炉子、煤气,你使用这些基础设施,来烤你的披萨。

方案2:PaaS, 除了基础设施,他人还提供披萨饼皮。你只要把自己的配料洒在饼皮上,让他帮你烤出来就行了。也就是说,你要做的就是设计披萨的味道(海鲜披萨或者鸡肉披萨),他人提供平台服务,让你把自己的设计实现。

方案三:SaaS,他人直接做好了披萨,不用你的介入,到手的就是一个成品。你要做的就是把它卖出去,最多再包装一下,印上你自己的 Logo。

从左到右,自己承担的工作量(下图蓝色部分)越来越少,IaaS > PaaS > SaaS。

而在我们前端?如何理解PaaS? 同样的,我也举个例子。

我们会员有一个模块,比如会员标签。功能是查看会员标签,并可以创建标签。如下图:

我们想把这个功能作为一个服务输出。给其他业务用,无需再额外开发一套。

使用SaaS我们会怎么做?构建一个iframe,将整个页面嵌入。接入方不做任何改造,直接使用。显然,不可以这么用,姑且不说UI的不一致,不同业务使用的系统接口也不同。So, 我们需要 PaaS来做这个事,只做部分通用不变功能,预留其它可变功能给业务方定制。

所以,我理解的前端PaaS, 即 前端PaaS应该是 前端UI+业务逻辑 打包输出,作为一种服务形式,给其他业务使用。

如何做前端的PaaS

首先,第一步,要进行业务抽象。这也是所有谈及PaaS,最头疼也是最重要的一部分:业务抽象。业务抽象做的好,会大大提高平台的服务能力和适应场景。

继续上面的会员标签功能来说明。

我简单列举了下这个模块的抽象,但是实际上抽象可以更加具体,比如接口入参和出参不同,就需要一层适配,因此适配也需要抽象。

第二步,根据抽象进行编码和发布。编码不再多说,和我们往常的开发一样,只是要注意预留抽象能力在业务组件上。发布后,我们会得到发布后的模块,这一个页面和相关静态资源,相当于我们的前后端能力打包到一个可访问的页面上。

前端PaaS化需要解决的几个核心问题

业务发布成平台,单个业务能力可以作为模块输出

业务抽象,哪些固定,哪些开放?然后是如何开放?业务模块基于一套约束或者框架来开发

业务定制,模块在不同系统中可轻松定制

业务升级方便,最好能做到接入方无感知

业务解耦,既然是服务,必然不能对接入方有太多耦合

通过远程模块来实现前端PaaS

最近我尝试通过远程模块来做到了上面几点。但是还需要进一步的论证:

大家先点击看demo. 来熟悉一下:

主应用中嵌入子应用(这是最基本一个场景,页面级作为服务输出和使用):

vy6vfy.coding-pages.com/index.html?…

不同技术栈的前端应用嵌套使用( 前端框架繁多的情况下。不同框架集成使用也是要解决):

vy6vfy.coding-pages.com/index.html?…

同一模块在不同业务下的多态(很重要的功能,如何让输出的页面适配业务):

vy6vfy.coding-pages.com/index.html?…

父子应用的数据共享(很重要的功能,主应用的逻辑不需要耦合到子应用中):

vy6vfy.coding-pages.com/index.html?…

什么是远程模块?和异步模块有啥区别?

远程模块本质上也是组件,只不过是大的业务组件,比如上面提到的会员标签整个业务,就可以当做一个组件。在服务输出领域,我更倾向于称之为远程模块。但是在开发时,我们知道它是组件即可。

之前的一篇博客介绍了一些微前端的方式。主要是讲述了如何在Vue项目中使用React项目的组件。这是基于组件均在本地的情况。今天介绍下远程模块(组件)的使用。

远程组件和异步组件最主要的一点区别是:异步组件是相对于同步组件的一种异步加载。也就是说组件都在当前项目仓库,为了解决组件打包体积过大带来网络加载过长,导致用户等待时间过久的体验问题。而采取的一种code split 解决办法。那么问题来了,既然我们可以基于路由,将本地组件通过code split 方式打包成多个包。那么这些包除了本地使用外。如果能够同时给其他项目使用。在其他项目里,可以引入远程项目的组件,当本地一样使用,这种集成方式听起来很新颖,也能解决很多问题。

为什么要用远程模块,iframe嵌套或者npm方式优劣分析?

首先说大家最耳熟能详的 iframe 嵌套方式。iframe方式本质上是将2个页面集成在了一起。因为隔离,能解决js污染,变量污染,js 沙箱运行。对于内外完全独立的场景来说,是合适的。但是通过 iframe 对外输出的是页面。外层页面对当前页面没有太多的干涉能力。如果有,需要内外协商定义 事件或者 通过 message 来实现。当然也无法直接使用外层页面内存中的对象。所以说iframe的内外隔离性很强,互动性差。

接着看去掉iframe的场景,方式是主页面动态构建dom, 引入另外系统的js, 该js 加载完成后自执行,渲染到指定的dom. 这里”指定的dom“ 会有一层依赖,即内外需要约定好 dom id 。这种方式去掉了iframe. 因此外部js在执行渲染期间,可以直接使用window上的对象或者方法。 但同时 外部js执行时也可能污染掉本地内存中的变量,甚至css等。隔离性差,互动性强。但是渲染需要约定。

到这里,我们发现上面2种方式,都有一个共同的缺点,就是如何渲染完全由外部js决定。外层不能控制和干涉。在一定程度上比较好理解,但能力有限。但实际场景中,外层真的完全不需要干涉内部渲染吗?设想一下这个场景,当项目作为一个子应用,需要给A, B 两个系统使用时,A,B系统均有自己全局错误交互方式,A系统使用弹窗告警。B系统使用Tip提醒。我们为了保证交互的一致性,需要子应用在A中使用弹窗,在B中使用Tip. 那我们项目该如何开发呢?开发2套不同的交互方式,分别给A,B用?如果父应用的交互方式发生了改变。那如何保持同步?不管是iframe还是加载远程js来渲染都解决不了这个问题。从场景上看,我们需要实现同一个应用在不同系统中的多态。从实现上看,我们要能够通过某种方式,控制到子应用在当前系统中的渲染。因此,今天介绍一种方式:远程组件。

远程组件解决的问题

续上面列举的场景,如果我们能够加载到远程js. 这个js并不立马执行渲染,而是暴露给我一个业务组件。此时,父页面拿到这个组件,就可以方便地在某个dom上执行渲染,不需要告知子应用,因此解决了父子依赖问题。然后,既然父页面拿到的是组件,那么我就可以当成一个本地组件来使用,我可以传入上下文(context),也可以进一步进行封装,成为一个高阶组件,当然也可以通过属性,传递父页面的一些能力,比如全局错误交互方式,比如全局的网络请求库。当前页面的主题是dark还是light等。然后挂在到响应的dom上进行渲染,渲染完成后,我们将得到一个定制化的子应用。从而很好解决了我们的问题。但是有一点约束,子应用在开发时,在可能出现多态的地方,需要调用属性中传递过来的参数或者方法来实现,不需要本地来解决。(这里逻辑可以兼容,如果属性上传递有,就使用属性传递的数据,如果没有,就使用本地的逻辑),也就是要求我们在开发子应用时,要进行一定的抽象,暴露一些外部可以控制的接口。

如何实现远程组件?

具体细节实现设计中,待补充。