通常,Alpine.js 之類的東西會與 Next.js 之類的框架進行比較,因為它們具有優勢。
現在我們要深入探討一些更相關的內容。這兩個模組(Alpine.js 和 HMPL)都直接與 HTML 交互,並且都旨在使邏輯更接近標記。這使得這次比較更加紮實。
開始吧! 🏎️
讓我們從最基本的點擊器範例開始。使用 Alpine.js,你可能會寫出類似這樣的程式碼:
<div
x-data
x-fetch:clicker="{
url: '/click',
method: 'POST'
}"
x-init="$fetch.clicker"
class="clicker-container"
>
<h1>Alpine Clicker</h1>
<div class="click-count" x-text="$fetch.clicker.data?.count ?? 0"></div>
<button class="click-button" @click="$fetch.clicker">Click</button>
</div>
它看起來很棒,最重要的是,它能正常工作。現在讓我們來看看 HMPL.js 版本:
<body></body>
<script>
const templateFn = hmpl.compile(`
<div class="clicker-container">
<h1>HMPL Clicker</h1>
<div class="click-count" id="counter">
{{#request src="/click" after="click:#btn"}}
{{/request}}
</div>
<button id="btn">Click!</button>
</div>
`);
const clicker = templateFn().response;
document.querySelector("body").append(clicker);
</script>
如您所見,我們有兩種不同的理念:Alpine.js 在 HTML 內部以聲明方式運作,而 HMPL 則編譯模板並透過 JS 動態渲染。但介面在概念上是相似的——操作與事件綁定,資料更新在 DOM 中。差別在於控制力和靈活性。
另外,如果你能點個星支持這個計畫就更好了!謝謝❤️!
{% cta https://github.com/hmpl-language/hmpl %} 💎 星標 HMPL ★{% endcta %}
Alpine.js 雖然簡潔易用,功能強大,但它並非天生就基於面向伺服器的範式建置。它是一個客戶端增強工具,旨在實現輕量級交互,而不是完全的模板化或伺服器端渲染。這使得它非常適合漸進式增強,但在建立嚴重依賴伺服器驅動內容的應用程式時會受到一定限制。
由於 Alpine 本身並不將伺服器視為 UI 生命週期的核心部分,因此整合複雜的請求流程或處理伺服器狀態常常感覺像是附加的。即使使用@alpinejs/fetch
這樣的插件,你仍然主要需要編寫客戶端邏輯、手動協調 fetch 呼叫以及管理瀏覽器中的響應式狀態。
隨著應用規模的擴大,這種用戶端依賴性強的方法可能會變得繁瑣。表單提交、條件載入、動態內容更新都需要越來越繁瑣的 JavaScript 綁定或涉及x-init
、外部方法和巢狀指令的 hack 操作。 Alpine 為您提供控制權,但通常缺乏抽象。
相較之下,像 HMPL 這樣的模板語言是以伺服器為核心設計的。它原生支援伺服器渲染的 HTML 和 fetch 驅動的響應式回應。您無需手動協調狀態或請求——它是聲明式的、上下文感知的,並且專為伺服器和 UI 協同工作的場景而建置。
讓我們來看一個更高級的例子,一個帶有載入指示器的註冊表單。它在 Alpine.js 中可能如下所示:
<div x-data="formComponent()" id="wrapper">
<form @submit.prevent="submit">
<div class="form-example">
<label for="login">Login: </label>
<input type="text" name="login" id="login" x-model="form.login" required /><br/>
<label for="password">Password: </label>
<input type="password" name="password" id="password" x-model="form.password" required />
</div>
<div class="form-example">
<input type="submit" value="Register!" />
</div>
</form>
<template x-if="loading">
<div class="indicator">
<p>Loading...</p>
</div>
</template>
<div id="response" x-text="responseText"></div>
</div>
<script>
function formComponent() {
return {
form: { login: '', password: '' },
loading: false,
responseText: '',
async submit() {
this.loading = true;
const res = await fetch('/api/register', {
method: 'POST',
body: JSON.stringify(this.form),
headers: { 'Content-Type': 'application/json' },
});
const text = await res.text();
this.responseText = text;
this.loading = false;
}
};
}
</script>
現在讓我們來看看如何在 HMPL 中實現相同的功能:
<body></body>
<script>
const templateFn = hmpl.compile(`
<div id="wrapper">
<form onsubmit="event.preventDefault();" id="form">
<div class="form-example">
<label for="login">Login: </label>
<input type="text" name="login" id="login" required /><br/>
<label for="password">Password: </label>
<input type="password" name="password" id="password" required />
</div>
<div class="form-example">
<input type="submit" value="Register!" />
</div>
</form>
<p>
{{#request
src="/api/register"
after="submit:#form"
repeat=true
}}
{{#indicator trigger="pending"}}
<div class="indicator">
<p>Loading...</p>
</div>
{{/indicator}}
{{/request}}
</p>
<div id="response">{{response.body}}</div>
</div>
`);
const initFn = (ctx) => {
const event = ctx.request.event;
return {
body: new FormData(event.target, event.submitter),
credentials: 'same-origin',
};
};
const result = templateFn(initFn);
document.body.append(result.response);
</script>
借助 HMPL,我們可以實現更精細的控制。您可以攔截事件、存取FormData
、自訂標題、控制指示器,所有這些都可以在聲明式範本結構中實現。
我們不要忽視尺寸差異。
Alpine.js 非常小巧,功能雖然精簡,但依然保持著極小的體積。以下是一個簡單的示意圖:
📦Alpine.js:
📦HMPL:
所以,Alpine 在尺寸上確實輸了。但差距並不大——如果你正在建立更具互動性或伺服器驅動的東西,那麼略微的尺寸增加或許值得你增加靈活性。
此外,從更廣泛的比較來看,HMPL 的表現仍然出奇地好:
當然,功能集越小,最終的 JS 套件就越小,但這也意味著您需要在 HTML 之外編寫更多的命令式邏輯。
對於那些需要簡單、內嵌響應式功能,又不想使用大型框架複雜度的專案來說,Alpine.js 是一個不錯的選擇。但在本文中,我想介紹一種替代方案。
HMPL 提供了一種更現代、可自訂的伺服器驅動 UI 方法。如果您的應用程式需要動態資料處理、進階請求邏輯或完全的抓取控制,HMPL 可能更適合您。
最終,一切都取決於選擇合適的工具來完成合適的工作。
感謝您閱讀這篇文章❤️!
你對這個比較有什麼看法?請在留言處留言告訴我!
有用的連結:
原文出處:https://dev.to/hmpljs/i-replaced-alpinejs-in-my-app-with-this-alternative-kgk