Published on

Tại sao cache của Autoptimize lại nặng đến vậy?

Authors

Plugin Autoptimize luôn là plugin yêu thích 🔗 của Tuấn từ rất lâu rồi bởi vì đây là plugin miễn phí, hoạt động ổn định và có đầy đủ những thứ mình cần. Bản thân Tuấn cũng thấy rất nhiều bạn đã chọn Autoptimize như một giải pháp miễn phí mà rất hiệu quả cho việc tối ưu trang. Tuy nhiên, được thứ này sẽ mất thứ kia, nếu tối ưu quá lố sẽ xảy ra những trường hợp rất đáng tiếc mà nổi bật trong số đó chính là dung lượng cache tăng quá cỡ.

true

Đây là một vấn đề không hề dễ chịu đâu. Nếu bạn vẫn đang nghĩ hosting/server của bạn vẫn còn đủ chỗ trống để chứa những tập tin cache này thì rất tiếc bạn đã không nhận ra rằng, kháchh hàng của bạn mới là những người chịu ảnh hưởng lớn nhất. Không chỉ Autoptimize mà WP Fastest Cache, Litespeed cache hay thậm chí các giải pháp trả phí như WP Rocket cũng gặp phải tình trạng này nếu chúng ta cấu hình không tốt.

Bài viết là rất dài, tuy nhiên, mình khuyên các bạn đọc hết bài viết vì như vậy, bạn sẽ biết được nguồn gốc của vấn đề trên chính trang của bạn và từ đó có thể đưa ra cách khắc phục tốt hơn là cách mình gợi ý nữa.


Nhưng trước tiên, tại sao nặng vậy?

Để lưu lại các kết quả tối ưu CSS/JS, các plugin đa số sẽ tạo một tập tin tạm trên ổ cứng, mục đích của việc sinh ra tập tin của các plugin trên là cache, giúp những lần truy cập sau plugin không phải tính toán, tối ưu lại lần nữa. Nhưng việc cấu hình sai cách sẽ dẫn tới số lượng tập tin tăng lên đột biến một cách không cần thiết. Tại sao lại sinh nhiều tập tin thay vì chỉ một, mời các bạn đọc tiếp.

Xóa cache (kể cả cache trình duyệt) một cách hiệu quả là rất khó, đã được chứng minh trong một câu nói nổi tiếng của ngành lập trình mà bạn cần nghe qua một lần:

There are only two hard things in Computer Science: cache invalidation and naming things.

Phil Karlton

Được dịch vui vẻ ra tiếng Việt như sau: Có hai thứ khó nhất trong ngành khoa học máy tính: xóa cache và đặt tên biến. Những ai đã học qua trường lớp hoặc đang đi làm công việc lập trình luôn hiểu về sự đau khổ khi tìm tên để đặt sao cho dễ hiểu nhất.

Nếu các bạn chưa biết, Autoptimize sử dụng một phương pháp băm để giúp xóa cache từ phía người dùng mà mình sẽ giải thích chi tiết ngay bên dưới. Autoptimize đã rất chính xác khi chọn xử lý theo cách này và rất rất nhiều plugin như WP Rocket, WP Fastest Cache cũng vậy. Thậm chí phương pháp này đã được sử dụng từ lâu trên các webapp được build bởi Webpack chứng tỏ đây là một phương pháp đúng và hiệu quả.


Tại sao phải hash (băm)?

Trước kia để xóa cache trình duyệt, các plugin tối ưu và kể cả WordPress đều sử dụng chung một biện pháp là sử dụng query string ví dụ theme.js?ver=10.2.1 để quản lý các phiên bản cache khác nhau của cùng một tập tin. Nếu bạn có những thay đổi mới trong tập tin theme.js, chỉ cần tăng số phiên bản này lên thành theme.js?ver=10.2.2 chẳng hạn là được. Trình duyệt lúc này sẽ xem đây là tập tin mới và tiến hành tải lại, từ đó những thay đổi của bạn sẽ có hiệu quả ngay lập tức.

Tuy nhiên, vấn đề xảy ra khi chúng ta chỉ thay đổi một hoặc một vài tập tin nhưng số phiên bản của tất cả các tập tin đều phải đồng loạt tăng theo (theo phiên bản WordPress, plugin, theme,...) vì không có một plugin tối ưu nào có thể theo dõi từng thay đổi của từng tập tin để có thể đánh số phiên bản riêng được. Ngoài ra, việc đánh số phiên bản này không thể làm tự động và cũng không thể chỉnh sửa dễ dàng.

