Một số vấn đề thường gặp trong offline-plugin và hướng xử lý

Trong những bài trước (các bạn có thể xem thêm tại đâyđây) mình có giới thiệu về thư viện giúp app của chúng ta có thể dễ dàng chạy ở chế độ offline. Đó chính là offline-plugin. Đồng thời mình cũng đã xây dựng một app có tính năng thông báo cho người dùng khi có phiên bản mới của app bằng cách ứng dụng những tính năng của offline-plugin. Và sau khoảng thời gian làm việc với thư viện này thì mình có nhận ra được một số vấn đề. Trong bài tiếp theo này mình sẽ cùng chia sẻ nhưng vấn đề đó và những đối ứng cùng với mọi người. Bắt đầu thôi! (Lưu ý nhỏ: Những vấn đề mà mình sắp đề cập bên dưới một phần là mình nhận ra trong quá trình làm và một phần nữa là tham khảo thông qua những người bạn khác. Một chú ý nữa là trong quá trình làm việc với offline-plugin thì mình chủ yếu kết hợp sử dụng với những Single Page app và dùng webpack để bundle code).

I. Đi qua một chút về offline-plugin.

Như mình đã giới thiệu ở bài trước cũng khá chi tiết. offine-plugin là một thư viện dùng để xử lý vấn đề khi mà app của chúng ta đang ở chế độ offline. Offine cũng có nghĩa là mất kết nối với mạng internet dẫn đến tất cả những giao tiếp của app với web server đề bị lỗi. Các bạn cũng có thử (F12 => Network => Offline) và sẽ thấy kết quả. Nếu chúng ta để nguyên và không thao tác gì hay tải lại trang thì sẽ ổn thôi nhưng thực chất vấn đề giao tiếp với web server đang bị gián đoạn và các chức năng không hoạt động như mong muốn. Còn nếu cố tải lại trang thì chúng ta sẽ lại phải chơi với khủng long rồi 🐲.

offline-plugin sinh ra để giải quyết vấn đề này (nhưng cũng chỉ ở mức tương đối thôi). offline-plugin sẽ có dùng những tính năng của WebAPI Service Workers để giải quyết vấn đề này. Ý tưởng là Service Workers sẽ lưu 1 bản những asset cần thiết (đơn cử như file index.html chẳng hạn hoặc có thể là những file .css, .js, image, ...) trước đó đã được tải từ web server về để ứng dụng hoạt động. Nhưng mà sẽ chỉ là có những thứ đó thôi, việc ứng dụng mất kết nối với web server vẫn xảy ra, việc giao tiếp truyền tải dữ liệu, xử lý những bussiness đều vô hiệu. Nói tóm lại ở khi ứng dụng của chúng ta ở chế độ offline và mất kết nối với web server đồng nghĩa với việc ứng dụng của chúng ta là một ứng dụng chết (đến khi nào có kết nối mạng lại). Và offline-plugin hay Service Workers chỉ giúp ứng dụng của chúng ta tạm thời không làm người dùng mất những trải nghiệm của mình (cho đến khi có kết nối lại).

Một vấn đề khác nữa là offline-plugin sử dụng Service Workers để cache những asset cần thiết trong những lần reload lại trình duyệt. Vì thế mà phần nào đó sẽ làm ứng dụng của chúng ta tải nhanh hơn (những asset sẽ được lập trình để được tải từ bộ nhớ cache thay vì là phải yêu cầu tải một lần nữa từ web server), vì thế chúng ta không cần quan tâm nhiều về việc ứng dụng load quá lâu mà sẽ tập trung vào phần xử lý bussiness của app cũng như là giao tiếp giữa app và web server.

Bên trên mình có nói sơ qua về offline-plugin cũng như là luyên thuyên thêm tý về Service Workers và cách hoạt động cơ bản. Tiếp đến chúng ta sẽ qua những vấn đề gặp phải trong khi làm việc với offline-plugin cũng như một số vấn đề khác liên quan đến việc xử lý cache, offline, ...

II. Một số vấn đề gặp phải cũng như hướng xử lý.

