软件系统变得复杂的三个成因是规模、结构与变化。
针对三个成因,我们可以通过以下方式简化系统:
- 分而治之,控制规模
- 保持结构的清晰与一致
- 拥抱变化
依据这些原则,我们该如何组织文件结构,管理好前端项目复杂度?
什么情况下需要将项目进行拆分维护
在页面不是特别多的情况下,一般不会出现构建的性能问题,项目也达不到需要拆分的程度。按照工具配置的最佳实践,大部分问题都能迎刃而解。但B端的企业级应用交互更复杂,业务模块也较多。几个讨论点和误区需要提前说明:
- React 官方不会给出这种实践标准,如何拆分维护是个工程性问题,开源社区如有最佳实践则可参考引入方案;
- 拆分维护不会以代码规模(多少行代码、多少个文件等)作为衡量是否可拆分的唯一标准;
- 拥抱变化,代码不断演进之后,资源会增多,构建的压力增大,构建速度变慢,因为 webpack 编译时需要根据依赖情况去全链路解析依赖情况进行资源引入和构建。这个时候可以考虑拆分出多个构建的入口,按需构建。
复杂项目(如云ERP、门户集成型应用等)的拆分维护是一个工程架构实践,没有唯一标准,但部分实践经验可供分享和参考:
- 从工程可维护性角度出发,如某个模块由指定的成员维护,那么模块可拆分为独立目录,配置独立编译入口,这样还能降低协作带来的耦合性问题。
- 从业务模块角度出发,将整个大型应用分而治之,控制规模。如一个大型单页应用,可以拆分为4-5个独立的单页应用,这些单页应用再集成到门户。
拆分指的是什么
- 拆分为多个代码工程,可以称之为拆分;
- 同一个代码仓库中,拆分为多个业务模块,并提供多个构建入口,可以称之为拆分;
这样会形成两种不同的拆分方案。
关于 webpack 编译占用内存的说明
首先,webpack 执行资源构建本质上是通过 Node 服务来运行的,所以出现内存溢出导致的问题也得从 Node 层面来解决。
Nodejs 是基于V8构建的,所以在Node中使用的JavaScript对象基本上(Buffer就不是)都是通过V8来进行分配和管理的。V8在占用内存大小上做了限制(64位操作系统,单个Node进程可使用的最大堆内存大小约为1.5GB)。
即使服务器的内存很大,但是由于V8的这种限制,导致Node无法充分利用服务器的资源。
即便如此,为什么V8要做这样的限制呢?
做这样限制的原因其实是与垃圾回收机制相关,以1.5GB的垃圾回收堆内存堆为例,V8做一次小的垃圾回收需要50ms以上,做一次全量的垃圾回收甚至要1s以上,要知道垃圾回收过程中JavaScript线程是要处于暂停执行的状态,太长的暂行时间对于后端服务的性能是会产生较大影响的,所以出于这方面考虑,V8对堆内存做了限制。
即便如此,V8还是提供了可以自定义堆内存大小的方式(—max-old-pace-size),old-space代表老生代、new-space代表新生代。
关于目录组织方式
按功能特性组织目录
src
├── components
├── order
│ ├── user
│ │ ├── action.js
│ │ ├── components
│ │ │ └── index.js
│ │ ├── containers
│ │ │ └── index.js
│ │ ├── reducers.js
│ │ └── sagas.js
└── index.js
按文件类型组织目录
src
├── index.js
├── components
├── containers
├── actions
├── reducers
└── sagas
一般地,从可维护性角度,我们一般会采用【按功能特性组织】的方式。
采用单页应用SPA还是多页应用MPA
(图片来自互联网)
1、SPA 单页应用有诸多好处,用户体验好,切换快;
2、多页应用SEO友好,嵌入集成方便。
两种都有各自的适用场景,需要按场景使用或融合使用。