最佳 Alpine.js 替代方案

2025-06-07

最佳 Alpine.js 替代方案

在本文中,我将向您介绍 Alpine.js 的绝佳替代品,它将帮助您使用服务器端 HTML 完成相同的操作(甚至更多)。

几个月前,我写了一篇有关 HTMX 的类似文章,现在我终于可以写一下使用HMPL而不是Alpine.js可以获得的好处

我认为这个想法比迄今为止所做的有更大的潜力。

好吧,让我们开始吧!


👀 我们如何比较?

首先,所有比较都将在服务器连接的上下文中进行。我们不会在这里考虑常规客户端功能的选项。尽管一切都在客户端完成,但仍然存在明显的差异。

比较时我们将考虑以下参数:

  • 渲染
  • 自定义服务器请求
  • 磁盘空间
  • 模块内部是什么样的

我们还将讨论支持、安装简易性和其他一些要点。


🔧 渲染

在现代 Web 开发中,界面渲染方法的选择至关重要。我们将探讨两种截然不同的方法:HMPL 中的模板编译和 Alpine.js 的声明式方法。这两种技术为用户界面提供了不同的处理范例,每种范例都有各自的优势和实现特性。

HMPL

HMPL 使用客户端模板编译,这意味着标记被转换成动态生成 HTML 的 JavaScript 函数。

const templateFn = hmpl.compile(`
  <div>
    {{#request 
       src="/api/my-component"   
       indicators=[
         {
            trigger: "pending"
            content: "<p>Loading...</p>"
         }
       ]}}
    {{/request}}
  </div>
`);

// Usage
const component = templateFn();
Enter fullscreen mode Exit fullscreen mode

该模板被编译一次为可执行函数,该函数:

  • 创建优化的渲染函数

  • 缓存结果以供重复使用

  • 为将来的更新准备 DOM 结构

Alpine.js

Alpine.js 提供了一种声明式风格——您可以通过属性( x-data、、 )直接在 HTML 中描述行为x-showx-text

<div x-data="{ user: null, loading: true }"
     x-init="fetch('/api/user')
       .then(r => r.json())
       .then(data => { user = data; loading = false; })">

  <template x-if="loading">
    <div>Loading...</div>
  </template>

  <div x-show="user" class="user-card">
    <h2 x-text="user.name"></h2>
    <span x-show="user.isPremium" class="badge">Premium</span>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

以下是 Alpine.js 代码工作原理的简明 4 点细分:

  • 该组件使用 Alpine.js 指令直接在 HTML 标记中定义其反应状态和数据获取逻辑。

  • x-init钩子在组件安装时自动触发数据加载,管理请求和状态更新。

  • Alpine 的x-if指令x-show根据加载状态和数据可用性处理动态 UI 渲染。

  • 当状态改变时,模板会自动重新渲染,使 UI 与底层数据保持同步,而无需手动操作 DOM。

比较

HMPL 提供了一种自动化渲染方法,内置了请求处理和模板功能,非常适合需要编译的复杂数据驱动组件。Alpine.js 通过显式 fetch 调用和响应式状态管理提供了更透明的控制,更适合轻量级交互。具体选择取决于项目需求——HMPL 擅长结构化模板,而 Alpine.js 则擅长快速原型设计和简单的动态元素。


🪄 自定义服务器请求

在构建动态 Web 应用程序时,高效地管理服务器请求至关重要。与自定义范围有限的 HTMX 不同,Alpine.js 提供了更广泛的自定义范围,自定义过程本身几乎与 jsx 类似,只需将 js 代码直接插入属性即可。当然,唯一的限制是模板。

<div x-data="{ user: null, error: null }"
     x-init="fetch('/api/user')
       .then(r => r.json())
       .then(data => user = data)
       .catch(e => error = e)">
</div>
Enter fullscreen mode Exit fullscreen mode

用这种方法我们看到它非常方便,但问题是它很可能看起来像eval,或者根据现成的模式处理模板。

这种方法存在许多严重的缺陷,因为随着 JS 的每个新版本的发布,越来越多的新功能需要通过这种方法来支持。在 jsx 中,这一点是合理的,因为事实上,jsx 是 React 的基础,而在这里它只是一个可以通过script标签连接的模块。我们严重依赖于版本更新,这使得这种方法虽然方便,但并不完全实用。

在 HMPL 中,使用了一种不同的方法,我们可以直接在模板中编写我们需要的一些最小部分,例如方法、接收 HTML 的路由和其他内容,但是我们将整个 js 部分写入 js 中。

const templateFn = hmpl.compile(...);

