2 điểm bởi GN⁺ 2025-11-04 | 1 bình luận | Chia sẻ qua WhatsApp
  • htmx 4.0 là một bản tái xây dựng quy mô lớn, thay thế toàn bộ kiến trúc dựa trên XMLHttpRequest hiện có bằng kiến trúc bất đồng bộ lấy fetch() làm trung tâm
  • Cơ chế kế thừa thuộc tính được đổi từ ngầm định sang khai báo tường minh bằng :inherited, giúp cải thiện độ rõ ràng của mã và khả năng bảo trì
  • Bộ nhớ đệm lịch sử được đơn giản hóa từ lưu snapshot cục bộ sang cơ chế khôi phục dựa trên yêu cầu mạng, tăng độ ổn định
  • Nhiều tính năng mới như streaming response, SSE, DOM morphing, thẻ <partial>, hàng đợi View Transition được tích hợp vào core
  • Về dài hạn, dự án hướng tới đơn giản hóa codebase và cải thiện khả năng mở rộng, đồng thời vẫn tiếp tục hỗ trợ người dùng 2.0

Tổng quan về htmx 4.0

  • htmx 4.0 được viết lại toàn diện, phản ánh kinh nghiệm phát triển fixi.jsbài học bảo trì trong 5 năm
  • Các thay đổi chính có thể tóm gọn thành 3 điểm cốt lõi: chuyển sang fetch(), minh bạch hóa kế thừa thuộc tính, và đơn giản hóa bộ nhớ đệm lịch sử

The fetch()ening

  • Thay XMLHttpRequest bằng fetch() để hiện đại hóa hạ tầng Ajax
    • Với hầu hết trường hợp sử dụng, tác động không lớn, nhưng mô hình sự kiện sẽ thay đổi theo đặc tính bất đồng bộ của fetch()
  • Việc chuyển đổi này tạo nền tảng cho việc đơn giản hóa mã và mở rộng tính năng trong tương lai

Kế thừa thuộc tính tường minh

  • Thay cho kế thừa ngầm định trước đây, nay dùng bổ nghĩa :inherited để khai báo rõ ràng
    • Ví dụ:
      <div hx-target:inherited="#output">
          <button hx-post="/up">Like</button>
          <button hx-post="/down">Dislike</button>
      </div>
      
    • Nếu không khai báo hx-target, các phần tử con sẽ không kế thừa
  • Đây là thay đổi nâng cấp lớn nhất với đa số người dùng

Đơn giản hóa bộ nhớ đệm lịch sử

  • Bộ nhớ đệm snapshot DOM cục bộ của htmx 2.0 kém ổn định do chỉnh sửa từ bên thứ ba, trạng thái ẩn, v.v.
  • Trong 4.0, cơ chế này được đổi sang khôi phục thông qua yêu cầu mạng
    • Mở rộng cache được cung cấp dưới dạng tùy chọn (opt-in)
  • Giúp đơn giản hóa codebase và nâng cao độ tin cậy của hành vi mặc định

Những gì được giữ nguyên

  • Các API cốt lõi như hx-get, hx-post, hx-target, hx-boost, hx-swap, hx-trigger vẫn giữ nguyên
  • Ngoài việc thêm :inherited, phần lớn dự án có thể tiếp tục chạy với mã hiện có
  • Tăng cường khả năng bảo trì dài hạn và độ ổn định

Chính sách nâng cấp

  • Người dùng 2.0 sẽ cần một dự án nâng cấp, nhưng 2.0 vẫn sẽ được hỗ trợ vĩnh viễn
  • 4.0 sẽ được phát hành song song với 2.x, và việc chuyển latest dự kiến vào đầu năm 2027
  • Dự kiến cung cấp extension để khôi phục hành vi của 2.0

Tóm tắt tính năng mới

Tích hợp streaming response và SSE

  • Tận dụng hỗ trợ Readable Streams của fetch() để cho phép thay thế DOM từng phần
  • SSE (Server Sent Events) được tích hợp lại thành tính năng cốt lõi, hỗ trợ cập nhật nội dung theo tiến trình

Morphing Swap

  • Dựa trên thuật toán Idiomorph, cải thiện việc quyết định giữ hay xóa node khi hợp nhất DOM
  • Các kiểu swap morphInner, morphOuter được đưa vào core

