2 điểm bởi GN⁺ 2023-11-14 | 1 bình luận | Chia sẻ qua WhatsApp
  • Web Components trông giống như phiên bản trên trình duyệt của React components, nhưng thực tế gần với mô hình lấy HTML sẵn có làm trung tâm rồi bổ sung chức năng hơn
  • Khác biệt cốt lõi nằm ở khả năng render trước khi JavaScript chạy: thay vì truyền dữ liệu vào một custom element rỗng, cách tự nhiên hơn là bọc HTML có ý nghĩa bằng custom element
  • HTML web component mở rộng markup hiện có, còn phần tử rỗng giao toàn bộ nội dung và chức năng cho JavaScript thì gần với JavaScript web component hơn
  • Nếu kiểu component hóa của React quen với việc thay thế (replacement), thì web components đòi hỏi tư duy tăng cường (augmentation): giữ nguyên nội dung rồi thêm chức năng
  • Trên nền tảng web, giống như các dòng chảy liên quan đến HTML5, fetch, và TypeScript, những ý tưởng tốt thường có xu hướng sống lâu bằng cách bổ sung, tăng cường công nghệ hiện có thay vì đẩy lùi nó

Web Components và React components có bản chất khác nhau

  • Cái tên “Web components” có thể khiến người ta nghĩ đây là đối ứng trên nền tảng web của React components
    • JSX của React dùng dạng <MyComponent>, còn web components có thể dùng dạng <my-component>
    • Nhưng nếu tạo web components theo cách tạo React components thì rất dễ thất vọng
  • Hai công nghệ này khác nhau ở các ưu tiên thiết kế và cách sử dụng
    • Nếu cố dùng cái này như cái kia, bạn sẽ va chạm với hướng đi tự nhiên của từng công nghệ

HTML web components phù hợp với tăng cường hơn là thay thế

  • Một React component điển hình có thể nhận dữ liệu qua props trên một component rỗng, rồi JavaScript render toàn bộ nội dung
<UserAvatar
  src="https://example.com/path/to/img.jpg";
  alt="..."
/>
  • Nhìn bề ngoài thì web components cũng có thể được viết theo cách tương tự
<user-avatar
  src="https://example.com/path/to/img.jpg";
  alt="..."
></user-avatar>
  • Nhưng sức mạnh riêng của web components là có thể render trước JavaScript
    • React components không thể hoạt động theo cách này
  • Vì vậy, thay vì “shell component” rỗng, cách phù hợp hơn là cấu thành nội dung cốt lõi bằng HTML rồi bọc nó bằng custom element để thêm chức năng
<user-avatar>
  <img src="https://example.com/path/to/img.jpg"; alt="..." />
</user-avatar>
  • Cách phân biệt “HTML web components” của Jeremy tập trung vào việc custom element có mở rộng markup hiện có hay không
    • Nếu custom element rỗng thì đó không phải HTML web component
    • Nếu nó bọc và mở rộng markup hiện có thì nó gần với HTML web component hơn
  • “JavaScript web component” là kiểu mà nội dung và chức năng của phần tử rỗng phụ thuộc hoàn toàn vào JavaScript
<user-avatar
  src="https://example.com/path/to/img.jpg";
  alt="..."
></user-avatar>
  • Ở dạng này, nếu không có JavaScript thì nó không có ý nghĩa gì với người dùng cuối
  • Ngược lại, HTML web components vẫn giữ lại ý nghĩa và nội dung ngay cả khi không có JavaScript, và khi có JavaScript thì chức năng được tăng cường lên trên đó
<user-avatar>
  <img src="https://example.com/path/to/img.jpg"; alt="..." />
</user-avatar>

