5

对于大多数前端来说,无非就是写写简单的页面,我并不是歧视前端,笔者也是前端,因为前端确确实实对于公司的整体业务的认知没有后端的了解的更加深刻(毕竟人家是玩数据库的)。

笔者在刚刚做公司内部系统的时候也只是做做简单的各个模块系统,现在大多数公司都是使用的微前端的系统架构,以达到各个业务依赖性没有那么大,同样也不会因为项目的逐渐扩大,导致项目越来越大,首先加载慢,再其次就是难以维护。

但是所有项目都以微前端的形式分散开,就会遇到整合的问题,于是在我们进行疯狂的讨论,因为使用的技术栈是Vue这个因素也被考虑进去了,讨论出来第一版最终解决方案。

初期实现-iframe

其实对于大多数人来说,一旦说到前端项目整合的话,第一个想到的就是iframe,这种是最简单最的方法了,大多数公司都是使用的这这种方法对项目进行整合的。

废话我们也就没多说,就开始开发了,遇到的第一个问题就是跨域,因为整合所有子项的每个都有自己的域名,承载这些子项目的框架又有自己的域名。这里就使用了,document.domain的解决了跨域问题。跨域的问题一般都会遇到,这也并不是难解决的。

除了跨域问题,还有就是各个子项目的鉴权,各个子项目需要登录之后的token其实这个问题也不是特别困难,但是后端在做这个地方为了保证权限的安全性考虑,token会随着一段时间进行变化,这样一来就不是简简单单的把token传给子项目就行了,首先考虑的是,各个子项目携带者着token向后端请求数据的时候,当token发生变化的时候,需要通知登录框架。

在最初考虑这个问题的时候,考虑使用postMessage进行通信因为涉及的项目太多,而且使用postMessage方法虽然轻便,但是觉得这种方法有些臃肿,不太适用于我们现在的整体架构方案。经过讨论之后,就放弃了这个方案。为什么会放弃这个方案,因为当打开多个子页面的时候,其中一个子项目在请求数据过程中token发生变化了,其他子页面需要知道token想要知道token发生变化,就必须通过登录框架通知,如果使用postMessage的话就实在太不方便了。

其实想要的无非是登录框架的token改变,子项目token随着改变,这时机智的我想到了灰常优秀的VueVue是使用的是Object.defineproperty,通过该方法,各个子项目也好和登录框架也好,只需要监控一个对象上某个自定义属性即可,这个使用我把矛头指向了window,虽然这样不太好,但是针对于目前的情况window是最好的选择。

依赖实现结构图:

image

解决了一些问题之后,也算是可以完成了第一版虽然存在很多的问题,但是确实是可以用了。于是第一个版本就这样匆匆忙忙的上线了,用户反映怎么说呢,其实也没有那么好,毕竟是iframe需要加载的会比较慢。还在想办法进一步优化一些。

结构优化

时间每天都在流失,登录平台依旧有很多的问题,对iframe有所了解的同学都应该知道,每次iframe在打开的时候都需要重新拉取资源,这个是真的是太头疼了,然而这还不是最关键的问题,最关键的是什么,各个子项目每个模块都在登录平台里面,很多模块完全在同一个项目里面,很多时候需要拉取相同的资源,这个实在是太难受了,作为一个前端来讲,如此大量的重复资源加载,有点无法容忍。

有的时候各个子项目业务太大的时候,页面加载的实在是有点过于太慢了,在最初做项目时,那个时候单页面应用火热(现在也有大部分公司在使用),单页面应用就会带来这样的问题。

为了解决这个问题曾经考虑过使用路由懒加载,虽然可以实现一些资源的节约,但是,举个例子来讲的话,如果当前模块只有一个只有表单,其他什么都没有,这个使用完全不需要使用routestroe,其他的在同一个项目里面的应用仍然用到了routestroe,导致加载该模块的使用routestore同时也被拉取下来了,实在是让人头痛,本身我不需要这些东西,为什么还要加载这些东西。我想哭~~~

