- vừa được xem lúc

Series Web app không dùng framework: Bài 1 Pure JS client-side rendering

0 0 13

Người đăng: Cao Nguyen Huy Hoang

Theo Viblo Asia

Nội dung

  1. Tại sao không dùng framework
  2. Rendering
  3. Rendering with component

Tại sao không dùng framework?

TLDR:

  • Không dùng framework để hiểu công dụng của framework
  • Hiểu rõ trade-offs trong quyết định sử dụng framework
  • Tối ưu hoá nợ kỹ thuật (technical debt

Frameworks là những công cụ cực kỳ cần thiết trong bất kỳ lĩnh vực nào không riêng frontend nói riêng và phát triển phần mềm nói chung.

Tuy nhiên, thông thường khi sử dụng một framework thì trước tiên ta cần phải hiểu rõ framework được tạo ra để giải quyết vấn đề gì thì những nguyên lý được sử dụng trong framework mới thật sự có ý nghĩa.

Nếu hiểu rõ vấn đề chính mà mọi framework muốn giải quyết, bạn sẽ có nền tảng để đánh giá những lợi ích và hạn chế mà từng framework mang lại.

Trong series này, mình sẽ đi qua một trường hợp điển hình trong phát triển ứng dụng web frontend để có thể làm rõ những vấn đề chính mà các framework như React, Angular, Svelte giải quyết.

Rendering

Trước tiên, ta sẽ bắt đầu với một trường hợp ứng dụng cụ thể và phát triển những chức năng thường thấy trong framework.

Trong bài viết này mình sẽ sử dụng trường hợp một ứng dụng ghi chú todo. Cấu trúc thư mục và html như sau:

Chức năng đầu tiên mà mọi ứng dụng GUI (graphic user interface) làm là rendering. Rendering là một function nhận state và trả về view. State là dữ liêu của các component trong ứng dụng (vd: todos, filter)

View = Render(state)

Mọi ứng dụng web được render bởi trình duyệt web. Dữ liệu trình duyệt dùng để thể hiện nội dung là HTML, được represent bằng DOM. Để thay đổi nội dung của front end, ta thay đổi nội dung của HTML và giao tiếp với rendering interface của browser.

Tiếp đến là ta sẽ xây dựng chức năng render trong file render.js

Component đơn giản nhất trong ứng dụng của chúng ta là todo, cấu trúc của todo có thể như sau:

Component todo sẽ tiêu thụ state và trả về một html để gán vào index.html

Component tiếp theo là count của todo:

Cuối cùng, function render sẽ copy DOM hiện tại từ root node của ứng dụng (sau đây gọi là DOM ảo), update những giá trị mới trong state vào DOM ảo và trả về DOM ảo.

Sau đó render của ta sẽ có nhiệm vụ giao tiếp thay đổi trong state với API render của browser.

Controller sẽ thay nhận state mới, pass state cho render, và cuối cùng yêu cầu trình duyệt update DOM cũ theo những thay đổi trong DOM ảo. Đây là nội dung của file index.js:

requestAnimationFrame gọi callback render và dùng replaceWith để thay đổi nội dung html, tất cả quá trình này sẽ xảy ra trước bước repaint tiếp theo trong các bước render của browser.

Cuối cùng đây là todo app của chúng ta với render đã được implement:

Render với components

Hiện tại, chức năng render của ứng dụng của chúng ta đã hoàn thành. Tuy nhiên, chức năng render còn nhiều hạn chế:

  • Tight coupling giữa logic sử lý dữ liệu trong mỗi thành phần của giao diện và logic của component
  • Khó quản lý các thành phần giao diện vì mọi thứ được xử lý chung trong cùng một function

Để có trải nghiệm tốt hơn, ta cần phải tìm giải pháp giúp sử dụng các component một cách declarative.

Ta cần tách biệt logic của render với quá trình import và sử dụng các component.

Để làm được điều đó ta có thể abstract chức năng của render đang bị coupled với component.

Các chức năng hiện tại của render gồm:

  • Xác định DOM của các component khác nhau trong giao diện
  • Pass state mới của giao diện vào function tạo DOM ảo của từng component

Để tách bạch chức năng trên, ta có thể sử dụng một class component để các component sau inherit chức đăng xác định DOM.

Tuy nhiên, ta có thể đi theo cách sử dụng pure functions của React.

Vì mô hình hiện tại của chúng ta thì view = render(state), ta có thể tiếp tục sử dụng function này cho các component vì các component cũng chỉ là một "immediate step" trong quá trình traversal DOM tree của render.

Để giữ các component là pure functions, ta mở rộng chức năng mỗi component với một higher order function khác là componentWrapper.

Function componentWrapper sẽ có các chức năng ta cần decouple khỏi component:

Component binding

Ta sẽ abstract chức năng đầu tiên. Ta tạo function bind các component khác nhau với các DOM của nó:

Để componentWrapper có thể nhận diện được component nào bind với DOM node nào thì ta cần key value như dictionary để có thể liên kết chúng với nhau.

Ta có thể dùng class hoặc id của DOM node làm key nhưng điều này có thể gây ra nhập nhằng khi ta bắt đầu phải làm việc với các bước sau như layout.

Với HTML ta có thể dùng data attributes để định dạng attribute riêng cho components.

Giờ ta có thể sử dụng .dataset.component để xác định tên component trong html.

Tiếp đến ta sẽ tách các component function thành những file riêng:

todos.js

count.js

filter.js

*Lưu ý là mỗi component function đều trả về lại một DOM node ảo đã được clone với state mới

Sau đó ta sẽ liên kết từng component với data attribute trong html trong file index.js

Trong file render.js ta tạo một renderer object và function add để gọi wrap với các component function

Cuối cùng file render.js sẽ như sau

Hiện tại ta đã bind logic của từng component. Ta có thể declare component mà không cần phải tìm DOM node.

Passing state

Tiếp theo ta phải tạo virtual DOM từ root và tạo logic phân tán state từ root cho các component con.

Ta thêm function renderRoot

rootComponent chỉ có nhiệm vụ clone root và pass state cho các component con. Lưu ý rằng từ lúc này bất kỳ operation nào sau đó được thực hiện ở root node đã được clone (virtual DOM)

Sau đó, ta chỉ cần sửa lại componentWrapper để nó gọi lại componentWrapper với các childComponents trong component đã được wrap.

boundedComponent sẽ tìm các DOM node có data-component, gọi component function cùng tên, và thay thế child node trong virtual DOM.

Có những thuật toán khác để viết function này hiệu năng hơn (ví dụ như của React), nhưng nội dung đó nằm ngoài phạm vi của bài viết hôm nay. Mình sẽ bàn về vấn đề này trong những bài sau.

Cuối cùng file render.js đã hoàn thành

Cuối cùng ta sẽ thay thế virtual DOM với DOM cũ trong index.js và fake dữ liệu dynamic

Giờ ta có thể tạo một ứng dụng front-end cơ bản một cách declaratively, và đây là ứng dụng hoàn chỉnh

Tổng kết

Nếu bạn đã từng sử dụng React hoặc các framework declarative, các bạn có thể thấy sự tương đồng trong cách viết và sử dụng các component, virtual DOM, và cách state được pass.

Trong phần tiếp theo mình sẽ tiếp tục bàn về diffing engine, event handing, routing và implement các chức năng này dùng Javascript để ứng dụng front-end của chúng ta trở nên reactive.

Mình viết để bồi dưỡng kiến thức nên nếu có chỗ nào sai hoặc có thể cải thiện mong mọi người thông cảm và giúp mình sửa sai do kiến thức mình chưa tốt.

Cảm ơn các bạn đã đọc bài viết rất dài và khá phức tạp. !

Tham khảo: https://github.com/Apress/frameworkless-front-end-development

Bình luận

Bài viết tương tự

- vừa được xem lúc

Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 30)