Để thay đổi số phiên bản của từng tập tin, chúng ta phải tìm từng dòng code của hai function wp_enqueue_scriptwp_register_script. Điều đó đồng nghĩa với bao nhiêu tập tin thay đổi, chúng ta phải sửa bấy nhiêu dòng code và phức tạp hơn nữa, các function này thường không nằm cùng một tập tin nên việc thay đổi là rất nhiều và không thể tự động được.

Lúc này người ta mới nghĩ ra một phương pháp rất đơn giản nhưng vô cùng hiệu quả, đó là tạo ra một chuỗi băm để tạo ra một tập tin hoàn toàn mới. Chuỗi băm này chỉ cần thỏa mãn một điều kiện duy nhất là không được trùng lặp với những thay đổi nội dung dữ liệu. Nói đơn giản, Autoptimize sẽ lấy nội dung của tập tin CSS/JS đã tối ưu và băm nội dung theo kiểu MD5. Lúc này mọi thay đổi của tập tin dù là nhỏ nhất sẽ tạo ra một nội dung băm hoàn toàn khác với tên cũ, đồng nghĩa tạo ra một tập tin cache mới.

$ echo "Day la noi dung 1" | md5 9be619cff1730f898f84f811938c5a3a

$ echo "Day la noi dung 2" | md5 9754c2863b36295609225add01d10862

$ echo "Day la noi dung 3" | md5 e97fa1eaef5c5dd0873d3cd9926ba4fb

Như ví dụ bên trên, chỉ cần một thay đổi nhỏ cũng làm nội dung băm thay đổi không thể đoán trước được. Từ đó đảm bảo những thay đổi về code của bạn đều sẽ tạo ra một tập tin cache hoàn toàn khác tên và đảm bảo trình duyệt sẽ thấy ngay đây là một tập tin mới chưa từng xuất hiện, không để người dùng bị "dính" cache cũ. Và vì là băm của từng tập tin nên các plugin cache có thể tự động tạo ra tập tin mới hoàn toàn, đồng thời cũng chỉ những tập tin có thay đổi mới được đổi tên.

Có hai tác dụng phụ nhưng ở nghĩa tích cực của việc băm tên tập tin cache:

  • Rollback (khôi phục những thay đổi): nhờ vào việc từng chuỗi băm là một khóa của tập tin, chúng ta có thể khôi phục về phiên bản trước và có một chút cơ hội rằng người dùng đó truy cập và có cache của tập tin đó trước kia.
  • Che giấu: các tập tin sau khi được tối ưu và lưu với một cái tên mới sẽ nằm tại thư mục /wp-content/cache/autoptimize. Điều này giúp bạn che giấu được kha khá việc lộ đường dẫn của theme và plugin đang sử dụng.

Cách Autoptimize, WP Rocket Cache làm việc

WP Rocket, WP Fastest Cache và các plugin khác cũng hoạt động tương tự như vậy. Tùy cấu của quản trị, trong đó một setting quan trọng nhất là bao gồm luôn cả những đoạn CSS/JS inline trong trang vào tập tin cache bên trên để tối ưu "hết mức". Tuy nhiên, để dễ hiểu hơn, mời các bạn xem qua một ví dụ đơn giản để có thể hiểu vấn đề ảnh hưởng như thế nào. (Nhớ click vào ảnh để xem ảnh to hơn nếu bạn không nhìn rõ).

Đầu tiên, hãy xem cách tải JS nếu chúng ta không cài đặt một plugin tối ưu nào. Mọi thứ rất bình thường, query string ver còn đó, JS chưa được tối ưu. Đoạn code này theo mình là rất tốt, tuy nhiên sẽ bị Google PageSpeed đánh giá không cao, từ đó mới sinh ra chuyện chúng ta sử dụng plugin tối ưu tốc độ website.

true

Chú thích JS: Đoạn JS inline trên tìm element có ID post-51, có thể là bài viết có ID 51, tìm tới element có tên wp-review và chuyển chữ sang màu vàng.

