Skip to content

这是一个重构项目,基于原项目,构建出更利于稳定性和扩展性的前端架构系统

License

Notifications You must be signed in to change notification settings

HardenSG/Win11InVueRefactor

Repository files navigation

系统重构计划

英文

resume

原项目为第四届字节跳动青训营前端进阶版项目,我小组历时3周完成这个零组件库的Win11 In Vue的开发,作为主力开发人员,我贡献了约 3 / 5 的commit。

偶然回省代码,觉得某些地方写的并不好,比如内容写的比较死;代码重复量高、复用性差;没有过多考虑性能等客观因素;组件注册方式死板丑陋....。

因而想要对此进行重构,吸取先前教训。

  • 代码会尽量以OOP + FP编程范式叙写逻辑。
  • 系统由单系统过渡到monorepo,模板依赖于我的cli搭建
  • 注重分包,删除无意义冗余文件分层
  • 注重通用性,减少重复代码的书写,可以实践HOC or HOF提高复用性
  • 编写过程中,思考数据流向,拒绝无意义重复数据输入,及时察觉错误数据传递,以数据流向作为组件乃至文件分包分层的导向依据

stack

  • Vite
  • Typescript
  • Vue3
  • Pinia
  • VueRouter

架构演变方向

应用注册方式变为手动导出自动注册,通过scheduler/apps导出你所需要的 packages/app中的应用,第三方开发者只需要在其中编写应用即可。

理论上:第三方开发者完全可以采用npm第三方发包的方式进行应用的插装,你只需要在scheduler/apps中简单的import一下就可以使用,系统会提供一些数据,通过provide依赖注入形式,注入到第三方编写的组件中,更多组件编写规则,请参考app开发规范组件编写规范

导出的组件会由统一调度器Scheduler进行管理,因此在Root(View/Home)组件的创建初期,对Scheduler进行初始化和挂载。通过调度器中的信息,而后对这些组件进行处理即可,最后处理的结果就是一个组件数组。因此,系统会直接遍历进行挂载即可

{Object.keys(Applications).map((key, idx) => {
    var WinApp = Applications[key];
    return <WinApp key={idx} />;
})}
  • 组件应该伪挂载,在不需要出现的时候不应该被渲染,否则毫无疑问这会拖垮首屏渲染,因此需要对未出现的组件统统remove,不渲染进dom tree

  • 将所有的组件和taskBar做联动,当点击的时候控制对应的组件显现。通过nomalize HOC实现,也就是说所有的应用其实都是要通过HOC做处理的,这样这个组件就会被HOC所管理,每个组件都会开启一个新的HOC,因此他们之间互不干扰

重构ToolsBar

  • 组件最小化不应该进行隐藏,而是隐藏层级,因为频繁的触发 display:none 会引起性能问题
  • 组件关闭需要考虑是否进行display:none,因为关闭后可能短时间内不会再次打开
  • 组件关闭最小化与否通过调用scheduler的方法实现
  • TODOToolBar作为公共组件,为了更好的维护性应实践OOP的开发方式,因此接下来的工作会着重于refactor ToolBar component and optimization it

如何做好全局联动?

单纯依靠对象的引用特性难以达成需求,如果依靠响应式那么如何将scheduler数据流向全局?

  • 如果采用props那就意味着需要对所有的组件进行改动,这显然违背开闭原则
  • 如果采用依赖注入的方式依然可以实现跨组件共享数据,同时可以确保所有组件都能够正常接收,因为他们同属于一个依赖链,但是性能负担较大,如果大规模组件存在,难以保证性能。
    • 这里的性能负担指的是,同一数据要被顶层App的自己组件也消费,这样注入的依赖深度就可能会不止3层(依赖注入3层以上的传递可能会造成严重的性能问题)
    • 因此不确定性就是不稳定的因素。但是如果要作为系统与应用间的数据共享,是一个很好的选择,因为这既打通了系统间的沟通壁垒,又能将数据流向控制在顶层依赖链中,但是这需要开发者自行遵守
  • 采用store方式可以实现跨组件间共享数据
    • 注意这里说的跨组件应用传递指的是系统中,包括系统的内置baseComponent是根据状态管理工具进行数据共享的。
    • TODOApp级的应用,初步还是想依赖于依赖注入。