Trên web, cách tiếp cận tăng cường tồn tại lâu hơn

  • Lý do cách tiếp cận tăng cường phù hợp với web là vì bản chất của web khuyến khích cải tiến dần dần có khả năng phục hồi, và phù hợp để lặp lại thay đổi trên một đối tượng lớn như web
  • Những ý tưởng tốt từ các framework và thư viện xung quanh web, dù có được hấp thụ vào nền tảng đi nữa, cũng thường đi vào theo cách bổ sung công nghệ hiện có thay vì thay thế toàn bộ
    • XHTML từng cố thay thế HTML4, nhưng HTML5 thì cố bổ sung cho HTML4, và HTML5 đã thắng
    • Các thư viện networking từng cố thay thế XMLHttpRequest, và những ý tưởng hay cuối cùng đã được chuyển vào chuẩn fetch
    • fetch hiện cũng tồn tại trong nhiều môi trường ngoài trình duyệt
    • Những ý tưởng hay từ Sass và jQuery cũng đã được chuyển vào trình duyệt
    • Những ý tưởng hay từ TypeScript cũng đang đi vào trình duyệt theo cách bổ sung chứ không thay thế công nghệ hiện có
  • Web components cũng có thể được xem là một dòng chảy đưa mô hình component của React vào trình duyệt, nhưng nó gần với việc bổ sung hơn là thay thế cách web vốn đang hoạt động
  • Nếu muốn một cách tiếp cận công nghệ bền lâu, thì chọn tăng cường và cải tiến thay vì thay thế sẽ phù hợp hơn với hướng đi của web

