Mẫu HTML phía sau cho khung web Rust Loco - tỷ số trực tuyến bóng đá 7m.cn

/imgposts/1fsztapc.jpg

Tài liệu của khung Loco hiện tại vẫn còn khá sơ lược, nên việc chỉ dựa vào tài liệu để bắt đầu không thực sự khả thi. Chúng ta cần kết hợp xem mã nguồn và tham khảo tài liệu của các thư viện phụ thuộc bên ngoài.

Lưu ý rằng các mẫu phía sau và tài nguyên liên quan nằm trong thư mục assets, chứ không phải frontend. Frontend là phần được tạo bởi Vite, dành riêng cho giao diện người dùng (phương án tách biệt giữa backend và frontend). Trang chủ mặc định vn69 của Loco nằm trong frontend.

Dưới đây là cấu trúc thư mục assets khi khởi nhận định kèo tạo dự án Loco SaaS:

> tree assets/
assets/
├── i18n
│   ├── de-DE
│   │   └── main.ftl
│   ├── en-US
│   │   └── main.ftl
│   └── shared.ftl
├── static
│   ├── 404.html
│   └── image.png
└── views
  └── home
    └── hello.html

Các mẫu HTML phía sau được lưu trữ trong thư mục assets/views, tương tự như Laravel nhưng được gọi là "views" thay vì "templates".

Loco Views chia thành hai loại:

  • JSON View: Đây thực chất là phản hồi JSON từ API, tuy nhiên nó được định nghĩa riêng trong một file, giúp mã nguồn gọn gàng hơn. Ví dụ, phản hồi JSON của API người dùng được định nghĩa trong src/views/user.rs.
  • Template View: Đây là các mẫu HTML phía sau.

Một điểm khác biệt ở Loco Template View là chúng cần được bọc trong src/views trước khi có thể sử dụng trong src/controllers. Điều này ít thấy trong các khung web khác mà bạn thường làm việc, nơi mà controller có thể sử dụng trực tiếp view.

Ví dụ từ tài liệu chính thức:

// src/views/dashboard.rs
pub fn home(v: impl ViewRenderer) -> Result<impl IntoResponse> {
  format::render().view(&v, "home/hello.html", json!({}))
}
// src/controllers/dashboard.rs
pub async fn render_home(ViewEngine(v): ViewEngine<TeraView>) -> Result<impl IntoResponse> {
  views::dashboard::home(v)
}

Làm thế nào để truyền tham số? Dưới đây là đoạn mã giả từ một issue trên GitHub:

// controller.rs
render_home(e: Engine<TeraView>) -> Result<impl IntoResponse> {
  views::dashboard::home(e, current_user)
}
// src/views/dashboard.rs
home(e: eng, user: User) -> impl ...{
    format::template(e, "dashboard/home.html", json!(name: user.name))
}

Một động cơ mẫu mạnh mẽ, dễ sử dụng cho Rust. Được lấy cảm hứng từ Jinja2 và Django templates. Rõ ràng Tera đã học hỏi cú pháp mẫu từ các khung web Python phổ biến. Sau khi xem qua tài liệu, tôi nhận thấy nó có rất nhiều tính năng mạnh mẽ, ngang tầm với Django template.

Ví dụ:

<title>{% block title %}{% endblock title %}</title>
<ul>
{% for user in users -%}
 <li>{{ user.username }}</li>
{%- endfor %}
</ul>

Trong hello.html mặc định có một ví dụ về cách sử dụng:

<html><body>
 <img src="/static/image.png" width="200"/>
 <br/>
 Tìm thấy mẫu tera tại <code>assets/views/home/hello.html</code>:
 <br/>
 <br/>
 {{ t(key="hello-world", lang="en-US") }},
 <br/>
 {{ t(key="hello-world", lang="de-DE") }}
</body></html>

Điều kỳ lạ là tham số lang, liệu có thể bỏ qua không? Từ file cấu hình view src/initializers/view_engine.rs, chúng ta có thể thấy:

use fluent_templates::{ArcLoader, FluentLoader};

Fluent-templates giúp bạn dễ dàng tích hợp localisation Fluent vào ứng dụng hoặc thư viện Rust của mình.

Cargo.toml

# Động cơ mẫu i18n
fluent-templates = { version = "0.8.0", features = ["tera"] }
unic-langid = "0.9.4"
# /động cơ mẫu

Quay lại vấn đề chính, liệu có thể bỏ qua lang không? Hình như không dễ:

Trong handlebars, fluent-templates sẽ đọc trường lang trong handlebars::Context khi đang render. Việc truyền qua thông qua tham số mẫu dường như không thể tránh khỏi. Có một cuộc thảo luận liên quan trên GitHub issue, nhưng hiện tại chưa có kết luận.

Thực hành: Xây dựng một trang HTML mới với khung web Rust Loco