Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal]: Modular core APIs #3029

Closed
JonasKruckenberg opened this issue Dec 6, 2021 · 14 comments
Closed

[Proposal]: Modular core APIs #3029

JonasKruckenberg opened this issue Dec 6, 2021 · 14 comments
Labels
status: needs more info Issue needs more information, discussion or reproducible example type: breaking change This issue or pull request will introduce a breaking change and requires major version bump type: feature request

Comments

@JonasKruckenberg
Copy link
Member

JonasKruckenberg commented Dec 6, 2021

This idea is in a very early stage, please contribute by leaving questions and ideas!

Is your feature request related to a problem? Please describe.
The backend currently has two different ways of exposing ApIs to the frontend: Commands (and Plugins) as well as the core APIs. Commands are very modular while the core APIs are not.

Describe the solution you'd like
Modularizing the core api using a similar system to #2959, inspired by deno's extensions.
So a tauri app could look like this:

let plugins = vec![
   tauri::api::fs::init(),
   tauri::api::path::init()
];

tauri::Builder::default()
   .plugins(plugins)
   .build(tauri::generate_context!())
   .expect("error while building tauri application");

Why?:

  1. In-code configuration.
    When reading the code it's immediately obvious what APIs are available to the frontend.
    The current allowlist system split's feature configuration between the app, the Cargo.toml file and the tauri.conf.json file.
    There is also no opportunity to add comments in the tauri.conf.json file, where dev could explain why an API is enabled.
  2. No feature flags.
    Tauri apps would be as slim as possible without the copious amounts of feature flags we employ right now. (Of course more involved features like systray would still use them on top)
    This makes the cli waay simpler and less error prone.
  3. Capabilities.
    The init function is a very natural way to pass capabilities to APIs enabling capability oriented design.
  4. A clear path for new APIs.
    @amrbashir pioneered this with the vibrancy plugin. Similar to rust itself, we could develop new APIs in separately versioned plugins, that can be iterated upon more easily. Once they reached sufficient stability can be merged into the core. This is maybe the most compelling reason IMO.
  5. A clear path for old APIs.
    Core APIs can be deprecated and still be accessible to users who didn't upgrade yet, while not taking up space for users who did. (I could see withGlobalTauri going this route for example. It would still be there for users who need it, but would never end up in the binary for users who don't)

Open Questions

  • Would the name plugin still be applicable to this new system?
  • How do users tell the tauri::Builder about plugins?
  • Does tauri::Builder::default() come with default plugins?
  • Are there core plugins that will not be modular (i.e. enabled by default)?
@lucasfernog
Copy link
Member

There's one downside going with this approach and removing the allowlist entirely: people need to touch the Rust code to enable APIs, and a lot of users are scared of it.

@lucasfernog
Copy link
Member

But turning the APIs into plugins is something I have in mind for quite some time, specially since it's the only way to have an allowlist when we have bindings (each core plugin could have its own binding, then e.g. a Deno user can install each plugin individually).

@amrbashir
Copy link
Member

amrbashir commented Dec 6, 2021

There's one downside going with this approach and removing the allowlist entirely: people need to touch the Rust code to enable APIs, and a lot of users are scared of it.

can't the allowlist include the plugins init calls ? like have a top-level tauri::include_apis!() macro ? kinda like how windows-rs used a similar macro to generate and include the apis

@JonasKruckenberg
Copy link
Member Author

JonasKruckenberg commented Dec 6, 2021

There's one downside going with this approach and removing the allowlist entirely: people need to touch the Rust code to enable APIs, and a lot of users are scared of it.

Do you think it is that bad? Adding plugins to a vec doesn't touch lifetimes or any other part of rust that people find scary 🤔
But I get the concern, maybe a macro could help here, yes!

Or: tauri init adds the vec snippet to the main function with all the apis "pre-filled" so rust-newcomers would just need to remove lines they don't want 🤔

@probablykasper
Copy link
Member

If there are no feature flags, will Rust skip the unused dependencies when compiling?