1 bình luận

 
GN⁺ 2023-11-14
Ý kiến trên Hacker News
  • Tôi đã kỳ vọng bài viết này giải thích user-avatar thực sự làm gì hoặc cung cấp gì, nhưng cuối cùng lại không thấy
    Nếu nó chỉ chứa style đơn thuần thì không hiểu vì sao không dùng CSS class là được, và việc để user-avatar nhận thuộc tính src trông tự nhiên hơn nhiều so với bắt nó lần nào cũng phải chứa thẻ img bên trong
    Vue/React/Angular không hẳn là đang cố “thay thế” HTML, mà giống như xây chồng lên trên HTML/CSS/JS hơn; nếu chúng render mọi thứ bằng canvas thì lập luận đó có lẽ sẽ thuyết phục hơn
    Khi Web Components được công bố lần đầu, tôi đã kỳ vọng, nhưng chức năng tích hợp sẵn quá thiếu, và cảm giác nó thực sự giúp xây web app như framework thì khá yếu
    Các lựa chọn thay thế cho những framework lớn, đặc biệt là những thứ như htmlx, trông như chỉ thêm một chút cú pháp tiện lợi lên dòng họ jQuery, nên với việc xây dựng web app thì cảm giác như một bước lùi lớn

    • Tôi đồng ý rằng “các lựa chọn thay thế cho framework lớn giống cú pháp tiện lợi của jQuery”, nhưng vẫn chưa rõ vì sao điều đó lại là lựa chọn hoàn toàn sai để xây dựng web app
      Nếu ‘web app’ nghĩa là thứ như Google Sheets thì tôi đồng ý, nhưng làn sóng phản React này dường như đang phê phán thói quen mặc định cứ cài framework rồi xây từ đầu hơn là những trường hợp như vậy
      Trên thực tế có rất nhiều website chỉ cần “một chút tương tác phủ lên trên”
    • Tôi nghĩ bài của Eric Meyer thể hiện ý đồ rõ hơn nhiều: https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the...
      Lợi ích cốt lõi là progressive enhancement: vì thẻ img có hành vi mặc định, có thể dựa vào render mặc định và chỉ “gia cố” bằng web component ở những phần cần thiết
    • Vì thiếu ví dụ cụ thể, bài này hơi có cảm giác như ý nghĩ nảy ra lúc đang tắm
    • Ví dụ thể hiện ý chính của bài cụ thể hơn thì bên này tốt hơn: https://www.zachleat.com/web/details-utils
      Component details-utils gia cố hành vi của component HTML tích hợp sẵn detail
      Nếu vì lý do nào đó JavaScript bị tắt thì component detail vẫn hoạt động như vốn có, còn khi JavaScript bật hoặc tải xong, nó sẽ có thêm các hành vi nâng cao như tự thu gọn khi bấm ra bên ngoài
      Phần có thể tái sử dụng trong cách làm này chính là kiểu gia cố hành vi đó
      Nhìn web component này của người tạo 11ty thì tôi hiểu được ý chính của bài, và cảm giác khi lần đầu thấy Web Components rằng “rốt cuộc vẫn cần JavaScript, không có thì đâu hoạt động” cũng là điểm được nêu trong bài của Rich Harris: https://dev.to/richharris/why-i-don-t-use-web-components-2ci...
    • Không biết bạn đã dùng htmx chưa, nhưng nó xử lý một vấn đề khác với trải nghiệm người dùng JavaScript phía client mà jQuery từng giải quyết, nên phê bình đó có vẻ lệch hướng
      htmx chủ yếu là cách mở rộng mô hình HTML render phía server từ làm mới toàn trang sang cập nhật một phần trang, đồng thời tránh phải viết JavaScript
  • Nếu muốn xem thêm về ý tưởng “HTML Web Components”, những bài này cũng đáng đọc
    https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the... - “Vậy là xong: vài nghìn từ về hành trình của tôi trong việc đi đến hiểu và làm việc với những web component hoàn toàn dùng Light DOM này, còn được gọi là custom elements. Giờ chúng chỉ cần một cái tên thật bắt tai, để chúng ta có thể kéo thêm nhiều người về Light Side của Web.”
    https://adactio.com/journal/20618 đề xuất một cái tên khá hợp lý

    • Tôi không hiểu trọng tâm là gì
      Vì viết khá phiền nên cuối cùng lại cần một framework nhẹ nằm trên một framework tích hợp kiểu Lit, mà Lit còn lớn hơn cả Preact
      Hơn nữa, nó không giải quyết các vấn đề thực tế như quản lý trạng thái, routing, nên nhiều khả năng còn phải kéo thêm thứ khác vào
      Có thể có được component tái sử dụng, nhưng nghĩ đến chuyện ở nơi đang dùng React lại mang một web component bên trong dùng Vue vào dùng thì nghe không hợp lý lắm
    • Tôi thật sự vui khi có xu hướng thúc đẩy web component không dùng Shadow DOM
      Vẻ đẹp và sự tao nhã của web đến từ cấu trúc khai báo, và nhờ đó mới có khả năng quan sát cũng như chỉnh sửa
      Shadow DOM với tôi giống một mong muốn mang tính doanh nghiệp nhằm dựng lên rào cản đóng gói cao hơn và sự chắc chắn hơn, chứ cá nhân tôi không chia sẻ mục tiêu đó
      Bài viết này cho thấy cách công việc với Light DOM có thể được hợp thành
      Tôi luôn nghĩ web component hay custom element phải có thể tự sửa DOM bên trong, di chuyển các phần tử con và tạo nội dung mới
      Ví dụ, trang hoặc framework có thể chèn biểu tượng, còn phần tử avatar người dùng có thể chèn tên hoặc các yếu tố trang trí
      Tuy nhiên, một điều tôi lo ở Light DOM/HTML Web Components là Shadow DOM có một số lợi thế về hiệu năng
      Với tư cách lập trình viên, tôi có thể hình dung việc giảm số phần tử mà bộ chọn CSS phải duyệt qua, và tôi cũng mong lợi ích đó có thể được tận dụng bằng cách nào đó
      Tôi thật sự vui với cách tiếp cận nhìn custom element và Web Components nhẹ nhàng hơn này, và cảm ơn vì các liên kết
    • Có lẽ nên rút gọn cái tên hợp lý đó hơn nữa và gọi là HTML components
  • Cách diễn đạt “có thể render trước JavaScript. Component React thì tuyệt đối không thể làm vậy” khó có thể khẳng định chắc chắn; nếu là render phía máy chủ thì vẫn có thể được render trước JavaScript phía client
    Tôi thấy ví dụ quá đơn giản để thể hiện lập luận của tác giả
    Một web component xử lý thay đổi trạng thái sẽ là đối tượng so sánh tốt hơn, và lập luận có lẽ cũng sẽ thuyết phục hơn

    • Nhận xét hay, và ngược lại cũng có thể xem là web component không thể làm vậy vì chúng phải được đăng ký bằng JavaScript trước khi trang được tải
      Có các giải pháp hydration, nhưng thường tệ hơn, có những đánh đổi bất ngờ và nhiều khi làm tổn hại khả năng kết hợp
    • Vấn đề lớn nhất của Web Components là không thân thiện với render phía máy chủ
    • Tôi không rõ “HTML Web Component” sẽ xử lý thay đổi trạng thái như thế nào
      Chỉ nhìn ví dụ bọc thẻ img thì lợi ích chưa thật sự rõ; có thể nhóm và tái sử dụng các phần tử chung, nhưng để có tương tác thì vẫn cần JavaScript
      Văn bản thay thế của ảnh trong ví dụ ngày nay cũng thường là động vì lý do bản địa hóa, nên nếu không có JavaScript thì nội dung có thể bị thiếu
  • Có vẻ cuối cùng tôi cũng bắt đầu nắm được Web Components: https://github.com/kennyfrc/cami.js
    “No Build Steps, No Client-Side Router, No JSX, No Shadow DOM. We want you to build an MPA, with mainly HTML/CSS, and return HTML responses instead of JSON. Then add interactivity as needed.”
    “Declarative templates with lit-html. Supports event handling, attribute binding, composability, caching, and expressions.”

    • Vẻ đẹp của Web Components nằm ở chỗ bạn có thể tìm hoặc tạo một lớp nền tảng hoạt động theo cách mình cần
      Cá nhân tôi thích kiểu class theo phong cách component class của React, có state machine tích hợp lấy cảm hứng từ XState
      https://github.com/codewithkyle/supercomponent/blob/master/s...
    • Tôi tò mò không biết bạn đã từng dùng HTMX chưa
      Hướng đi trông khá giống nhau, và phía HTMX có thể có cộng đồng lớn hơn
      Nếu đã dùng rồi, tôi muốn biết nó còn thiếu điểm nào
    • Về cơ bản là thay JSX bằng một DSL tùy chỉnh không chuẩn, rồi gọi đó là chiến thắng
  • “web components” không phải là một thứ duy nhất, và cũng không phải là tạo ra “a web component”
    “Web Components” là tên của Web Components API, gồm ba thứ được gộp lại
    Thứ bạn thực sự tạo ra là phần tử tùy chỉnh; trong đó bạn có thể dùng Shadow DOM hoặc dùng template HTML
    Quan trọng nhất trong ba thứ là phần tử tùy chỉnh
    Khái niệm cốt lõi là “tạo thêm phần tử HTML”, nên việc hỗ trợ thuộc tính nào và API JavaScript nào hoàn toàn do bạn quyết định
    Cách đưa lên trang, tương tác và lắng nghe sự kiện cũng giống hệt các phần tử HTML khác
    Nếu bạn biết viết trang web theo “kiểu cũ”, thì bạn đã biết cách dùng phần tử tùy chỉnh rồi, chỉ cần học cách khai báo chúng

  • Gần đây tôi bắt đầu thử Web Components không cần môi trường build
    Không có npm, bun, webpack hay thứ tương tự, cũng không có dependency, và tôi viết bằng TypeScript
    IntelliJ tự động biên dịch sang JavaScript, còn phần xem trên trình duyệt thì chèn một handler phát hiện thay đổi nhỏ để cập nhật theo thời gian thực trong lúc phát triển
    Đến giờ vẫn chưa gặp vấn đề gì
    Thứ đang kìm chân Web Components có vẻ là HTML Modules
    Sẽ tốt hơn nếu có thể liên kết tới file .html thay vì file .js để import web component, nhưng hiện tại nếu muốn dùng template hoặc thứ gì phức tạp hơn một chút thì phải chèn kiểu xấu xí như .innerHtml = \...``
    Tôi đã nghĩ đó sẽ là vấn đề, nhưng IDE parse chuỗi template khá tốt

    • HTML Modules đã bị loại bỏ và thay thế bằng import chỉ dành cho JavaScript
      Và đó cũng không phải là lý do duy nhất cản trở Web Components
  • Tôi không thật sự thấy thuyết phục với lập luận rằng “React là thay thế chứ không phải bổ trợ”
    Rốt cuộc React cũng render các phần tử HTML và gắn các trình xử lý sự kiện JavaScript
    Việc bọc img bằng một component React không lấy mất chức năng của img; nó chỉ thêm lên trên, tức là bổ trợ
    Tác giả có thể đã làm việc với những codebase React khác, nhưng theo kinh nghiệm của tôi, nếu không có lý do gì thì chúng tôi dùng nguyên tính năng tích hợp sẵn của trình duyệt
    Cũng có thể là tôi đã gặp may

    • Việc bất kỳ kiến trúc web nào cuối cùng cũng render các phần tử HTML là điều hiển nhiên, và đó không phải trọng tâm
      Trọng tâm là cách tiếp cận “HTML Web Component”, khác với React, không phụ thuộc vào JavaScript để bắt đầu render
    • Tôi nghĩ khác biệt cốt lõi mà bài viết nói đến đại khái là thế này
      Theo tiêu chí render của trình duyệt, React là “tải trang → tải component”, còn Web Component gần với “tải trang → render cơ bản → tải component” hơn
      Người tắt JavaScript vẫn có thể thấy thứ gì đó với web component, nhưng với React thì có thể chẳng thấy gì; còn nếu có JavaScript thì có thể chuyển sang trạng thái render nâng cao hơn
    • Trong một số trường hợp, React cũng khiến việc tiếp cận tính năng tích hợp sẵn trở nên khó hơn
      Ví dụ, nếu gán onchange cho một phần tử, React sẽ đưa cho bạn thứ gần với sự kiện input hơn là sự kiện change
      Thực ra nó không hẳn là cả hai, mà là một sự kiện tổng hợp gần với input hơn change
      Nếu thật sự muốn change, bạn phải dùng tham chiếu tới phần tử và tự gắn handler trực tiếp bên trong effect
    • Còn tùy vào kiến trúc ứng dụng
      Nếu dùng React để trả về HTML từ server, thì bọc img bằng một component React đúng là bổ trợ cho phần tử sẵn có
      Nhưng nếu render toàn bộ ở phía client, thì img đó cuối cùng không thể tách rời khỏi component React
    • Khi đọc đoạn đó, tôi lại nghĩ đến hướng ngược lại: nhúng React vào trong HTML khác
      Theo kinh nghiệm, React rất tuyệt khi để nó đảm nhận toàn bộ cấu trúc trang từ trên xuống dưới, nhưng có thể trở nên khó khăn nếu cố nhét nó vào một cấu trúc có sẵn trong khi làm những việc như render phía server
  • Nếu đang tìm một cách làm bền lâu, thì kết luận nên chọn bổ trợ và nâng cấp thay vì thay thế cũng phù hợp với kinh nghiệm của tôi
    Nhờ triết lý này, các dự án web của tôi đã tồn tại lâu dài với mức bảo trì và phụ thuộc tối thiểu

  • Web component nên làm một việc duy nhất, còn framework JavaScript thì gần như là cả một hệ sinh thái
    Tôi đã tạo một web component trình phát video có thể nhận nhiều loại input, trong đó input phức tạp nhất là file torrent
    Có thể port sang Vue/React bằng StencilJS [0], nhưng không có cũng đã đủ dùng
    Chỉ cần đặt tag đó cùng với class được export từ awesomePlayer.js, bạn sẽ có một trình phát video HTML5 dạng sao chép-dán có thể phát torrent
    Tôi cũng rất khuyến nghị mô phỏng các phần tử HTML sẵn có nếu có thể
    Ví dụ, tôi dùng srcvideo cũng làm như vậy, nhờ đó phía sử dụng có thể tương tác mà không cần lục tài liệu
    [0] https://stenciljs.com/

  • Tôi khó đồng ý rằng component của các framework frontend hoàn toàn chỉ để thay thế và không thể composable
    Nhìn bề ngoài có thể như vậy, nhưng trong component của tôi, tôi dùng slot rất nhiều; việc triển khai cũng dễ và hoạt động tự nhiên
    Ngược lại, Web Components thường được demo theo kiểu chèn một đống code khổng lồ để tạo thứ gì đó như một editor
    Dùng slot trong Web Components rất đau đớn: phải gắn thủ công rất nhiều node, xử lý template như chuỗi, và nếu muốn làm việc hơi phức tạp thì còn phải lắng nghe cả sự kiện slotchange
    Về bản chất là đang dùng DOM API, mà nếu API đó không tệ đến vậy thì có lẽ chúng ta đã chẳng chuyển sang các framework frontend như React
    Tôi cũng không đồng ý với lập luận phụ rằng XHTML thất bại vì không bổ trợ cho HTML
    Theo tôi, nó thất bại vì ứng dụng phải hoàn toàn hợp lệ và việc kiểm chứng đó được giao cho client/trình duyệt
    Nếu dùng XHTML thật sự, chỉ một lỗi nhỏ trong markup cũng có thể làm hỏng trang; vì vậy dù mọi người đều kiểm chứng XHTML để chuẩn bị cho tương lai, sẽ chẳng công ty nào chấp nhận rủi ro khiến cả hoạt động kinh doanh đổ vỡ chỉ vì một thẻ p không được đóng đúng cách