rust web 框架 loco 的后端 HTML 模板

文章目录

    loco 框架目前的文档还是有点简陋,想通过直接看文档来上手,不太现实。
    还是需要自己结合代码去查看三方的依赖库的文档。

    目录结构

    注意,后台模板及相关的资源文件是在 assets 目录下。
    而不是 frontend 目录下,frontend 是 vite 创建的纯前端部分 (前后端分离的方案, loco 的默认首页就是在 frontend 中)。

    Loco SaaS 项目,初始化的 assets 目录结构:

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

    view

    后台 HTML 模板存放在 assets/views 目录下,这点有点像 laravel,
    不叫 template,而称之为 view。

    Loco Views 分为两类:

    • JSON view: 其实就是 API 接口的 JSON 返回。但是独立到一个文件中进行定义,确实代码简洁了不少。例如,用户接口的 JSON 返回,就定义在了 src/views/user.rs 中。
    • Template view: 这个就是后台 HTML 模板。

    但是 Loco Template View 有一点不一样,就是需要先封装在 src/views 中,然后才能在 src/controllers 中使用。
    这在之前用过的 web 框架中从未见过,其他框架都是直接在 controller 中使用就行了。

    官方的一个示例:

    // 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)
    }
    

    如何传递参数呢?

    下面是 github issue 中的一段伪代码:

    // 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))
    }
    

    Tera 模板引擎

    https://keats.github.io/tera/

    A powerful, easy to use template engine for Rust. Inspired by Jinja2 and Django templates.

    看来是借鉴了 python 主流 web 框架的模板语法。
    看了一下文档, 功能非常强大,不逊色于 django template。

    示例:

    <title>{% block title %}{% endblock title %}</title>
    <ul>
    {% for user in users -%}
      <li><a href="{{ user.url }}">{{ user.username }}</a></li>
    {%- endfor %}
    </ul>
    

    I18N 多语言支持

    默认的 hello.html 中包含了一个示例:

    <html><body>
      <img src="/static/image.png" width="200"/>
      <br/>
      find this tera template at <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>
    

    比较奇怪的是 lang 参数,是否可以省略?

    从 view 的配置文件 src/initializers/view_engine.rs 可以看到:

    use fluent_templates::{ArcLoader, FluentLoader};
    

    fluent-templates lets you to easily integrate Fluent localisation into your Rust application or library.

    https://github.com/XAMPPRocky/fluent-templates

    Cargo.toml

    # view engine i18n
    fluent-templates = { version = "0.8.0", features = ["tera"] }
    unic-langid = "0.9.4"
    # /view engine
    

    回到正题,是否可以省略 lang,看起来不太容易:

    In handlebars, fluent-templates will read the lang field in your handlebars::Context while rendering.

    通过模板参数传过去看起来是省不了。

    github issue 中有一个相关的讨论,不过目前还没有结论。

    https://github.com/loco-rs/loco/pull/389

    继续阅读

    动手篇:rust web 框架 Loco 新建一个 HTML 页面

    参考

    • https://loco.rs/docs/the-app/views/
    • https://keats.github.io/tera/

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式