1. App của chúng ta đã có thể xử lý offline nhưng lại bị cache trong thời gian dài?

Vấn đề này khá phổ biến khi chúng ta mới bắt đầu tiếp xúc với những xử lý cache asset ở trình duyệt hoặc là xử lý thêm phần offline cho ứng dụng của mình. Đơn giản là những request yêu cầu tải những asset từ trình duyệt gửi lên web server đều được Service Worker chặn lại và trả về những asset mà nó đã cache trước đó. Và phương pháp tạm thời là hard-refresh ứng dụng. Việc này sẽ đảm bảo những request assets của chúng ta sẽ bỏ qua cache và đi thẳng lên web server.

Khi ứng dụng của chúng ta sử dụng offline-plugin thì thư viện này sẽ dựa vào Service Workers để lập trình xứ lý cache những asset của ứng dụng. Vì thế để xử lý vấn đề này chúng ta cần lập trình lại Service Workers để app hoạt động như mong muốn.

Để xử lý vấn đề này thì chúng ta đơn giản chỉ cần tập trung vào phần xử lý của Service Workers. Service Workers khi khởi chạy thì sẽ cần được khởi tạo với một file cấu hình. Trong file đó sẽ có sẵn những thông tin về việc xử lý cache trong ứng dụng. File này có thể được đặt tên như serviceworker.js hoặc sw.js, nó sẽ được lưu trữ ở web server và được trình duyệt tải về trong lần tài đầu tiên. Thì mỗi lần chúng ta build app thì sẽ sinh ra những file mới và trong đó sẽ có một file cấu hình Service Worker được sinh ra. Thì ở phần web server chúng ta sẽ cấu hình để mỗi lần khi trình duyệt tải file cấu hình này thì đảm bảo sẽ được làm mới chứ không phải bị cache ở trình duyệt nữa (để xử lý việc này thì ở web server chúng ta sẽ phải thêm vào header của response một cặp key, value cache-control: no-store).

2. App đã có thể được làm mới nhưng chỉ khi load lại?

Với vấn đề số một thì chúng ta đã xử lý bằng cách lập trình cho web server của chúng ta có thể kiểm soát việc cache của file cấu hình Service Workers khi được trình duyệt tải về. Nhưng từ đó chúng ta lại gặp một vấn đề khác là chính là app của chúng ta mặc dù đã được cập nhập nhưng vẫn không thấy những tính năng mới và chỉ khi tải lại trang thì chúng mới thấy được những thay đổi đó.

Thực chất việc này là đúng. Vì khi có tính năng mới thì thông thường app sẽ cần phải thông báo cho người dùng biết là có tính năng mới và cần tải lại trang. Nhưng đó là những điều mà app của chúng ta chưa có.

Để xử lý vấn đề này thì có nhiều cách. Chúng ta cũng có thể lập trình để app của chúng ta có một kết nối liên tục với server. Mỗi khi mà chúng ta cho release một phiên bản mới của app thì từ server sẽ gửi một thông điệp đến cho app và app sẽ dựa vào thông điệp đó để kiểm tra và thông báo lại cho người dùng (có thể là một popup thông báo có phiên bản mới và người dùng cần tải lại trang để thấy được)

Một cách nữa là chúng ta có thể lợi dụng lifecycle của Service Workers. offline-plugin đã làm rất tốt cho chúng ta với phần runtime của nó. Ý tưởng là sẽ kiểm tra thay đổi của file cấu hình Service Workers xem là có thay đổi nào không, nếu có thì app sẽ được lập trình để thông báo lại cho người dùng. Vì mỗi lần chúng ta build thì sẽ sinh ra một file cấu hình Service Workers mới, trong đó chứa những thông tin để Service Worker có thể vận hành và mỗi lần build source thì chúng ta sẽ có những khoảng thời gian khác nhau, vì thế mà file cầu hình Service Workers sẽ khác nhau tùy vào thời điểm build (các bạn có thể kiểm tra trong file cấu hình Service Workers sẽ có một thuộc tính là version, offline-plugin sẽ kiểm tra thuộc tính version đó để biết là app của chúng ta có được cập nhật mới hay không?). Một chú ý nữa là để làm được việc đó thì offline-plugin chúng ta sẽ lập trình để trong một khoảng thời gian (có thể 2 phút) thì ở trình duyệt sẽ request đến web server để lấy file cấu hình Service Workers và kiếm tra. Sau đó sẽ dùng phần runtime để có những hành động tương ứng. Thì tất cả những điều mình nói ở trên đều có trong bài viết này, mọi người có thể xem thêm.