Khi đã cài đặt một plugin tối ưu JS/CSS nào đó, ví dụ như Autoptimize với một số tùy chọn đơn giản, Autoptimize chỉ làm một số việc như loại bỏ code comment, query string ver, tối ưu JS về còn 1 dòng để tiết kiệm được byte nào hay byte đó. Đây cũng là cấu hình tối ưu rất dễ chịu nhưng hiệu quả, Google PageSpeed khá thích bạn tối ưu như thế này, dù cho nó chưa phải là nhanh nhất.

true

Như các bạn có thể thấy, tập tin theme.js vẫn được giữ nguyên và có thể chưa được tối ưu hoàn toàn. Chỉ những đoạn JS inline không nằm trong tập tin nào được tối ưu thôi. Mà plugin cho ta rất nhiều tính năng, tội gì mà không bật nên mới có chuyện tối ưu kiểu "hardcore".

Cuối cùng là mức tối ưu cao nhất, gom tất cả JS lại, bao gồm cả nội dung của tập tin theme.js và tất cả các nội dung JS inline có trên trang. Tên tập tin 1dg823.js chính là kết quả băm của toàn bộ nội dung JS mà Autoptimize đã gom lại được.

true

Mọi việc có vẻ đã nhanh hơn và tốt hơn rất nhiều, PageSpeed Insight xanh mướt nhưng cực kì cực kì nhiều bạn không nhận ra vấn đề đang gặp phải. Vấn đề được thể hiện ngay trong hình ảnh dưới đây.

true

Vấn đề đã trở nên rõ ràng hơn, nếu một bài viết khác, ví dụ ID 52 cũng cấu hình chuyển chữ viết thành màu vàng. Lúc này, chỉ vì sự thay đổi từ số 1 sang số 2 mà nội dung tập tin JS đã tối ưu của các plugin trở thành một tập tin mới có tên t2g1ds.js. Đồng nghĩa với một tập tin mới được tạo ra, hơn thế nữa, đồng nghĩa với việc người dùng và bạn mất đi ưu thế về cache. Đó là khi người dùng phải tải lại tập tin có kích thước tương đương nhưng chỉ khác mỗi số 1 và 2 trong post ID 51 và 52.

true

Như ví dụ một website trên đây sử dụng WP Rocket cũng gặp phải tình trạng tương tự. Ở mỗi trang khác nhau, WP Rocket lại sinh ra một tập tin mới dù cho những thay đổi là nhỏ đáng kể. Như hai tập tin dưới đây, sự khác nhau chỉ là một thư viện được thêm vào script ở trang bài viết (bên phải) làm tập tin ở trang này khác hoàn toàn với trang chủ (bên trái).

true

Chỉ vì một sự khác biệt nhỏ mà người dùng phải tải lại toàn bộ thư viện tập tin JS rất nặng. Ngoài ra còn rất rất nhiều website khác cũng gặp phải vấn đề tương tự mà mình không thể tổng kết hết được.


Tại sao chuyện này lại quan trọng?

Thật sự vấn đề cache không tốt bị bỏ qua hoàn toàn (theo quan sát của mình) bởi vì lí do rất đơn giản, Google PageSpeed không đánh giá được vấn đề này và những người tối ưu website cũng không nhận ra được sự khác nhau.

Giải thích đơn giản là, Google PageSpeed Insight chỉ đánh giá duy nhất trang mà bạn yêu cầu, không đánh giá một cách toàn diện những trang khác theo cách mà người dùng bình thường sử dụng ví dụ như truy cập trang chủ, sau đó mở trang chuyên mục, sau đó mới mở đến trang bài viết. Trong khi đó cho dù bạn làm điểm Pagespeed Insight thật sự nhanh ở trang bài viết, tuy nhiên ở real-world (trải nghiệm thật của người dùng) thì chưa chắc đã nhanh, chưa chắc đã tối ưu.

Dưới đây sẽ là sơ đồ đơn giản cách trình duyệt tải các tập tin JS dựa vào các cách tối ưu bên trên. Mình cũng đã lược giản CSS đi rồi.

