tauri icon indicating copy to clipboard operation
tauri copied to clipboard

feat(tauri): support patch context at runtime

Open WSH032 opened this issue 8 months ago • 10 comments

Discussed at https://github.com/tauri-apps/tauri/pull/13033#issuecomment-2928745052

This allows simulating the behavior of generate_context! at runtime and dynamically loading the Context.

WSH032 avatar Jun 02 '25 13:06 WSH032

CC @Legend-Master.

In examples/precompiled, you can see that I only set the most basic tauri.conf.json at build time, and then dynamically set the identifier, provide frontend assets, etc. at runtime based on examples/precompiled/src-tauri.

WSH032 avatar Jun 02 '25 13:06 WSH032

Package Changes Through 8a56ea7222401a5b69027e543aec1c80ed382ee8

There are 8 changes which include tauri-bundler with minor, tauri with minor, tauri-cli with minor, tauri-codegen with minor, tauri-utils with minor, @tauri-apps/api with minor, @tauri-apps/cli with minor, tauri-runtime-wry with patch

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
@tauri-apps/api 2.5.0 2.6.0
tauri-utils 2.4.0 2.5.0
tauri-bundler 2.4.0 2.5.0
tauri-runtime 2.6.0 2.6.1
tauri-runtime-wry 2.6.0 2.6.1
tauri-codegen 2.2.0 2.3.0
tauri-macros 2.2.0 2.2.1
tauri-plugin 2.2.0 2.2.1
tauri-build 2.2.0 2.2.1
tauri 2.5.1 2.6.0
@tauri-apps/cli 2.5.0 2.6.0
tauri-cli 2.5.0 2.6.0

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector

github-actions[bot] avatar Jun 02 '25 13:06 github-actions[bot]

So basically, this is duplicating the code from context_codegen in tauri-codegen to tauri so that it can be used at runtime, and they would be normal functions instead of ones that works with rust TokenStream right?

To be honest, this is just moving the responsibility of maintaining it from pytauri to tauri, and I don't think anyone on the team really wants to do it...

I don't know how feasible is it, but I think it might be better/easier to move out Context and its fields to a shared crate (maybe tauri-utils) and implement quote::ToTokens, then change the code inside tauri-codegen to 2 parts, one part generates the Context and another part quote! it to TokenStream that the macro could use, and then you can use the one generated from the first part directly

Legend-Master avatar Jun 02 '25 14:06 Legend-Master

To be honest, this is just moving the responsibility of maintaining it from pytauri to tauri, and I don't think anyone on the team really wants to do it...

I would argue that if Tauri wants to support bindings for other languages, it must provide a way to configure at runtime. Otherwise:

Each user has their own configuration → their own tauri.conf.json → needs to be converted into a runtime-usable Context by the Rust compiler (tauri-codegen) → every user needs the Rust compiler (even if they're using bindings for other languages) → users will complain, "If I need the Rust compiler anyway, why not just write Rust directly?" 🤔

Moreover, both Qt and CEF provide runtime configuration, allowing them to be compiled as dynamic libraries. If Tauri doesn't make changes, it can only be used as an executable.

WSH032 avatar Jun 02 '25 14:06 WSH032

I do really want to support using another language binding without the rust compiler, and that's why I suggested that we change the codegen to generate the Context instead just of rust source code, that way, you can just ship that code, and then generate the Context dynamically at runtime

Legend-Master avatar Jun 02 '25 14:06 Legend-Master

In fact, I think the context should only be used to control runtime behavior, and should not be used for embedding assets.

Ideally, we should split tauri.conf.json into two parts: one solely for controlling build-time behavior, and the other solely for controlling runtime behavior. This is why I said that build configuration should only be controlled by BuildConfig.

static embedded_assets:  {
    icon_bytes: &[u8],
    plugin_global_api_scripts: &[u8],
    // ...
} = generate_embedded_assets!();

let context: Context = serde::from_str(include_str!("tauri.runtime-conf.json"));

Builder::default()
    .embedded_assets(Some(embedded_assets))
    .runtime_context(context)

You should specify in the Context whether you want to use embedded assets or runtime assets. The Builder should initialize the app by calling existing tauri api based on the provided Context (used only for configuration), rather than relying on macros to dynamically generate initialization rust code.

impl Builder {
    fn init(self) {
        if self.runtime_context.use_embedded_assets {
            app.set_icon(Image::from_bytes(embedded_assets.icon_bytes));
        } else {
            self.set_icon(Image::from_path(self.runtime_context.icon_path));
        }
    }
}

WSH032 avatar Jun 02 '25 16:06 WSH032

I like the idea of splitting them up so it's clear which one is used in build and which one is used at runtime

The Builder should initialize the app by calling existing tauri api based on the provided Context (used only for configuration), rather than relying on macros to dynamically generate initialization rust code.

The method that I suggested is just basically moving this to tauri-codegen, and let it produce the Context instead of just rust code, so if you want to generate the Context at runtime, you can

And if you would like to consume it not through tauri-codegen, but through tauri, we can gate that in a feature and re-export them, so we don't have so much duplicated code, we might also want to enable it in dev for faster compile speed by moving them to runtime

Legend-Master avatar Jun 03 '25 04:06 Legend-Master

You should specify in the Context whether you want to use embedded assets or runtime assets.

I believe this is only for your currently implementation of pytauri, if we have the Context generation as a function (instead of a macro that generates the rust code), you can just do that in the runtime, and swap to use your own Assets implementation

For example, currently you do:

  1. Context generation at your library's build time
  2. Modify this context at runtime based on library consumer's configs

What we can do if that's a function:

  1. Ship the context generation code
  2. Generate this context at runtime based on library consumer's configs

And there's no need for

        if self.runtime_context.use_embedded_assets {
            app.set_icon(Image::from_bytes(embedded_assets.icon_bytes));
        } else {
            self.set_icon(Image::from_path(self.runtime_context.icon_path));
        }

Legend-Master avatar Jun 03 '25 04:06 Legend-Master

The method that I suggested is just basically moving this to tauri-codegen, and let it produce the Context instead of just rust code, so if you want to generate the Context at runtime, you can

What we can do if that's a function:

  1. Ship the context generation code
  2. Generate this context at runtime based on library consumer's configs

Sorry, I don't quite understand. Could you provide some pseudocode to describe how users/downstream consumers would use this new API?

WSH032 avatar Jun 03 '25 04:06 WSH032

So currently, we have

https://github.com/tauri-apps/tauri/blob/a472d51f683eea040fe68aadc92210f470bdaa6f/crates/tauri-codegen/src/context.rs#L134

And we change it to pub fn context_codegen(data: ContextData) -> EmbeddedAssetsResult<Context> {}, and then you can use this function to generate the context directly

Legend-Master avatar Jun 03 '25 05:06 Legend-Master