const elementObj = templateFn(({
  request: { event, clearInterval }
})=>{
  clearInterval?.();
  return {
      mode: "cors",
      cache: "no-cache",
      credentials: "same-origin",
      headers: {
        "Content-Type": "text/html",
      },
      redirect: "follow",
      get: (prop, value) => {},
      referrerPolicy: "no-referrer",
      body: new FormatData(event.target, event.submitter),
    }
});
Enter fullscreen mode Exit fullscreen mode

这里,js 部分和 html 部分有明确的区分。因此,你不会依赖于模块的新版本,因为描述 js 所需的一切,你都可以在这里编写,即使是 1.0.0 版本,即使是 3.0.1 版本。

此外,在 Alpine.js 中,使用此类语法存在 XSS 注入的风险。没错,它当然不是真正的eval,而是相同的,只是语法有限,可以避免大多数风险,但仍然存在风险。这不仅是 Alpine.js 的问题,也是所有模块(包括 HMPL)的问题。顺便说一下,HMPL 中有一个选项,可以从sanitize传入 HTML DOMPurify


📁 磁盘空间

这可能是比较时最简单、最易理解的事情。只需编写相同的代码并进行比较(但我们必须明白,如果应用程序很大,那么代码也会呈指数级增长)。

Alpine.js

document.querySelector(
  "#app"
).innerHTML = `<div x-data="{ count: 0, l() { fetch('/a').then(r => r.text()).then(d => this.c = d)}}"><button @click="l()">Click!</button><div>Clicks: <span x-text="c"></span></div></div>`;
Enter fullscreen mode Exit fullscreen mode

HMPL

document
  .querySelector("#app")
  .append(
    hmpl.compile(
      `<div><button>Click!</button><div>Clicks: {{#r src= "/api/clicks" after="click:button" }}{{/r}}</div></div>`
    )().response
  );
Enter fullscreen mode Exit fullscreen mode

这里大概是清楚了,写出来会比较短。

但是,如果您仍然需要完整的测试,那么有一个包含 tests 的存储库。该模块还有第二个版本,它更短,但第三个版本的本质没有改变。

比较

这些数字最接近大型和小型项目的实际结果。


⚙️ 模块内部是啥

这是指发送请求本身的技术。我不会写关于RegExp处理模板的方法,或者如何将元素保存到数组中——这些对客户端来说根本不应该有趣。

我们主要考虑的是XMLHTTPRequest支持fetch。关于这个话题,我们有以下内容:

Alpine.js

fetchAlpine.js 与和方法完全兼容XMLHTTPRequest。在某些情况下,这允许发出更精确的请求,例如overrideMimeType

<div x-data="{ data: null }"
     x-init="
       const xhr = new XMLHttpRequest();
       xhr.overrideMimeType("text/html");
       xhr.open('GET', '/api/data');
       xhr.onload = () => { data = JSON.parse(xhr.responseText) };
       xhr.send();
     ">
  <div x-text="data?.message || 'Loading...'"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

尽管这种方法存在缺点eval,但它仍然是一种非常方便的切换方式,Alpine.js 在这方面可以发挥一定的优势。在相同的 HTMX 中,您只能使用它,XMLHTTPRequest而无法更改它。

HMPL

不幸的是(或者说幸运的是),HMPL 不支持XMLHTTPRequest请求,并且所有内容都建立在 之上fetch,这是不可替代的。请求发生在模块内部,您只需描述它们:

<div>
    <button data-action="increment" id="btn">Click!</button>
    <div>Clicks: {{#request
      src="/api/clicks"
      after="click:#btn"
    }}{{/request}}</div>
</div>
Enter fullscreen mode Exit fullscreen mode

这也有一个优点,因为thencatch和其他东西都是在模块内实现的,所以你不必像在 jsx 中那样编写它。

结论

当然,你可以在项目中使用最适合你的框架。比如说,在文章中我们讨论了与服务器请求相关的部分,但 Alpine.js 也包含其他部分,这使得它成为一种轻量级框架。但是,如果我们要处理服务器端的工作,我建议(谁会怀疑呢👽)使用 HMPL,因为它更适合这项任务。所以,这两个选项都很不错!

🔗 模块链接:

HMPL - https://github.com/hmpl-language/hmpl
Alpine.js - https://github.com/alpinejs/alpine

非常感谢大家阅读这篇文章!

谢谢

文章来源:https://dev.to/hmpljs/best-alpinejs-alternative-2hme
PREV
📢 HMPL v3.0:全新重大更新!
NEXT
以 Spotify 为例,解释 OAuth 的工作原理 它是什么?工作原理 创建“客户端应用程序” 建立指向“提供商”的链接 为重定向 URL 创建端点 测试其是否正常工作 保存刷新令牌 为什么每个人都实现 OAuth?不要发明自行车