Như các bạn có thể thấy, hai cách Không tối ưu hoặc Tối ưu cơ bản có cách tải rất giống nhau, chỉ khác một chút xíu khi tối ưu cơ bản có kích thước nhỏ hơn do đã được tối ưu rồi. Khi di chuyển giữa các trang, trình duyệt sẽ thấy tập tin jquery.min.jstheme.js đã được cache khi bạn truy cập lần đầu ở trang chủ, vì vậy những lần truy cập tiếp theo trình duyệt chỉ phải tải HTML và các inline JS nằm trong nó mà thôi.

true

Ở những lần truy cập sau, lượng dữ liệu trả về từ server cho mỗi lượt truy cập trang đã giảm đi đáng kể, chỉ còn khoảng 3-4Kb mỗi lần. Đồng nghĩa với việc trình duyệt đã cache được những tập tin lớn và quan trọng, không tốn thời gian tải về ở những lần tải trang tiếp theo.

Như trường hợp Tối ưu kiểu "hardcore" nhưng sai cách, các bạn sẽ gặp phải vấn đề mình đã chia sẻ. Chỉ vì vài thay đổi nhỏ trong inline JS (khoảng 2Kb) nhưng vẫn phải tải lại bao gồm 20Kb của tập tin theme.js mặc dù tập tin này không thay đổi gì. Từ đó lượng dữ liệu có thể cache được sẽ giảm đi rất nhiều, đồng nghĩa với việc trình duyệt phải đợi/tải đi tải lại những thứ mà lẽ ra đã được cache từ lần truy cập đầu tiên.

true

Vấn đề này không chỉ ảnh hưởng trực tiếp đến người dùng mà còn ảnh hưởng đến quản trị viên. Server/hosting phải tốn thời gian để generate (tạo ra) từng tập tin cache cho từng trang cho những thay đổi rất nhỏ. Những tập tin cache này cũng làm nặng số lượng và kích thước lưu trữ của hosting và server đó bạn nhé.


WordPress mở nên rắc rối

WordPress có một hệ sinh thái rộng lớn bao gồm rất nhiều theme và plugin đa dạng, từ miễn phí đến trả phí, thực hiện rất nhiều chức năng khác nhau. Đa dạng và tự do là vậy nên việc WordPress không yêu cầu các theme/plugin hoạt động theo một quy chuẩn nào là điều dễ hiểu. Chính vì vậy, việc lập trình viên không dự đoán trước được các trường hợp người dùng cần tối ưu xảy ra rất nhiều, từ những người non kinh nghiệm đến những bên có tên tuổi như MyThemeshop, BetterStudio,...

Anh em dev có thể giải quyết tình trạng này bằng cách đưa những giá trị động trong inline JS vào một chỗ khác dễ giải quyết hơn, ví dụ thuộc tính data của element, từ đó viết một đoạn global JS để xử lý vấn đề. Ví dụ data-custom-css="color: yellow" hay data-post-id="52" thay vì nhét vào đoạn inline JS kia. Và mình tin là còn nhiều cách xử lý nữa mà mình nghĩ anh em có thể sáng tạo sau khi được chỉ ra vấn đề.


Cách giải quyết vấn đề

Một cách giải quyết mà mình thường thấy, có thể là vô tình hoặc cố ý, các bạn sẽ sử dụng tính năng Inline all CSS của Autoptimize để đẩy thẳng toàn bộ CSS vào response HTML trả về trình duyệt. Cách tiếp cận này có vẻ rất hoàn hảo vì trình duyệt không cần tải về quá nhiều tập tin trong khi dữ liệu đã có sẵn và xử lý nhanh chóng mà không cần phải tạo yêu cầu đến máy chủ.

Tuy nhiên kết quả bạn nhận được sẽ tương tự với cách tối ưu "hardcore" sai cách bên trên và kết quả sẽ còn tệ hơn. Thông thường kích thước tập tin CSS của theme hiện tại là rất nhiều, trình duyệt sẽ tốn rất nhiều thời gian để có thể đọc đến phần cuối của trang, nơi bạn đặt các script JS khác, làm mọi thứ trong trang phải đợi lâu hơn. Ngoài ra response HTML này cũng không thể cache được, từ đó mình nhận thấy rằng lượng dữ liệu (gồm CSS/JS) mà trình duyệt cache được nếu bạn Inline all CSS là gần như bằng 0.

