当前位置: 首页 > Web前端 > vue.js

Vuejs大型项目实践——面向服务的设计与业务模块化

时间:2023-03-31 20:46:45 vue.js

前端架构概览思考:我们有什么,我们缺少什么?前端架构分为很多部分,每个项目都会有自己的特点。因此,当我们要对一个大型项目进行优化时,可以从一个概览图入手,比如下图:从我自己的项目特点分析,我们的基础设施比较完善,可以尝试一些公共基础服务.输入,但业务代码极其混乱。原因:由于业务迭代频繁,接班人多,组件规范不好,公共方法没有分离。而且各个业务之间的代码耦合度非常强,看似无关的业务,内部代码却相互调用。长此以往,这个项目肯定很难维护,新的需求迭代只会越来越慢,最后没人愿意接手。那么我的切入点就是从这个代码结构开始的。既然vuejs框架这么自由,我们就可以创造出更多属于自己业务特点的东西。Retrofit1:面向服务设计的前端如何提供服务?定义服务是设计用于执行特定任务的独立软件功能单元。它包含执行完整、离散的业务功能所需的代码和数据集成,并且可以远程访问、交互或独立更新。以往痛点前端的公共代码往往最多放在一个公共目录下,有的甚至分散在不同的业务页面,不断复制粘贴,代码复用率很低。并且没有版本可以跟踪修改历史,从而导致潜在的全球影响。借鉴Chrome团队的面向服务的架构设计(SOA)。将原有的各个模块重构为独立的服务(Service),每个服务(Service)可以运行在一个独立的进程中,访问服务(Service)必须使用定义的接口通过IPC进行通信,从而构建一个系统更内聚、松耦合、易于维护和扩展,更好地实现Chrome简单、稳定、快速、安全的目标!示意图:集成点前端的独立模块可以用npm包实现,每个npm包负责一个独立的公共功能,有版本管理和独立更新。package.json定义导出文件index.js,定义了本模块提供的功能接口和代码文件。接口调用通过export和import实现,可以全局加载,也可以按需加载。示意图:改造效果目录结构:调用方式:import{ServiceStorage}from'hc-services'ServiceStorage.setItem('userId',userId)改造2.业务模块化前端如何有模块?定义模块化是指在解决一个复杂问题时,将系统从上到下逐层划分为若干个模块的过程。每个模块完成特定的子功能,所有模块按照一定的方式组合起来形成一个整体,完成整个系统所需要的功能。以往痛点前端的业务代码容易形成低内聚高耦合的穿插形式,维护难度大,可读性差。另外,vuejs的可选开发导致逻辑关注点碎片化,mixin导致子组件中的方法名和变量名混乱。随着项目规模变大,几年后就很难维护了,没人敢动,只能重构。学习Symfony的捆绑系统(一组可重用的PHP组件)。捆绑包类似于其他软件中的插件,但更好。关键区别在于:Symfony中的所有内容都是一个包,包括框架的核心功能,以及您编写的程序代码。Bundle是Symfony架构中的一等公民。bundle是一组存储在“用于实现独立功能”的目录中的结构化文件。每个目录都包含与该功能相关的所有内容,包括php文件、模板、css、js文件、测试等。示意图:集成点基于Vue的多页面模式。每个页面都是一个完全独立的业务模块(App),可以独立编译部署。每个业务模块又进一步细分为子业务模块subApp,每个subApp自带store、router、mixins等vuejs框架这个业务相关的东西。编译时将subApp等子模块组装在一起,实现一个独立的业务功能。这样可以实现业务代码的解耦,各个子模块的功能更加内聚,更易于维护和扩展。示意图:转换效果子App的接口文件index.js//index.js,子App的导出文件import{HcSubApp}from'hc-micro-pages';importstorefrom'./store';import来自“./路线”的路线;从'./libs/utils'导入{jump2IsvPage,jump2CreateCard};constsubApp=newHcSubApp();subApp.store=商店;//vuex数据注册subApp.routes=routes;//vuerouter路由注册subApp.routePrefix='inquiry';//命名空间隔离subApp.storeModule='inquiry';//命名空间隔离//输出用于融合的subApp对象exportdefaultsubApp;//输出其他子应用调用的对外接口export{jump2IsvPage,jump2CreateCard};SubApp热插拔注册:/***SubApp注册*这里是SubApp热插拔的实现*/importSubAppInquiryfrom'./inquiry';importSubAppCollectfrom'./collect';importSubAppInoculatefrom'./inoculate';从'./doctor'导入SubAppDoctor;导出默认{SubAppInquiry,SubAppCollect,SubAppInoculate,SubAppDoctor,};子应用程序的聚合导入{HcBaseApp,HcSubAppComposer}from'hc-micro-pages';importAppfrom'./App.vue';//引入subAppsimportsubAppsfrom'./subApps';//整合所有subAppsconstcomposer=newHcSubAppComposer(subApps);composer.install();//创建聚合的App实例类MyAppextendsHcBaseApp{beforeStart(){}//hookafterStart(){}//hook}constapp=newMyApp({router:composer.router,//引入聚合数据store:composer.store,//引入聚合数据App,});//创建一个Vue实例挂在dom节点上app.start();改造3、多包管理模式为什么还要涉及到多包?公共服务包+业务模块=?新问题npm包的形式不适合经常修改的项目。总是发布一个新版本,会降低开发效率,而且包的代码必须和业务代码分离。同时运营两个项目写同一个业务,感觉很分裂。不利于调试。同时,业务模块也缺少一个模块应有的特性:版本、修订历史、发布标签。这对灰度发布、版本回滚和问题追踪不友好。学名lerna,名字来源于希腊神话中的九头蛇(LernaeanHydra)。如图所示,它是一个用来管理多包项目的工具(monorepos)。多包是指一个项目包含多个git和npm包。lerna管理的库有很多,如Babel、React、Jest、Taro等,结合点将服务包和业务模块结合到一个项目中。服务包放在packages目录下,业务模块放在pages目录下,每个子目录都初始化为一个npm包进行版本管理。并且由于yarn的工作区特性,每个包和模块都有自己的版本依赖关系。lerna在初始化项目时,会将对各个包和模块的引用变成一个软链接(如果没有指定版本;或者指定的版本与本地包的版本一致,也会形成一个软链接),这样每次修改都会实时生效到其他包上,大大提高开发调试效率。开发调试完成后,可以指定具体的包版本发布到npm源,保证代码的稳定性。并且在打包部署的时候,可以根据版本(例如:hc-utils@1.0.1)标记每个包和模块,并生成一个changelog文件,方便代码回滚和问题追溯。改造效果lerna配置{"useWorkspaces":true,"version":"independent","npmClient":"yarn","packages":["src/*","src/packages/*","src/pages/*",],"command":{"publish":{"allowBranch":["master"],"message":"chore(release):publishpackages","conventionalCommits":true}}}在lerna下发布目录结构之前,标签的最终结果和未来扩展在哪里?最终效果,逻辑图:缺点包的权限问题是一个monorepos项目,也就是说你可以修改所有的代码,在实际开发中会造成一些麻烦。例如,一些成员不小心修改了其他包的代码,我们可能检测不到这些修改。幸运的是,我们会在发布版本时标记master分支上的所有包。如果我们发现当前的MR需求中没有涉及到一些变化的包,那么我们可以lernadiff看看是不是错误码。展望未来,subApp子模块不应仅限于子页面类别。它就像一个页面的构建块,应该提供更多的功能。但是基于目前的业务特点,首先解决的是页面多、复杂的问题。另一种可能性是能够提供逻辑功能,例如用户登录模块(监控令牌过期和自动拦截路由跳转)。还有页面部分功能块的能力,比如广告位(根据positionid,请求数据后自动渲染)。