Definitely would like to specify the allowlist in code, and avoid tauri writing feature flags to Cargo.toml

@JonasKruckenberg
Copy link
Member Author

JonasKruckenberg commented Dec 10, 2021

If there are no feature flags, will Rust skip the unused dependencies when compiling?

Yes, of course! Rust binaries are large, but without dead code elimination and other optimizations the size would be measured in gigabytes 😉
I will do a mvp of this next week and we can go from there!

@nothingismagick
Copy link
Member

Definitely would like to specify the allowlist in code, and avoid tauri writing feature flags to Cargo.toml

I think this is actually an antipattern to be honest. Having your configuration in exactly one place makes it auditable. If you can set this kind of thing anywhere in code, then where do you look to know what you have set?

@JonasKruckenberg
Copy link
Member Author

JonasKruckenberg commented Dec 10, 2021

I think this is actually an antipattern to be honest. Having your configuration in exactly one place makes it auditable. If you can set this kind of thing anywhere in code, then where do you look to know what you have set?

Totally agree, having the config in one place is good and the closer we can get to that the better.
That said, configuration of a tauri app is already split between main.rs and tauri.conf.json right now and as a user I'd rather have all configuration in rust code where I can add comments and the like at the expense of simplicity 🤔

But I know that a lot of people interested in/using tauri don't know rust and making the project accessible is important.
The question is how do we archive this; and imo we should provide easy-to-use APIs, so on-ramps into rust rather than avoiding rust through custom config tooling

@amrbashir
Copy link
Member

I think this is actually an antipattern to be honest. Having your configuration in exactly one place makes it auditable. If you can set this kind of thing anywhere in code, then where do you look to know what you have set?

Actually it can be in one place in rust, with the proposed API, all plugins (user defined) and core plugins (our plugins proposed in this issue) can only be passed through tauri::Builder::plugins() in main.rs.

@jquesada2016
Copy link

I think the point brought up about users having to touch Rust code is very daunting, even if it a very simple operation. I think the option for users to choose one system over another is preferable. So for example, have the project when initialized, include the allowList in the config file. In the main code, we could have a macro for the plugins portion, something link include_from_config!(),
This way, if a user would rather use the init pattern, they can just remove the macro call and go from there.

Another important note, if we wanted to go with the above route, of allowing users to choose, it would be a very good idea to emit an info message to the console so the user knows which of the two methods are being used, and thus avoid confusion. This or just emit a warning, if for example, the user opts out of using the config file, but still has the allowList key in their config file.

But I 100% love the idea of modularizing the core API's.

@JonasKruckenberg
Copy link
Member Author

JonasKruckenberg commented Jan 21, 2022

As a notice to anyone coming along, work on this will continue after the release of v1.

But just for context (and so I can remember later) I like the idea of a macro that pulls in the tauri.conf.json and compiles down to calls to the modular APIs under the hood.

@jsejcksn
Copy link

configuration of a tauri app is already split between main.rs and tauri.conf.json right now and as a user I'd rather have all configuration in rust code where I can add comments and the like

I like the idea of a macro that pulls in the tauri.conf.json and compiles down to calls to the modular APIs under the hood

@JonasKruckenberg If comments are a desirable feature, is JSONC an option for the config file?

@FabianLars
Copy link
Member

rc.0 introduced JSON5 support for the conf file in February :)

@lucasfernog lucasfernog added status: needs more info Issue needs more information, discussion or reproducible example type: feature request type: breaking change This issue or pull request will introduce a breaking change and requires major version bump and removed status: needs discussion labels Jul 1, 2022
@lucasfernog
Copy link
Member

With the migration of the API endpoints to separated plugins this has been implemented (though there's a lot more we can do, which are tracked in other issues).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs more info Issue needs more information, discussion or reproducible example type: breaking change This issue or pull request will introduce a breaking change and requires major version bump type: feature request
Projects
None yet
Development

No branches or pull requests

8 participants