数字营销 · Web开发 · 基础设施

制造业网站性能优化:前端功能模块化

制造业网站功能越来越丰富,但并不是每个页面都需要加载全部前端代码。本文结合实际网站开发经验,介绍如何通过前端模块化和按需加载,让页面只加载真正需要的功能,在减少资源请求和运行开销的同时,也让长期维护更加简单。

熟悉我的朋友都知道,在制造业网站开发过程中,除了内容、版式和 SEO 之外,我一直比较关注网站性能。因为对于制造业企业来说,网站很多时候并不只是一个展示页面,它既是企业的品牌窗口,也是客户了解企业、进入转化流程的重要入口。

尤其是中小制造业企业,很多客户第一次接触一个品牌,就是从网站开始。页面打开速度、滚动是否流畅、交互是否顺畅,这些看起来比较细节的问题,实际上都会影响用户对企业的第一印象。特别是在广告着陆页场景中,用户可能只停留几十秒。

这个时候,网站性能就更加重要。但制造业网站还有一个特点:页面又不能为了追求速度,做得过于简单。

很多时候,丰富的内容展示本身就是用户体验的一部分。比如:产品轮播、图库、数字增长、标签切换、滚动动画、视频模块……

这些功能可能只在某一个页面使用,也可能被多个页面重复使用。这就带来了一个很现实的问题:一个网站到底应该怎么管理这些前端功能?

早期网站:功能集中加载

以前很多网站的做法都比较简单。所有页面统一加载 jQuery,然后各种页面效果全部基于 jQuery 开发,这种方式在当年非常流行。一方面是因为开发比较快,另一方面是因为当时的插件生态也非常丰富。但随着网站越来越复杂,问题也慢慢暴露出来。

首先,jQuery 本身就有一定的体积,但很多页面实际上只使用了其中很少的一部分能力。更大的问题是,很多项目并没有按照页面实际需求加载功能,而是所有页面统一加载一套公共 JS。

main.js
app.js
common.js

之类的统一文件里。这样做虽然简单,但一个页面即使只需要一个轮播,也可能把其他功能一起加载进来。很多代码当前页面根本用不到。但浏览器还是需要:下载、解析、执行。页面上的功能越来越多,公共 JS 也会越来越大,最后一个看起来并不复杂的企业网站,前端资源反而变得越来越重。

后来开始拆 JS 功能文件

再后来,有些项目开始按照页面拆分 JS 文件。哪个页面需要什么功能,就引入对应的 JS 文件。这样确实比所有代码统一加载合理了很多,因为至少可以避免一部分无关代码被加载。

但管理上的问题也随之出现了,页面模板开始变得越来越复杂。开发人员需要不断记住:

  • 这个页面要加载哪个 JS?
  • 那个页面还需要哪个文件?
  • 以后增加一个功能,又应该放在哪里?

时间一长,前端的依赖关系就会越来越混乱。还有一些项目,直接把功能逻辑写进页面模板或者页面模块内部。刚开始开发的时候很方便。但是网站运行几年之后,通常就会遇到:功能无法复用、升级困难、配置混乱、维护成本越来越高。

而企业网站恰恰又是生命周期很长的一类网站。一个项目可能运行很多年。前端代码如果没有一个比较清晰的结构,时间越长,越容易失控。

RequireJS模块化加载方案

后来,为了解决前端模块之间的依赖问题,也出现了 RequireJS 这样的模块化加载方案。

RequireJS 可以根据页面需要动态加载不同的 JavaScript 模块,同时处理模块之间的依赖关系。相比把所有代码都塞进一个 main.js,这种方式已经进步了很多。

但对于现在的企业网站来说,RequireJS 这套完整的模块化机制,很多时候又显得有些重了。

一方面,企业网站本身的功能通常比较明确,页面之间也相对独立,并不需要复杂的模块依赖关系;另一方面,现在主流浏览器对原生 JavaScript 的支持已经非常完善,很多过去需要依赖额外库,或者为了兼容不同浏览器而做的处理,现在都可以直接交给浏览器完成。

所以,模块化加载的思路当然可以保留,但实现方式其实没有必要那么复杂。

结合制造业网站的实际特点,我更希望做到一件简单的事情:页面需要什么功能,就加载什么功能。

让 HTML 自己声明需要什么功能

于是,我给网站设计了一个主功能文件 app.js。它除了统一处理页面公共逻辑、初始化逻辑和基础功能之外,还负责检查 HTML 中声明的组件,并根据这些声明异步加载对应的功能模块。

HTML 依然按照正常方式编写,只是在需要某个功能的时候,在对应元素上声明组件:

<div component="gallery"></div>

这里的 component="gallery",就是一个模块声明。页面加载之后,app.js 会检查当前页面中有没有需要加载的组件。

如果发现:

component="gallery"

就知道当前页面需要 gallery 模块,然后异步加载:

gallery.js

如果页面没有这个组件,就不会请求对应的 JS 文件。

也就是说:页面需要什么,就加载什么。没有出现的功能,就不加载。这样,一个只使用图库功能的页面,不需要为了一个图库,把轮播、视频、动画等其他代码一起加载进来。

现成的 Demo

这套模块化加载方式,实际上现在这个网站就在使用。比如你正在查看此页面的评论功能,就不是所有页面统一加载 comment.js。你可以直接查看网站源代码,在评论区域的 section 上,可以看到:

component="comment"

这个属性就是模块声明。

网站主要的 app.js 加载运行之后,会自动检查当前页面中有没有需要加载的组件。发现 component="comment",就会加载对应的 comment.js 模块,没有这个组件的页面,自然也不会加载这部分代码。

所以整个网站需要哪些功能,其实从 HTML 结构本身就能够很直观地看出来。

这也是我采用这种方式的一个原因:功能跟着页面走,需要什么加载什么,不需要的就不加载。

有兴趣的同学可以直接研究我的网站源代码,也可以在评论区交流。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。