前端重构实践(二) —— 模块化开发

简介:
  • 前言:

在上一篇文章中我介绍了我们对N产品性能优化的整个历程,主要偏重优化方法。本篇我将介绍在这一过程中,我们的代码出现了什么样的问题,以及我们是如何通过前端重构来解决掉这些问题,并产生了哪些收益。


  • 痛点

按需加载为我们的页面带来了很大的性能提升,但同时也为代码结构带来了很大的冲击,很多直接调用的方式被改为了模块化的调用形式(先判断模块是否存在,不存在就先加载对应的js,再执行回调)。

 

而js代码本身又不是模块化形式的。就使得代码结构很混乱,各种调用方式都存在,开发人员在写代码的时候不知道该直接调用还是模块化调用。

打包配置混乱,散落在各个目录结构中,经常出现重复打包和漏打包的现象,严重的还造成线上问题。

因为长期的产品策略变更,导致代码不同功能块之间耦合严重,一些关键方法不知道都在哪里被调用过,如果修改的时候有遗漏,就会出现问题。

没有文档。

没办法做自动化测试。

  • 思考

因为以上问题,我们每次产品升级都如履薄冰,需要非常小心谨慎,测试也很耗费精力。为了提高效率,我们必须要重构。

这次重构迫切要解决的问题有三点:

1. 代码调用方式统一,希望加载方式可以对开发人员透明。

2. 模块职责明确、模块之间依赖关系清晰。

3. 按需加载的配置可以统一管理,不影响开发时的效率。

这三点,让我很自然地就想到了JS模块化开发

  • 模块化开发:

关于模块化框架和CommonJS规范,在网上有很多介绍的文章,我就不在这里赘述了。我只说最关键的一点:每个模块都有明确的定义(模块名、输入、输出),模块之间的依赖和调用必须通过require或use的形式。如下图是一个common/pop模块的示例代码:


这种设计带给我们最大的好处是:规范了代码之间的调用方式,开发人员在写use的时候,不用担心这个模块是否已经被加载,所有的加载策略和打包策略都对他是透明的。

  • 模块依赖 & 自定义事件

如上面说到的,按照CommonJS规范,模块之间有require和use两种依赖形式,我们加入了第三种:fire(事件触发)。通过自定义事件的监听和触发,我们实现一种弱依赖的形式。

fire适用于投统计、异常处理等场景,不会触发代码加载。

  • 打包配置:

将以前分散在各个地方的打包策略合并到同一个配置文件中,如下图(示例代码):

它起到两个作用:1. 保证项目编译的时候将模块打包到对应文件;2. 在使用模块的时候,去检测它所在的js文件是否已经加载,如果没有则自动加载。

可以看到,我们对css也做了同样的模块化加载的处理。

  • 文件加载 & CSS模块化

对于按需加载的组织形式而言,文件的加载监控很重要。

早期我们对CSS做延迟加载的时候,碰到一个情况:由于这部分CSS加载是异步的,如果网络状况不好,就可能出现JS已经将页面元素组装好了,但是CSS还没加载完成,这一部分页面就会乱掉。后来我们采用了“先隐藏元素,等CSS加载结束再重写display属性来显示元素”的方法,避免了这种case。不过这毕竟不是一个系统化的解决办法。

如何鉴定文件加载的结束,特别是CSS文件的加载结束是个蛮有学问的事情。在框架中对于文件的下载监控,我们借鉴了SeaJS的思想,对于这块感兴趣的同学可以深入研究一下。

  • 整体架构

基础层是对一些基础模块和session数据的封装,这些方法每个模块都会用到,就不再做单独的require,打包成ctx变量传入每个模块的定义中进行使用。

应用层是具体的产品功能开发,对于数据的处理统一使用view/model/service的形式,由view从模板的textarea(性能优化考虑)中提取数据建立model,由service统一向server端发送异步请求进行持久化。

通用层是业务逻辑无关的组件,很多产品都可以复用,如分页、截字、弹层、类定义等。

物理层:通过config.js来统一配置按需加载的打包策略,并在模板中对编译加戳后的物理文件进行引用。

  • 代码文档:

既然每个模块都有统一的定义方式,模块之间的依赖和调用也有统一的形式,那么我们通过对代码进行自动分析,就生成了类似如下形式的代码文档

每个模块的依赖与被依赖、调用与被调用信息,一目了然。

开发人员利用这个文档可以清楚的知道他的每次修改都可能会影响到哪些模块。

QA人员可以根据每次提测的模块列表,评估出可能会影响到的case范围。

这对于开发和测试的效率提升不言而喻。

最重要的是,这是有生命力的文档,不需要维护,每次代码写完后就可以自动生成。

  • 单元测试:

按照模块化进行重构之后,我们可以针对单个组件写case进行测试。这里用到了Qunit框架。效果如下图:

  • 问题:

当然,模块化框架并非前端开发的银弹。我们在重构过程中也碰到了“不好调试”、“出现循环依赖后不好定位”等问题。这也是我们接下来要尝试解决的方向。

另外,重构后我们发现,框架本身和模块配置打包的代码,合并压缩后也有4-5k,这对于性能优化并没有太大的帮助。

  • 总结:

模块化框架对于按需加载、模块划分、代码复用、自动文档、单元测试、团队合作等都有很大的帮助。

本次重构规范了JS和CSS的模块化使用,让模块划分变得更清晰,让开发变得更单纯,为以后的升级维护奠定了一个很好的基础,提高了测试的效率,并且使得“单元测试”,“自动化测试”,和“敏捷开发持续集成”等 成为了可能。

本次重构还没有对HTML做模块化拆分,所以还没办法做到“模板的独立渲染”。这会是我们团队后续的工作方向之一。

by lizhouquan










本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/1033712,如需转载请自行联系原作者

相关文章
|
1月前
|
缓存 前端开发 JavaScript
利用代码分割优化前端性能:策略与实践
在现代Web开发中,代码分割是提升页面加载性能的有效手段。本文介绍代码分割的概念、重要性及其实现策略,包括动态导入、路由分割等方法,并探讨在React、Vue、Angular等前端框架中的具体应用。
|
15天前
|
编解码 前端开发 开发者
探索无界:前端开发中的响应式设计深度实践与思考###
本文将带你领略响应式设计的精髓,一种超越传统页面布局限制的设计策略,它要求开发者以灵活多变的思维,打造能够无缝适应各种设备与屏幕尺寸的Web体验。通过深入浅出的讲解、实际案例分析以及技术实现细节的探讨,本文目的是激发读者对于响应式设计深层次的理解与兴趣,鼓励在实际应用中不断创新与优化。 ###
60 10
|
29天前
|
编解码 前端开发 开发者
前端开发中的响应式设计实践
前端开发中的响应式设计实践
|
1月前
|
编解码 前端开发 UED
探索无界:前端开发中的响应式设计深度解析与实践####
【10月更文挑战第29天】 本文深入探讨了响应式设计的核心理念,即通过灵活的布局、媒体查询及弹性图片等技术手段,使网站能够在不同设备上提供一致且优质的用户体验。不同于传统摘要概述,本文将以一次具体项目实践为引,逐步剖析响应式设计的关键技术点,分享实战经验与避坑指南,旨在为前端开发者提供一套实用的响应式设计方法论。 ####
64 4
|
26天前
|
编解码 前端开发 UED
探索无界:前端开发中的响应式设计哲学与实践####
本文不拘泥于传统摘要的框架,而是以一种对话的方式,引领读者踏入响应式设计的奇妙世界。想象一下,互联网如同一片浩瀚的海洋,而网页则是航行其中的船只。在这片不断变化的海域中,如何让我们的“船只”既稳固又灵活地适应各种屏幕尺寸和设备?这正是响应式设计的魅力所在。通过深入浅出的探讨,我们将一同揭开它背后的哲学思想与实战技巧,让你的网页在任何设备上都能展现出最佳姿态。 ####
21 0
|
29天前
|
前端开发 JavaScript API
现代前端框架中的响应式编程实践
现代前端框架中的响应式编程实践
36 0
|
2月前
|
人工智能 资源调度 数据可视化
【AI应用落地实战】智能文档处理本地部署——可视化文档解析前端TextIn ParseX实践
2024长沙·中国1024程序员节以“智能应用新生态”为主题,吸引了众多技术大咖。合合信息展示了“智能文档处理百宝箱”的三大工具:可视化文档解析前端TextIn ParseX、向量化acge-embedding模型和文档解析测评工具markdown_tester,助力智能文档处理与知识管理。
|
1月前
|
缓存 监控 前端开发
前端开发中的性能优化:策略与实践
前端开发中的性能优化:策略与实践
|
1月前
|
编解码 前端开发 UED
前端开发中的响应式设计实践
前端开发中的响应式设计实践
38 0
|
2月前
|
JavaScript 前端开发 Docker
拿下奇怪的前端报错(二):nvm不可用报错`GLIBC_2.27‘‘GLIBCXX_3.4.20‘not Found?+ 使用docker构建多个前端项目实践
本文介绍了在多版本Node.js环境中使用nvm进行版本管理和遇到的问题,以及通过Docker化构建流程来解决兼容性问题的方法。文中详细描述了构建Docker镜像、启动临时容器复制构建产物的具体步骤,有效解决了不同项目对Node.js版本的不同需求。
115 0