Hỗ trợ thẻ <partial>

  • Đơn giản hóa cú pháp phức tạp của Out-of-band swap hiện có
  • <partial> là một phần tử template, có thể dùng các thuộc tính chuẩn như hx-target, hx-swap
  • Out-of-band swap quay về dạng thay thế đơn giản dựa trên id

Cải thiện View Transition

  • Thêm hàng đợi chuyển tiếp (queue) để tránh xung đột hiển thị
  • Chuyển tiếp CSS giữ nguyên cách làm cũ, còn runtime bất đồng bộ được đơn giản hóa
  • Việc bật mặc định hay không vẫn chưa được quyết định

Ổn định thứ tự sự kiện

  • Cấu trúc bất đồng bộ dựa trên fetch() giúp dễ đảm bảo thứ tự sự kiện hơn
  • Quy ước đặt tên sự kiện mới:
    htmx:<phase>:<system>[:<optional-sub-action>]
    • Ví dụ: htmx:before:request

Tăng cường khả năng mở rộng

  • Cung cấp extension preloadoptimistic update dựa trên async
  • Mở chu kỳ yêu cầu/phản hồi/swap cho nhà phát triển extension, đồng thời có thể thay thế triển khai fetch()
  • Có thể hiện thực hành vi mong muốn mà không cần đến hack

Cải thiện hx-on

  • Áp dụng cú pháp chuẩn hóa hx-on:<event name>
  • Hỗ trợ API bất đồng bộ để script DOM đơn giản
    <button hx-post="/like"
            hx-on:htmx:after:swap="await timeout('3s'); ctx.newContent[0].remove()">
        Get A Response Then Remove It 3 Seconds Later
    </button>
    
  • Vẫn hoạt động trong môi trường tắt eval(), dù một số tính năng sẽ bị giới hạn

Định hướng tổng thể

  • htmx 4.0 hướng tới giảm lỗi và cải thiện tính năng trong khi vẫn giữ cảm giác sử dụng tương tự 2.0
  • Đơn giản hóa mã, cấu trúc tường minh và khả năng mở rộng dựa trên bất đồng bộ giúp mang lại một htmx ổn định và hiện đại hơn

Lịch phát triển

  • Bản alpha (htmx@4.0.0-alpha1) đã được công bố
  • Bản phát hành chính thức 4.0.0 dự kiến vào đầu đến giữa năm 2026
  • Dự kiến chuyển sang latest vào đầu năm 2027
  • Có thể theo dõi tiến độ phát triển trên nhánh GitHub fourfour.htmx.org