Lời giải thích mà mình có thể nghĩ đến là các bạn lầm tưởng đây là tính năng Critical CSS giúp ưu tiên những đoạn CSS quan trọng để tải đầu tiên và lazyload tất cả những CSS chưa thật sự dùng đến. Thật sự phương pháp sử dụng critical CSS thật sự rất khó áp dụng ở mức tự động cao, Tuấn có một thời gian sử dụng Critical CSS của Autoptimize và cảm thấy việc tối ưu critical CSS (chỉ là một phần trăm nhỏ trong toàn bộ CSS) mà còn cảm thấy rất cực và không hiệu quả. Hãy tối ưu toàn bộ CSS của bạn một cách tốt nhất có thể, từ đó Google sẽ không phàn nàn gì nữa.

Autoptimize

Cách giải quyết tốt nhất mà Tuấn có thể đưa ra là bạn hãy áp dụng một số cách tối ưu dễ chịu hơn và chấp nhận điểm số vừa phải, cân bằng giữa điểm số và quan trọng hơn hết là trải nghiệm người dùng thông suốt. Dưới đây là cấu hình Autoptimize mà mình gợi ý cho những bạn tự tối ưu cho website lần đầu hoặc có cấu trúc theme/plugin phức tạp.

Trước đây Autoptimize chưa có tính năng "Aggregate JS-files", các tập tin khi không combine sẽ được tải như bình thường nhưng cũng không có gì thay đổi (minify, tối ưu). Mình đã gửi một request đến tác giả 🔗 và tính năng này đã được tích hợp, sử dụng hiệu quả cho đến ngày nay. Đó cũng là lí do mà mình thích sử dụng Autoptimize và WordOps vì dù là miễn phí nhưng các tác giả vẫn hỗ trợ rất nhiệt tình.

true

Đây là cấu hình ở mức tối ưu đơn giản mà mình chia sẻ ở trên. Sau khi áp dụng cấu hình này, các bạn sẽ không gặp phải tình trạng tăng kích thước nữa mà cũng không ảnh hưởng quá nhiều đến tốc độ của website.

WP Rocket

Bạn có thể điền một số đoạn chữ nằm trong những đoạn inline JS của các plugin/theme vào đây để giải quyết phần nào vấn đề kể trên. Trong ví dụ trên đoạn chữ xuất hiện đi xuất hiện lại là wp-review, vì vậy mình sẽ điền vào khung Exclude Inline JavaScript này. Bạn cũng có thể xem chi tiết hướng dẫn của WP Rocket tại hướng dẫn gom JS 🔗 của họ.

true


Kết

Kết quả mà bạn có thể đạt sau khi test qua một số trang như: trang chủ, 3 đến 4 trang bài viết, 1 đến 2 trang chuyên mục và có kết quả như sau.

  • Tất cả các trang trên website của bạn đều sử dụng chung một tập tin: đây là kết quả tốt nhất mà bạn đã đạt được, xin chúc mừng!.
  • Trang chủ và trang chuyên mục (tất cả các chuyên mục, tag, archive,...) nên có cùng một tên tập tin (cùng một chuỗi băm).
  • Tất cả bài viết đều có sử dụng chung một tập tin.
  • Tất cả các trang (page) đều sử dụng chung một tập tin, càng tốt hơn nữa nếu sử dụng chung tập tin với bài viết.

Để xác định xem các trang có dùng chung một tập tin hay không, bạn có thể sử dụng chức năng View source của trình duyệt hoặc mở tab Network trong Chrome Developer Tools, chọn filter theo JS. Ngoài ra bạn cũng có thể kiểm tra bằng Pingdom 🔗, GT Metrix 🔗, Webpagetest.org 🔗 đều được nhé.

true

Ngoài ra sẽ còn rất nhiều cách tối ưu khác mà mình sẽ gửi đến các bạn trong những bài viết sắp tới sau khi mình tìm cách giải thích dễ hiểu và hướng dẫn dễ làm nhất cho các bạn.

Tối ưu website vẫn là công việc đòi hỏi thời gian và sự tỉ mĩ. Đối với Tuấn, một trang web được tối ưu hoàn hảo là khi chúng ta không còn gì để tối ưu nữa mà vẫn giữ nguyên được những giá trị, chức năng website hiện có.

Chúc các bạn luôn vui và giữ được sự hào hứng khi website đạt được điểm số cao hơn.