重构taskBar

  • 底部栏根据你的配置决定是否固定 通过 Scheduler - IsFixTaskBar实现

  • 底部栏要联动桌面 通过HOC实现

  • taskBar还需要考虑当前打开的app是否是taskBar固定的,如果是固定的就原地打开即可,如果不是就末位打开,按照时间戳排序(UI层消化)

  • ToolsBar联动pinia.components实现层级切换,这就需要组件具备自治能力,因此在此采用OOP建立自定义组件类是最佳实践

taskbar同步消费currentShowTaskbar,数据按照时间戳进行排序 desktop要消费scheduler.components数据,可以直接消费piniacomponents即可

做到多向联动性是系统互联的基础


继续演变

为什么要继续演变?

因为如果TaskBar继续采用HOC方案,那么目标应用在开启的时候需要打开两次,这不是一个好的结果

那么如何做到组件统一管理,且只渲染一次呢?

我的思路是仍然保留scheduler方案,HOC方案也可以继续得以保留,因为以HOC方案做组件的管理要更加单一化细粒度,各HOC各司其职

那么就需要taskBar做出让步,因此taskBar的渲染方案并不是继续采用HOC方案,而是自己渲染出一套icon

通过各组件自行管理的方式导出CustomComponent类实例,其内置组件信息,taskBar可基于此对其进行渲染

如何在组件隐藏的时候能同步taskbar样式

想起来很简单,因为如果是正在显示的话,一定是存在于currentShowComponent中的,如此一来,我需要在taskBar中做出操作

如何操作?

要分为不同的考虑方式

taskBar的显示数据源分为两个部分:fixTaskBarComponentcurrentShowComponent 因此需要考虑:

  1. 如果是fixTaskBarComponent的任务显示无论order与否都是原地显示的
  2. 如果不是fixTaskBarComponent中的任务显示就需要根据order进行排序,order越小距离左侧越近(这个地方写死还是做动态化需要考虑)

因此渲染还需要依赖于currentShowComponent,对于隐藏(非关闭)的组件来讲,它仍然还存在于currentShowComponent中,因此这个时候需要根据isHide判断(需要分区域考虑了)是否隐藏,对当前显示的和隐藏的内容所应用的类是不同的比如显示的是长蓝色条,隐藏的是白色的条

因此在components/taskbar.vuecomputed阶段就需要进行划分了,将不是fixTaskBarComponent的任务划分出来,这部分是需要用order排序的(这个保留与否有待思考,因为感觉不太美观)

只要不是fixTaskBarComponent的内容就直接根据isHide处理就好了

About应用

  1. 先抛出问题:自定义应用如果需要store或者其他数据进行第三方app间联动,这如何实现?

    这需要一步步思考为何需要这样,这样的应用场景有哪些举例证明一下;如何做到跨应用数据共享,如何做到跨应用数据变动....

    如何组件间共享数据,我相信方案绝对不止一种,包括上面思考的三种实现方式:propsstoreprovide之外肯定还有能够实现的方案。不过不论哪种方案来讲,都需要遵守以下的原则:

    • 是否遵守合理安全的数据流向
    • 代码可访问安全性:(不能将全部的隐私数据开放给用户)
    • 代码复杂程度,数据流向复杂程度
    • 。。。。

    1. 对于props来讲,我觉得并不是一个好的选择,尽管你可以自定义选择是否接收props,但在组件的挂载初期,要将中心放在这上面,并且不能实现第三方的数据插入到另一个appprops
    2. 对于store来讲,要思考是否具有必要性,因为这会另引入新包,并且尽管可以由app自定义store数据,那么这个store的引入就必需通过core repo 某个文件导出三方appstore 或者,第三方的app直接引入另一个appstore 这你觉得好吗?

    所以最佳的方案我认为还是 依赖注入 的形式,应用可以方便的引入其他app 暴露的数据,只需要简单的inject一下,便可以拿到你想要的数据。同时在组件的挂载时期,需要遍历待挂载的组件,检测到有暴露的数据就将其provide即可,由于组件最终是需要挂载到core/Home/index.vue中的,因此就能实现所有的组件数据共享。不过要想达成这一点就需要修改CustomComponent同时需要更新HOC的逻辑。

    不过在编写的时候应当注意以下的事项

    • provide 的名字需要标明组件名称,用户自定义数据名,以下划线分割,如:Folder_FolderData,用户在使用的时候需要标明,以防混淆,因此数据的名称需要在注册期做正则判定
    • ....

待续....

About

这是一个重构项目,基于原项目,构建出更利于稳定性和扩展性的前端架构系统

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published