Can I use Rust / Yew / Trunk to generate just a DOM node and script for use in HTML templates?

284 Views Asked by At

TLDR

Total n00b with rust, yew and trunk.

I want to find out how to rust, yew and trunk to build an HTML file containing just one DOM node, not a whole HTML page.

Background

Day-to-day, I use Django, the python web framework. Its admin console uses HTML template rendering, and an example of a template might look like this:

{% extends 'django_twined/question_changeform.html' %}

{% block object-tools-items %}
    {% if show_set_active %}
        <li><a href="?set_active=True">Set active</a></li>
    {% endif %}
    {{ block.super }}
{% endblock %}

Where in this example the {% %} and {{ }} get evaluated at render time into a valid HTML structure (from other template files), and the <li> is an extra node that gets added to the DOM.

Instead of a vanilla li element, I want to build a complex DOM node using Rust/Yew/Trunk. Then I can include the resulting head and body elements file in a django template, something like:

{% extends 'django_twined/question_changeform.html' %}

{% block head %}
    {{ block.super }}
    <!-- Include the scripts generated by trunk build -->
    {% include 'my-dom-node-head.html' %}
{% endblock %}

{% block object-tools-items %}
    <!-- Include the elements generated by trunk build -->
    {% include 'my-dom-node-body.html' %}
    {{ block.super }}
{% endblock %}

Where I'm at

I've used the yew starter app to get myself to an app. The input index.html is:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Yew App</title>
  </head>
</html>

And the main.rs file looks like:

use yew::prelude::*;

enum Msg {
    AddOne,
}

struct Model {
    value: i64,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        Self {
            value: 0,
        }
    }

    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            Msg::AddOne => {
                self.value += 1;
                // the value has changed so we need to
                // re-render for it to appear on the page
                true
            }
        }
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        // This gives us a component's "`Scope`" which allows us to send messages, etc to the component.
        let link = ctx.link();
        html! {
            <div>
                <button onclick={link.callback(|_| Msg::AddOne)}>{ "+1" }</button>
                <p>{ self.value }</p>
            </div>
        }
    }
}

fn main() {
    yew::start_app::<Model>();
}

After trunk build, the output index.html looks like:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Yew App</title>
    <link
      rel="preload"
      href="/yew-app-caccf6c60742c530_bg.wasm"
      as="fetch"
      type="application/wasm"
      crossorigin=""
    />
    <link rel="modulepreload" href="/yew-app-caccf6c60742c530.js" />
  </head>

  <body>
    <script type="module">
      import init from "/yew-app-caccf6c60742c530.js";
      init("/yew-app-caccf6c60742c530_bg.wasm");
    </script>
  </body>
</html>

Where next?

So basically I need to get the <link> and <script> elements added by trunk build and put them into my template.

What should I do next? Would you suggest I try to:

  • Get trunk build --filehash false to output deterministic .js and .wasm file names without the hash (caccf6c60742c530 in this case) so that I can directly write the includes into my template (I'm concerned this will cause me development problems down the road)?
  • Get trunk build to output separate head link and body script?
  • Post-process the output index.html to extract the inserted scripts?
  • Alter main.rs in some way to output only what I need/want?
0

There are 0 best solutions below