我是这样重构和优化组件的 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
zcf0508
V2EX    分享创造

我是这样重构和优化组件的

  •  1
     
  •   zcf0508
    zcf0508 2024 年 3 月 14 日 2117 次点击
    这是一个创建于 672 天前的主题,其中的信息可能已经有所发展或是发生改变。

    AI 总结

    这篇文章介绍了一个名为 vue-hook-optimizer 的工具,这个工具可以帮助优化 Vue 和 React 组件代码,通过分析代码使用情况以及链式调用、代码逻辑耦合等方面给出优化建议。作者认为,这个工具能帮助开发者更好地梳理和优化代码,从而提高代码质量。

    引言

    有时我们不得不重构旧代码,可能一个文件里有成百上千行的代码,太复杂难以理解。

    这种场景想必大家都遇到过,特别是在工作中接受了一个新的项目,并且需要在此之上开发新的功能。如果新的功能比较简单,或者新功能较为独立,那么在旧代码的基础上编写代码的难度还是比较低的。但是如果我们的需求,需要在理解旧业务、梳理旧代码,并在旧代码的基础上增加或者修改功能,那么我们就不得不对旧代码进行重构或优化。

    另一个场景是说,我们在开发新功能时,全身心投入在功能的开发下,而暂时忽略了代码的可读性和可维护性,这是非常正常且合理的。但是我们最好不要直接将这样的代码作为我们的成果,这是非常不负责任的表现。

    所以我想开发一个工具来帮助我们分析代码,并找出变量和方法之间的关联关系。我们可以发现一些变量是孤立的,一些方法是过度关联的,然后我们可以重构它们。今天的文章将会主要围绕 vue-hook-optimizer 来介绍一些我常用的优化代码的方式。注意,这里我们主要优化代码本身,针对性能的优化不在今天的讨论范围。如果大家感兴趣,我们后面可以再专门进行讨论。

    优化方案

    工具介绍

    今天主要用到的工具 vue-hook-optimizer 是我开发的专门针对 vue 和 react 组件的代码优化辅助工具,它使用 babel 分析组件的源码并生成 ast 语法树,收集信息并展示一定的优化建议。同时 vscode 作为我们日常的开发工具,也提供了强大的优化和重构能力。

    常见问题

    优化无用代码

    如果我们的代码冗长,并且经过了多次的修改和维护,那么代码中很大程度上会出现冗余的内容,比如说未使用的变量和函数。这是常见的例子。

    <script setup lang="ts"> const notUsedVar = getData() const usedVar = getData() </script> <template> <div> {{usedVar}} </div> </template> 

    在上面的代码中,notUsedVar 变量其实是无效变量,因为它并没有在模板和其他方法中被使用。这个简单的示例是显而易见的。但是如果我们的代码非常冗长,代码的调用是复杂的,那么我们可能无法很快的找出未使用的变量或函数。

    <script setup lang="ts"> function getData1() { return new Person() } function getData2() { return new Person() } const data1 = getData1() const data2 = getData2() const data3 = computed(() => data1.value) </script> <template> <div> {{data2}} </div> </template> 

    在上面的代码中,模板只使用了 data2 ,那么其实代码中只有 data2getData2 是有效函数,其他的代码其实是无效的。

    vue-hook-optimizer 支持分析组件中代码的使用情况,并给出优化的意见,比如针对上面的代码,就会生成下面这样的结果。

    image.png

    无效的链式调用

    为了能够提高代码的可读性,我们一般会把较为独立和重复的部分抽象独立出来作为单独的模块,比较常见的做法比如我们会把 api 接口统一整理在一起,便于组件调用。这是一个非常好的思路,但是在编写代码的过程中,我们也可能会产生过多的无效的抽象,比如抽象的模块职责过于简单或过于复杂,或者代码的可复用性不强等。我们看一个简单的例子。

    <script setup lang="ts"> const baseDate = new Person() function getData1() { return baseDate } function getData2() { return getData1() } const data2 = getData2() const date3 = computed(() => data2) </script> <template> <div> {{date3}} </div> </template> 

    在这个例子中,getData2 和 getData1 其实做了无效的抽象,他们的职责过于简单,并且没有其他代码依赖这两个抽象,那么这两个函数其实是没有必要的。vue-hook-optimizer 能够针对链式调用提供一定的优化建议。

    image.png

    耦合的逻辑

    vue3 和 react 可以使用 composition-api 或者 hook 的范式进行代码的编写,这非常便于我们梳理代码的逻辑,并且更易于测试和复用。但是和 vue2 的 options api 不一样,代码允许放在一起就一定会存在代码耦合在一起的情况。这里给一个我工作中的例子给大家参考看下。

    image.png

    这是我在工作中经常遇到的情况,代码逻辑复杂并且耦合程度很高。比如在图中,左下角有几个独立的灰色节点,这说明这些代码并没有在模板或者方法中被使用;在右侧复杂的调用链里,也存在几个灰色的节点,这些是没有暴露到模板中的内容,在组件的代码中将他们屏蔽掉是更好的选择。

    image.png

    在建议中提示了几个节点为重要节点,说明它们是代码中的关键路径,这些节点报错或者异常可能会阻断代码的逻辑。优化这些节点能够提高整体的稳定性。

    特别的,在 vue-hook-optimizer 提供的建议中高亮了一个循环依赖。代码逻辑中 refresh 方法会调用 getList 获取数据并复制给 searchDeptList 。但是同时 searchDeptList 的变化会在 watch 中触发 refresh 方法,这是非常危险的,需要做好边界情况的处理避免做成无限循环。

    根据提供的建议,有 30 个节点的内容耦合度高,需要我们手动对代码进行优化。比如在这个例子中可以将耦合的代码划分为 处理筛选模块、获取数据模块、处理数据模块。vscode 提供很方便的重构代码的能力,比如支持 重命名符号 重构到新文件 等能力。

    image.png

    这里再放一个代码逻辑比较清晰的情况下,vue-hook-optimizer 提供的可视化图示。

    image.png

    在这张图中,代码的逻辑虽然比较复杂,但是整体上还是可以区分成两个大的模块的,这说明代码结果是清晰的、易懂、易于维护的。

    总结

    维护旧代码一直被认为是吃力不讨好的工作,就像是大家调侃时说的「代码和人有一个能跑就行」。但是我认为,一个富有责任心的开发者,是需要反复推敲业务逻辑,反复打磨自己手里的代码,找出其中的薄弱环节并有针对性地优化。这也是我开发 vue-hook-optimizer 的初衷,我希望能够帮助更多的人更好地梳理和优化自己手里的代码。

    最后,如果你认同我的观点,那么不妨现在就打开 vscode 安装 扩展 ,然后从第一个文件开始检查和优化吧。如果你有什么好的意见或建议,欢迎在评论区留言或到 github 去提 issues ,我都会尽快回复。

    4 条回复    2024-03-15 10:38:46 +08:00
    4ark
        1
    4ark  
       2024 年 3 月 15 日 via iPhone
    感谢分享,不过这些问题是不是可以通过 eslint 和 sonar 一类工具结合来解决?
    zcf0508
        2
    zcf0508  
    OP
       2024 年 3 月 15 日
    @4ark 我也在考虑集成进 eslint 了,目前只有 未在模板中使用 这一条规则,其它的规则还不知道以什么样的方式进行处理。

    https://github.com/zcf0508/vue-hook-optimizer/blob/master/packages/eslint/src/rules/not-used-in-template.md

    eslint 可以实现部分的代码分析功能,但是我觉得提供一个代码耦合相关的图和建议是我这个工具的亮点。后面的工作可能会更加关注在针对耦合的代码提供更有建设性的建议,比如不仅仅是提示需要重构,而是提供更有意义的重构方案等等。
    royalknight
        3
    royalknight  
       2024 年 3 月 15 日
    react 的好像不可用
    zcf0508
        4
    zcf0508  
    OP
       2024 年 3 月 15 日 via Android
    @royalknight react 支持的代码模式比较有限,主要我也不是很熟悉 react ,可以看下源码 test 里的 jsx 部分,应该支持常见的 class 和 hook 模式。如果是用的扩展,可能要改一下设置,选 react 模式。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5195 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 39ms UTC 08:45 PVG 16:45 LAX 00:45 JFK 03:45
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86