关注【索引目录】服务号,更多精彩内容等你来探索!
TL;DR
是的,我明白你会立即对我所说的话产生怀疑,因为“你怎么能改变 Spotify、OpenAI 和其他大公司所使用的东西?”。
但我想说,这个话题在2025年显然已经不新鲜了,我不会在这里透露任何超自然的东西。HTMX和Alpine.js已经向所有人充分证明了这并非无稽之谈。我只是在复述所有内容,但有一点很有意思——HMPL模板语言在某些任务上比前两者更胜一筹。接下来,我将解释它为何以及如何帮助你取代Next.js。
开始吧! ️
这是什么应用程序?
一开始,我想做一个小型落地页作为示例。纯粹是为了我自己。或者是为了简历,或者其他用途,但我只是想快速完成一些事情。
当然,我选择了我每天在工作中使用的堆栈,即 Next.js,我以为我会很快用它做一些事情,但事实并非如此。
让我们看一下该应用程序的设计:
它看起来像是一个可以在 5 分钟内完成的简单应用程序,但显然,当你遇到一个重量级框架时,最困难的部分就开始了——实现。
构建结构、组件和第一个困难
当你开始使用 Next.js 做某事时,首先想到的是什么?当然,你需要将它安装到项目中。这里我们谈到了在框架上创建网站的主要缺点之一,无论是 Next.js、Nuxt.js 还是 Remix。这里的观点有所不同。
现在我们继续安装。我们在终端中输入初始化起点的命令:
npx create-next-app@latest
我设置了一个没有额外 CSS 模块、没有 TypeScript 和其他东西的起点,我只安装了 TurboPack,以便一切都能更快地构建,这就是你所看到的:
这是项目本身的重量,只有起始重量,没有起始组件:
我甚至还没开始做任何事情,只是安装了这个应用而已。如果我想在 Next.js 中安装 RTK-Query 或其他状态管理器,它会有多重?如果我开始认真开发这个应用,会发生什么?
我可以告诉你,它的重量将低于500 兆字节,如果我有很多组件的话,甚至会是1 千兆字节。
应用程序大小和可扩展性
我继续进一步制作应用程序,创建合适的组件,上传图像,稍微更改配置以及其他类似的事情。
结果,我成功创建了以下组件:
- 标题
- 特征
- 促销
- 行动呼吁
- 页脚
是的,它们在那里,原则上这些组件没有任何重量,因为它们是简单的功能,但是,当然,增加了几 MB,但这是可以理解的,因为应用程序很小。
而且,我可能得出了更换框架的最重要原因之一——它们的沉重。
假设我们以一家中型公司在 Next.js 上部署的常规网站为例,该网站位于 Gitlab 或 GitHub 上,node_modules无论你如何压缩,它的大小都会达到几百兆甚至几千兆(不包括文件夹)。但如果是大型项目呢?它们的代码库可能会达到几十千兆,就像 Steam 上的某个大型游戏一样。
按照这个速度,我们即将达到云存储过载的程度,全世界的信息量高达数 TB,需要整栋建筑的服务器来存储所有信息——即使在普通公司中这也是难以理解的,但如果我们谈论的是大型公司呢?
另外,我们考虑到从此类框架构建的程序重量相当大,有30-40 兆字节的纯 javascript,将在客户端上执行。
那么体重怎么办?
当然,有些人认为最明显的解决方案是使用 Web 组件,或者甚至像 21 世纪初那样完全不使用此类系统来制作网站,但实际上这在生产项目中并不适用。
早在 Next.js 出现之前,人们就已经提出了一种替代方案。这种替代方案是一种直接通过标记创建动态 Web 界面的机制。粗略地说,它的功能与.ejs文件类似,但仅限于客户端,并且通过属性来实现。
<div data-some-custom-attr="getHTML()" @click="someFunction()">
</div>
一些最受欢迎的库是HTMX 和 Alpine.js。Alpine.js可能在较小程度上受到青睐,因为它更侧重于标记中的 JS 交互,而 HTMX 则被人们视为框架的完全替代品。在某种程度上,这是正确的,我对此并不反对,但这种方法存在严重的缺陷:
- 几乎最小化的 js 集成
- 几乎不可定制的请求
- 发送请求的旧标准
它更多地是关于 HTMX 的,但很明显 Alpine.js 在语法方面存在一些缺陷,例如.jsx等等。
略有不同的方法
当我们既没有 HTMX 也没有 EJS 时,可以使用几种方法的组合,但可以使用介于两者之间的方法。这就是HMPL模板语言。
首先我们来看看我们改变的结果会是什么样的。
而不是page.jsx:
<body>
<Header/>
<Features/>
<Promo/>
<CTA/>
<Footer/>
</body>
我用常规方法替换它index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Landing Page</title>
<link rel="stylesheet" href="global.css" />
</head>
<body>
<script src="./json5/dist/index.min.js"></script>
<script src="./dompurify/dist/purify.min.js"></script>
<script src="./hmpl-js/dist/hmpl.min.js"></script>
<script src="global.js"></script>
<script>
const body = document.querySelector("body");
const template = `
<main>
<!-- Header Component -->
{{#request src="http://localhost:8000/api/get-header-component"}}{{/request}}
<!-- Features Component -->
{{#request src="http://localhost:8000/api/get-features-component"}}{{/request}}
<!-- Promo Component -->
{{#request src="http://localhost:8000/api/get-promo-component"}}{{/request}}
<!-- CTA Component -->
{{#request src="http://localhost:8000/api/get-cta-component"}}{{/request}}
<!-- Footer Component -->
{{#request src="http://localhost:8000/api/get-footer-component"}}{{/request}}
</main>
`;
const { response } = hmpl.compile(template)();
body.append(response);
</script>
</body>
</html>
我还将所有组件带到服务器并通过fetch底层请求和直接在标记中加载它们。
该方法的优点
现在,让我们纯粹地看一下当我们将基础从 Next.js 更改为 HMPL 时在应用程序中获得的结果。
而且,这个大小还包含了 Express.js 上的服务器及其所有文件。缩减的效果肉眼可见,体积大约缩小了 90 到 100 倍。
是的,我当然可以用纯 HTML 完成所有事情,而且结果也不会超过 1MB,但重点不同。对于简单的项目,这样的系统是有效的,对于用 Next.js部分替换客户端组件也是如此。
我们正在寻找一个简单的基础,以便我们能够用 CSR 替代 SSR,但重点放在服务器端。我们也在服务器上编写所有组件,例如 Next.js(Node.js),但问题是,我们通过标记连接一个包来实现这一点,而我们用的是一整套系统,它只针对大型网站。
结论
这种方法可以让你减少应用程序的代码库数倍(字面意思),但也值得记住的是,这适用于中型应用程序,或者像 webpack 模块联合一样,当一部分是 Vue,另一部分是 Angular,第三部分是其他东西时。
关注【索引目录】服务号,更多精彩内容等你来探索!

