Hiệu năng Liquid: viết template render nhanh hơn

5 phút đọc

Read in English →

Liquid chạy trên server của Shopify trước khi bất kỳ byte nào đến được trình duyệt, nên các template kém hiệu quả sẽ làm time to first byte chậm đi ở mọi request không được cache. Phần lớn theme không chậm đáng kể ở khâu này, nhưng section, block và snippet cộng dồn lại. Đây là những thói quen chúng tôi gợi ý để giữ việc render template gọn nhẹ, cùng với những điểm mà Liquid hiếm khi là nút thắt thật sự.

Hãy thực tế về mức cải thiện

Tài liệu của Shopify nói khá thẳng về quy mô: mỗi micro-optimisation trong Liquid tiết kiệm khoảng 1 đến 5 ms TTFB, và với một theme có khoảng 50 section và vài block mỗi section, áp dụng tất cả các mẫu này cùng lúc có thể lấy lại chừng 25 đến 50 ms. Con số đó đáng có với một theme phức tạp, nhưng sẽ không cứu được một storefront nạp nhiều JavaScript hoặc hình ảnh chưa tối ưu. Hãy coi việc tinh chỉnh Liquid là bước hoàn thiện cuối cùng, và đo bằng tiện ích Theme Inspector cho Chrome, công cụ cho thấy thời gian render đi vào đâu theo từng dòng.

Đưa công việc không đổi ra khỏi vòng lặp

Quy tắc đáng tin cậy nhất: nếu một thao tác trả về cùng kết quả ở mọi lần lặp, hãy làm nó một lần trước vòng lặp. Sắp xếp, lọc và truy vấn metafield là những nghi phạm thường gặp.

{%- comment -%} Before: setting lookups repeat on each pass {%- endcomment -%}
{% for product in collection.products %}
  <h3 class="{{ section.settings.heading_class }}">{{ product.title }}</h3>
  {% if section.settings.show_vendor %}
    <p>{{ product.vendor }}</p>
  {% endif %}
{% endfor %}

{%- comment -%} After: read once, reuse {%- endcomment -%}
{%- liquid
  assign heading_class = section.settings.heading_class
  assign show_vendor = section.settings.show_vendor
-%}
{% for product in collection.products %}
  <h3 class="{{ heading_class }}">{{ product.title }}</h3>
  {% if show_vendor %}
    <p>{{ product.vendor }}</p>
  {% endif %}
{% endfor %}

Cách nghĩ này cũng áp dụng cho các setting của block: gán chúng vào một biến một lần rồi dùng biến đó về sau. Nếu một filter được gọi lặp lại với cùng tham số, hãy lưu kết quả thay vì tính lại.

Lấy dữ liệu một lần, lọc trong Liquid

Khi một trang cần nhiều chế độ xem đã lọc của cùng một dữ liệu, hãy cưỡng lại ý muốn yêu cầu từng chế độ xem riêng. Hướng dẫn của Shopify lưu ý rằng lọc bên trong Liquid rất nhanh, trong khi mỗi yêu cầu dữ liệu bổ sung đều kéo theo chi phí mạng và truy vấn. Hãy lấy toàn bộ tập dữ liệu một lần rồi tách ra bằng vòng lặp hoặc filter.

Giữ mức lồng snippet nông

Mỗi lệnh gọi render đều có chi phí, và đặt nó trong vòng lặp sẽ nhân chi phí lên. Một snippet product card tự render snippet giá, rồi snippet đó lại render snippet badge, sẽ được gọi rất nhiều lần trên trang collection. Khi một snippet nhỏ và chỉ dùng ở một nơi, viết thẳng markup của nó vào thường gọn hơn là thêm một tầng. Các vòng lặp lồng sâu cũng đáng nghi ngờ như vậy, và mega menu xuất ra lượng markup lớn ở mỗi lượt xem trang cũng thế.

Ưu tiên xuất giá trị trực tiếp thay vì nối chuỗi phức tạp

Dựng chuỗi bằng một chuỗi filter nối nhau chậm hơn so với việc đơn giản in giá trị bằng output tag hoặc echo. Nếu bạn thấy mình đang ghép các phần của tên class bằng nhiều filter, hãy cân nhắc xem vài câu điều kiện có dễ đọc hơn và chạy nhanh hơn không.

Những cải thiện nằm ngoài Liquid

Hướng dẫn rộng hơn của Shopify về theme chỉ ra những mảng thường quan trọng hơn việc tinh chỉnh template:

  • JavaScript: dùng HTML và CSS cho hành vi cốt lõi, coi script là progressive enhancement, giữ bundle đã minify ở mức 16 KB trở xuống, và nạp tệp bằng defer hoặc async.
  • Resource hint: không quá hai cái cho mỗi template, dành cho các tệp thực sự quan trọng và chặn render.
  • Hình ảnh: chỉ lazy-load các ảnh nằm dưới màn hình đầu, yêu cầu đúng kích thước bạn sẽ hiển thị, và để image_tag tạo srcset responsive.
  • Font: font hệ thống tránh hoàn toàn các lượt tải thêm.
  • Asset: phục vụ chúng từ thư mục assets của theme để được cung cấp qua CDN của Shopify.

Một ví dụ nhỏ cho điểm về hình ảnh:

{{ product.featured_image
  | image_url: width: 800
  | image_tag:
      loading: 'lazy',
      sizes: '(min-width: 990px) 25vw, 50vw',
      widths: '300, 450, 600, 800' }}

Chỉ dùng loading: 'lazy' cho các ảnh nằm dưới màn hình đầu tiên; ảnh hero nên tải bình thường để trình duyệt có thể lấy sớm.

Phòng tránh suy giảm hiệu năng

Theme Check cảnh báo các bundle CSS và JS quá lớn, tham chiếu asset từ xa, script chặn parser và các phụ thuộc CSS giữa các tệp, nên là một linter hữu ích để chạy ngay trong trình soạn thảo. Với các dự án lớn hơn, Shopify cũng cung cấp một Lighthouse CI action có thể chạy trên pull request, và tài liệu của họ khuyên chạy Lighthouse nhiều lần rồi lấy giá trị trung vị thay vì tin vào một điểm số duy nhất. Thêm ?pb=0 vào URL sẽ ẩn thanh preview trong lúc audit.

Nếu bạn muốn có thêm một góc nhìn thứ hai cho một cửa hàng đang chạy, trang dịch vụ của chúng tôi mô tả cách chúng tôi thực hiện audit theme, và các theme chúng tôi phát hành được xây dựng với những ràng buộc này ngay từ đầu.

Đọc thêm

← Tất cả bài viết