3. App của chúng ta có thể xử lý offline nhưng chỉ ở root /?

Chúng ta đã làm việc nhiều với mode offine. Nhưng hãy để ý là app sẽ chỉ hoạt động ổn khi ở root / và ở những trang khác như là /feature. /service thì sẽ lại là chơi với khủng long 🐲 rồi. Lý do của việc này là app của chúng ta là Single Page vì thế mà tất cả những xử lý điều hướng thì sẽ đề phải thông qua code javascript chứ không phải được request đến web server như thông thường. Và Service Workers sẽ ở giữa nhận request và response của client và server dẫn đến việc điều hướng /feature không được Service Workers tìm thấy ở bộ nhớ cache và nó sẽ gửi thẳng lên web server. Kết quả như các bạn đã thấy đấy 🐲.

Hướng xử lý là sẽ lập trình Service Workers làm sao để mà những điều hướng không nằm trong cache thì sẽ được điều hướng lại vể root /. offline-plugin cũng đã cung cấp cho chúng ta tính năng này rồi và sử dụng AppShell model để xử lý. Ở config của offline-plugin chúng ta sẽ thêm một option appshell: '/' để có thể hoạt động được. Những giải thích về AppShell model thì mình sẽ để lại bài sau để có những nghiên cứu kỹ càng hơn.

4. Service Workers cập nhật liên tục và app thông báo liên tục cho người dùng?

Vấn đề này khá hy hữu và hiếm gặp. Service Workers cập nhật liên tục là do nó nhận thấy có thay đổi và làm theo những phần lập trình của chúng ta đã áp dụng vào nó trước đó (khi có phiên bản mới thì app sẽ thông báo cho người dùng). Lý do của việc này là do file cấu hình Service Workers của chúng ta đang có vấn đề, dẫn đến thuộc tính version trong file cấu hình thay đổi liên tục. File cấu hình thay đổi liên tục dẫn đến app được lập trình thông báo liên tục cho người dùng.

Hướng xử lý sẽ là kiểm tra thuộc tính version trong file cấu hình Service Workers và đồng thời kiếm tra lại phần cấu hình ở web server. Lý do thường gặp ở đây nhất là do phần cấu hình web server có tính năng Load-Balancing và chưa được hợp lý khi áp dụng tính năng này. Khả năng là trên những server khác nhau và serve những asset khác nhau bao gồm cả file cấu hình Service Workers. Source build chưa đồng bộ giữa các server do mỗi server là một job build khác nhau dẫn đến thời gian build có thể bị chênh lệch, tiếp đó hệ quả sẽ là file cấu hình Service Workers sẽ có sai khác ở phần version. Và ở dưới client khi request lên server thì sẽ được rẽ nhánh đến các server khác nhau và lấy những file cấu hình Service Workers khác nhau, cuối cùng dẫn đến Service Workers có cập nhật liên tục. Hướng xử lý cuối cùng sẽ là đồng bộ source code build giữa các web server (có thể build docker image và dùng chung hay chỉ đơn giản là tạo một thư mục chia sẻ giữa các server rồi build source code vào đó dùng chung).

III. Kết luận.

Bên trên là một số vấn đề mình gặp phải và có một phần tham khảo được từ những người bạn trong quá trình mình làm việc với offline-plugin. Thì mong rằng với những chia sẻ của mình sẽ phần nào giúp mọi người hiểu hơn về hoạt động offline-pluginService Workers để từ đó có những đối ứng hợp lý hơn với những vấn đề gặp phải. Bài viết của mình đến đây là hết rồi! Cảm ơn mọi người đã đón đọc. Xin chào và hẹn gặp lại trong bài kế tiếp.


All Rights Reserved