带着这些疑问,开始寻求解决方案,经过一段时间的调研,发现多页面应用完全可以满足我现在的需求,通过多页面,只需要在对用的页面的实例中挂载对应所需要的资源就可以了。当读取到当前这个子项目中的某个模块的时候就可以做到这一点了。

这样做的好处在于当前子业务模块,需要用到route就引入route,用到stroe就使用stroe,打开页面也只会拉取相对应的资源。再也用担心当前子项目拉取一些没有相关的资源了。

具体多页面配置请参考:Vue-cli3多页面配置

结构设想

虽然通过上面两部操作,已经对性能解决了很大一部分问题,但是,身为一个优秀的前端(咳咳咳,不要打断我。。。暂时不接受反驳,哈哈哈)来讲得话,整个框架还是存在一些问题。

  1. 登录框架中已经存在了routestroe这些资源,为什么子项目打开的时候,还要重新拉取一次呢?
  2. 使用iframe始终不是那么的优雅,会带来一些不可预知的问题,或者以后一些需求甚至会导致无法满足(虽然现在还没有遇到,但是还是得为以后做打算)

以下内容没有经过实践,还无法知道是否可以实现。

这个想法来自于SSR,当调研Vue的服务端预渲染的时候我发现,当客户端页面启动的时候是通过,读取客户端导出的一个json文件,并且读取了里面的内容,找到对应的.js文件,既然在服务端渲染的时候可以通过读取对应的js文件做到页面的渲染,那么在前端渲染的时候是不是也可以来一波这样的骚操作呢?。这样一下灵感就来了,忽然就有了一个大胆的想法。

关于这里还有一个小插曲想要说一下,我以前以为ssr是服务端解析了js文件,但是被小伙伴给质疑了,其原因是Node根本就没得办法去解析js文件。以前调研ssr的时候用到了renderToString的函数,但是,当时接收的是一个url参数,也就是前端路由,createBundleRenderer返回的对象中存在两个函数分别是renderToStringrenderToStream,其中renderToString函数接收的就是页面中所写的template模板内容,最后把渲染好的页面返回给客户端。这是我自己后来理解的,再往下就要看源码,这里我没有详细看,毕竟与该文章内容不符,这里就不做多余赘述了,有兴趣的同学可以看下。这里灰常感谢我的小伙伴指出了我的错误。

服务端渲染中节选的代码:

let render = vueRender.createBundleRenderer(serverBundle,{
    template,
    clientManifest:clientBundle.data,
    renInNewContext:false
}); 
//  重点就是这里
render.renderToString({
    url:request.url
}).then((html) => {
    respones.end(html);
}).catch(error => console.log(error));

服务端渲染请参考:手把手教你搭建SSR(vue/vue-cli+express)

如果在Vue打包的使用,可以把各个页面对应的css文件js统一写入到项目中的一个json文件中,如果是这样的话,登录框架可以通过域名获取到该模块对应的组件,然后通过动态路由route.addRoute这个api把读取到的组件注册到登录页面,这样一来Vuestoreroute组件库这些东西就完全可以使用,登录框架的了。岂不是一举两得的吗?这样的优化真的太大了。

image

上图中完成了操作之后,获取到对应的页面组件之后,通过路由动态注入到登录框架中的,就行了。这些想法还在一步一步的调研过程中。。。

总结

所有的项目无论大小,都需要演变,但是其中需要作为开发人员的我们,进行不断的思考和优化,以达到一个比较好的状态,做前端也有一段时间了,个人觉得,没有最好的选型,只有最适合选型,只有真正符合当前项目的需求的选型才是最正确的。

前端的路还有很长,还有太多太多的东西需要去考虑,前端所需要重视的是用户体验和数据交互,其实最最重要的还有就是性能。不能因为一个错误的想法,让用户觉得当前的系统变得很慢。

感谢大家阅读这篇文章,文章中如果有什么问题,大家在下方留言我会及时做出改正。


Aaron
4k 声望6.1k 粉丝

Easy life, happy elimination of bugs.