阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

63 個專案實戰,寫出作品集,讓面試官眼前一亮!

立即開始免費試讀!

通常,Alpine.js 之類的東西會與 Next.js 之類的框架進行比較,因為它們具有優勢。

現在我們要深入探討一些更相關的內容。這兩個模組(Alpine.js 和 HMPL)都直接與 HTML 交互,並且都旨在使邏輯更接近標記。這使得這次比較更加紮實。

今天,我們正在用HMPL取代專案中的Alpine.js

開始吧! 🏎️


⚙️ 從簡單的例子

讓我們從最基本的點擊器範例開始。使用 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:

HMPL

所以,Alpine 在尺寸上確實輸了。但差距並不大——如果你正在建立更具互動性或伺服器驅動的東西,那麼略微的尺寸增加或許值得你增加靈活性

此外,從更廣泛的比較來看,HMPL 的表現仍然出奇地好:

比較

當然,功能集越小,最終的 JS 套件就越小,但這也意味著您需要在 HTML 之外編寫更多的命令式邏輯。


結論

對於那些需要簡單、內嵌響應式功能,又不想使用大型框架複雜度的專案來說,Alpine.js 是一個不錯的選擇。但在本文中,我想介紹一種替代方案。

HMPL 提供了一種更現代、可自訂的伺服器驅動 UI 方法。如果您的應用程式需要動態資料處理、進階請求邏輯或完全的抓取控制,HMPL 可能更適合您。

最終,一切都取決於選擇合適的工具來完成合適的工作


感謝您閱讀這篇文章❤️!

你對這個比較有什麼看法?請在留言處留言告訴我!

有用的連結:


原文出處:https://dev.to/hmpljs/i-replaced-alpinejs-in-my-app-with-this-alternative-kgk


共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。

阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

63 個專案實戰,寫出作品集,讓面試官眼前一亮!

立即開始免費試讀!