yewstack / yew

Rust / Wasm framework for creating reliable and efficient web applications
https://yew.rs
Apache License 2.0
30.79k stars 1.43k forks source link

Flags, or how to inject data before hosting? #170

Closed vitiral closed 4 years ago

vitiral commented 6 years ago

Hey, thanks for the amazing framework! I just started rewriting the frontend of artifact in yew and I have to say this is already an immense pleasure to work with.

Use Cases

  1. One wants to dynamically host static content. For instance, they just need to inject a JSON blob of the data to render.
  2. One wants to inject configuration flags before hosting the static HTML/JS. For instance, configuration variables like readonly or url/port information of some kind.

My old (hacky) solution in elm.

In elm I accomplished this through a super hacky method, I just put this in the index.js:

var app = Elm.Main.embed(mountNode, {/* REPLACE WITH FLAGS */} );

This causes the compiled app.js to look like this:

var app = Elm.Main.embed(mountNode, {/* REPLACE WITH FLAGS */} );

I then replace the string {/* REPLACE WITH FLAGS */} with the json of the actual flags before hosting. I do a similar thing for the artifacts (when hosted statically where I just put artifactsRaw = "REPLACE WITH ARTIFACTS" in the initialModel and then replaced that string with escaped json. Both methods worked.

However, it seems that this hack cannot be accomplished in yew because the "REPLACE WITH FLAGS" (or any other string I choose) doesn't get included in the final output (I assume you are converting it to binary or something, which is sensible).

Conclusion

Is there a way to do this in yew, even hacky? Can I prevent yew/cargo-web from optimizing the size of the string so I can inject my own data? Is there any similar concepts as Flags? Is there any way for me to control the app.json/index.html?

Thanks!

vitiral commented 6 years ago

Edit

It looks like the dashboard example isn't quite what I was looking for. The data.json is included alongside the index.html but it doesn't run as a static file... so it isn't capable of actually getting the static content.


It looks like the dashboard example uses a data.json file. I'm a bit confused about it.

The relevant code seems to be:

Put some data in static/data.json:

{
    "value": 123
}

Have a type which matches the type of what is/will-be in data.json

/// This type is used to parse data from `./static/data.json` file and
/// have to correspond the data layout from that file.
#[derive(Deserialize, Debug)]
struct DataFromFile {
    value: u32,
}

Put something like this in your update

Msg::FetchData => {
    self.fetching = true;
    let callback = context.send_back(|response: Response<Json<Result<DataFromFile, Error>>>| {
        let (meta, Json(data)) = response.into_parts();
        println!("META: {:?}, {:?}", meta, data);
        if meta.status.is_success() {
            Msg::FetchReady(data)
        } else {
            Msg::Ignore  // FIXME: Handle this error accordingly.
        }
    });
    let request = Request::get("/data.json").body(Nothing).unwrap();
    let task = context.web.fetch(request, callback);
    self.ft = Some(task);
}

Am I to understand that yew::services::fetch::Request::get(/file) gets files from the directory where index.html is? I guess that is what "static hosting" means? (I'm way too much of a newb on how html projects are handled)

vitiral commented 6 years ago

well, I figured out how to do the same hacky workaround by using stdweb's js! macro (yay!)

example_json: js!{return "REPLACE FOR EXAMPLE"}
    .into_string().unwrap_or("couldn't unwrap".into()),

The "REPLACE FOR EXAMPLE" stays in the compiled output and looks like this:

function($0) { Module.STDWEB_PRIVATE.from_js($0, (function(){return "REPLACE FOR EXAMPLE"})()); },
vitiral commented 6 years ago

it should be possible to use Properties for this.. I think.

samuelvanderwaal commented 4 years ago

Missing label:

jstarry commented 4 years ago

This is supported with https://docs.rs/yew/0.11.0/yew/fn.start_app_with_props.html