1 bình luận

 
GN⁺ 2025-11-04
Ý kiến trên Hacker News
  • Cuối cùng họ đã đổi ý và quyết định phát hành một major version mới của htmx
    Tuy nhiên, để giữ lời hứa rằng “sẽ không có 3.0”, phiên bản tiếp theo sẽ được đặt tên là htmx 4.0
    Họ đùa rằng xét về mặt kỹ thuật thì cách gọi này vẫn đúng

    • Đây là một cách giải quyết vui, nhưng có thể cũng gây nhầm lẫn cho người dùng như trường hợp PHP 6 từng biến mất
      Có lẽ phát hành thẳng 3.0 một cách thành thật còn tốt hơn
    • Có người đùa rằng cứ lên luôn htmx 4.1 và tạo ra “xhtmx 1.0”
    • Có cảm giác giống Leisure Suit Larry 4: The Missing Floppies
    • Cũng may là họ không nói “sẽ không có phiên bản thứ 3”, nên vẫn còn chỗ để lách câu chữ
  • htmx 2.0 sẽ được hỗ trợ vĩnh viễn, nên hoàn toàn không có áp lực phải nâng cấp
    Trong thời đại mà API thay đổi liên tục như hiện nay, cách tiếp cận này rất đáng khen

  • Có cảm giác những người theo đuổi sự ổn định thường rút ra bài học sai
    Thay vì dồn mọi thay đổi lớn vào một lần như Python 3.0, họ cho rằng chiến lược phát hành dần dần sẽ tốt hơn
    Ví dụ, đưa thay đổi vào theo các mốc như 2.1, 4.0, 5.0 sẽ giúp việc quản lý dễ hơn nhiều
    Họ khuyến nghị cách làm như Django, tức là duy trì các giai đoạn tương thích qua nhiều phiên bản

  • Mô tả của thuộc tính hx-target bị cho là hơi khó hiểu
    So với “inherited”, thì “inheritable” hoặc “inherit” có vẻ tự nhiên hơn

    • Có người nói họ đã hiểu theo nghĩa “được con thừa hưởng”, và gợi ý rằng cách diễn đạt như “pass-down” có thể rõ ràng hơn
    • Có ý kiến cho rằng “inherited” là từ không đúng, còn “inherit” thì ngắn gọn và hay hơn
      Đùa thêm rằng cũng có thể dùng “bequeath”
    • Họ nói đang cân nhắc nhiều cách diễn đạt và sẵn sàng tiếp thu ý kiến
    • Một số phương án khác như “heritable” hoặc “cascade” cũng được đưa ra
  • Người bình luận cho rằng ý tưởng của HTMX và triết lý Hypermedia rất tuyệt
    Họ đã rời môi trường SPA để chọn Datastar, và cảm thấy khả năng mở rộng nhận lại được lớn hơn nhiều so với công sức học bỏ ra
    Họ đẩy signal trực tiếp từ server sang trình duyệt, loại bỏ mã polling, và độ phức tạp giảm đi đáng kể
    Việc bỏ phụ thuộc vào Alpine.js cũng giúp mã đơn giản hơn, và cập nhật toàn bộ view theo kiểu streaming hoạt động hiệu quả nhờ nén
    Nếu đi lên từ SPA, họ khuyên nên thử cả Datastar lẫn HTMX

  • Việc chuyển sang fetch() để tận dụng Readable Stream là một điểm thú vị
    Dù đã dùng HTMX rất nhiều, họ vẫn thích streaming dựa trên SSE của Datastar hơn nên dạo này nghiêng về bên đó

  • Dù vui khi thấy HTMX tiếp tục phát triển, có người vẫn cảm thấy Datastar cung cấp API thân thiện với chuẩn hơn và linh hoạt hơn
    Trong một gói nhỏ có cả Fetch, SSE, declarative signals, DOM morphing và nhiều tính năng khác
    Vì thế họ đặt câu hỏi: “Vậy tại sao phải dùng HTMX?”

    • Có ý kiến chỉ ra rằng Datastar Pro không phải mã nguồn mở, nên có rủi ro về độ tin cậy
    • Họ nhắc đến sự mỉa mai khi tác giả Datastar trước đây từng muốn đưa các tính năng kiểu này vào HTMX
    • Có người giải thích rằng điểm mạnh của HTMX là giao diện đơn giản, tối ưu cho mô hình request/response
      Datastar thì xoay quanh event stream nên phù hợp với dashboard thời gian thực hoặc game, nhưng với phần lớn web app, sự đơn giản của HTMX có lợi hơn
      Tham khảo: Datastar essay, Less HTMX is More
    • HTMX hỗ trợ quản lý lịch sử URL trong trình duyệt khá dễ dàng, còn Datastar thì giới hạn tính năng này ở bản trả phí (Pro)
  • Có người châm biếm việc từng nói “quá hoàn hảo nên sẽ không còn major version nào nữa”, nhưng cuối cùng lại phải thừa nhận sự cần thiết của tiến hóa
    Họ trích đoạn “giờ chúng tôi sẽ thay đổi chuẩn đặt tên event” để mỉa mai nỗ lực né JavaScript

    • Họ mỉa mai rằng “cuối cùng vì không muốn dùng JavaScript nên lại phải dùng JS để diễn giải cú pháp tùy biến
      Dù vậy, họ vẫn thừa nhận rằng việc thể hiện ý đồ bằng HTML là một điểm hay
    • Có người đùa rằng “lần này mới là phiên bản cuối cùng thật sự”
    • Có người đón nhận tích cực hơn: “dù sao vẫn tốt hơn là tự viết JavaScript trực tiếp”
    • Cũng có ý kiến cho rằng giọng điệu chỉ trích như vậy là không cần thiết, vì “đổi ý thì có gì sai?”
  • Có người nói bài viết rất rõ ràng và giúp học được nhiều về triết lý thiết kế API

  • Có người đã tạo xhr-fetch-proxy để dùng fetch cùng với HTMX, và cho rằng
    thay đổi lần này sẽ mở ra thêm nhiều khả năng hơn
    Liên kết dự án

    • Trong 4.0, chu trình request được mở hoàn toàn, nên có thể thay thế implementation của fetch cho từng request
      Họ nói thêm rằng ý tưởng này học được từ fixi.js