. Hello xin chào mọi người, mình đã trở lại và tiếp tục với phần 30 của series về Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết. Bắt đầu thôi nào.

0 0 45

- vừa được xem lúc

5 câu hỏi phỏng vấn Frontend giúp bạn tự tin hơn khi sử dụng bất đồng bộ trong Javascript

Một trong những điều khó khăn khi học Javascript là promises. Chúng không dễ hiểu và có thể cần một vài hướng dẫn và một thời gian kha khá để vận dụng chúng.

0 0 92

- vừa được xem lúc

Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 31)

Hello xin chào mọi người, mình đã trở lại và tiếp tục với phần 31 của series về Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết. Bắt đầu thôi nào.

0 0 44

- vừa được xem lúc

Những lý do khiến mình thích CSS custom properties hơn SASS variables?

Halo các bạn,. Lại là mình với một bài post liên quan tới chủ đề Front-end đây Mình còn nhớ hồi mình bắt đầu tìm hiểu và bị SASS lôi cuốn, mình đã nghĩ rằng mình sẽ chẳng bao giờ cần dùng đụng tới CSS

0 0 86

- vừa được xem lúc

Usability là gì? Những lưu ý khi thiết kế Usability

Usability là một yếu tố quan trọng trong sự thành bại của sản phẩm. Thật đáng tiếc khi sản phẩm làm ra ưu việt về tính năng, nhưng lại không được người dùng tiếp nhận, đơn giản chỉ vì khó sử dụng.

0 0 36

- vừa được xem lúc

7 Repos cho Front-End mà chính bạn còn không biết là bạn cần nó

. Những repos chẳng mấy khi được nhắc đến nhưng lại giúp bạn build mọi thứ nhanh hơn và tốt hơn nhiều. Chúng ta đang sống trong một thời đại có sẵn các công cụ và tài nguyên hoàn hảo, chúng chỉ cách t

0 0 37