Просмотр исходного кода

feat(core): allow swapping the assets implementation (#9141)

Lucas Fernandes Nogueira 1 год назад
Родитель
Сommit
ba0206d8a3

+ 6 - 0
.changes/codegen-set-assets.md

@@ -0,0 +1,6 @@
+---
+"tauri-macros": patch:feat
+"tauri-codegen": patch:feat
+---
+
+The `Context` codegen now accepts a `assets` input to define a custom `tauri::Assets` implementation.

+ 5 - 0
.changes/context-assets-unbox.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch:breaking
+---
+
+`Context::assets` now returns `&dyn Assets` instead of `Box<&dyn Assets>`.

+ 5 - 0
.changes/context-remove-assets-generics.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch:breaking
+---
+
+The `Context` type no longer uses the `<A: Assets>` generic so the assets implementation can be swapped with `Context::assets_mut`.

+ 1 - 0
core/tauri-build/src/codegen/context.rs

@@ -128,6 +128,7 @@ impl CodegenContext {
       // outside the tauri crate, making the ::tauri root valid.
       root: quote::quote!(::tauri),
       capabilities: self.capabilities,
+      assets: None,
     })?;
 
     // get the full output file path

+ 12 - 4
core/tauri-codegen/src/context.rs

@@ -12,6 +12,7 @@ use proc_macro2::TokenStream;
 use quote::quote;
 use sha2::{Digest, Sha256};
 
+use syn::Expr;
 use tauri_utils::acl::capability::{Capability, CapabilityFile};
 use tauri_utils::acl::manifest::Manifest;
 use tauri_utils::acl::resolved::Resolved;
@@ -36,6 +37,8 @@ pub struct ContextData {
   pub root: TokenStream,
   /// Additional capabilities to include.
   pub capabilities: Option<Vec<PathBuf>>,
+  /// The custom assets implementation
+  pub assets: Option<Expr>,
 }
 
 fn inject_script_hashes(document: &NodeRef, key: &AssetKey, csp_hashes: &mut CspHashes) {
@@ -132,6 +135,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
     config_parent,
     root,
     capabilities: additional_capabilities,
+    assets,
   } = data;
 
   let target = std::env::var("TARGET")
@@ -163,10 +167,13 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
     options = options.with_csp();
   }
 
-  let assets = if dev && config.build.dev_url.is_some() {
-    Default::default()
+  let assets = if let Some(assets) = assets {
+    quote!(#assets)
+  } else if dev && config.build.dev_url.is_some() {
+    let assets = EmbeddedAssets::default();
+    quote!(#assets)
   } else {
-    match &config.build.frontend_dist {
+    let assets = match &config.build.frontend_dist {
       Some(url) => match url {
         FrontendDist::Url(_url) => Default::default(),
         FrontendDist::Directory(path) => {
@@ -190,7 +197,8 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
         _ => unimplemented!(),
       },
       None => Default::default(),
-    }
+    };
+    quote!(#assets)
   };
 
   let out_dir = {

+ 40 - 24
core/tauri-macros/src/context.rs

@@ -17,6 +17,7 @@ pub(crate) struct ContextItems {
   config_file: PathBuf,
   root: syn::Path,
   capabilities: Option<Vec<PathBuf>>,
+  assets: Option<Expr>,
 }
 
 impl Parse for ContextItems {
@@ -29,6 +30,7 @@ impl Parse for ContextItems {
 
     let mut root = None;
     let mut capabilities = None;
+    let mut assets = None;
     let config_file = input.parse::<LitStr>().ok().map(|raw| {
       let _ = input.parse::<Token![,]>();
       let path = PathBuf::from(raw.value());
@@ -57,32 +59,44 @@ impl Parse for ContextItems {
           root.replace(p);
         }
         Meta::NameValue(v) => {
-          if *v.path.require_ident()? == "capabilities" {
-            if let Expr::Array(array) = v.value {
-              capabilities.replace(
-                array
-                  .elems
-                  .into_iter()
-                  .map(|e| {
-                    if let Expr::Lit(ExprLit {
-                      attrs: _,
-                      lit: Lit::Str(s),
-                    }) = e
-                    {
-                      Ok(s.value().into())
-                    } else {
-                      Err(syn::Error::new(
-                        input.span(),
-                        "unexpected expression for capability",
-                      ))
-                    }
-                  })
-                  .collect::<Result<Vec<_>, syn::Error>>()?,
-              );
-            } else {
+          let ident = v.path.require_ident()?;
+          match ident.to_string().as_str() {
+            "capabilities" => {
+              if let Expr::Array(array) = v.value {
+                capabilities.replace(
+                  array
+                    .elems
+                    .into_iter()
+                    .map(|e| {
+                      if let Expr::Lit(ExprLit {
+                        attrs: _,
+                        lit: Lit::Str(s),
+                      }) = e
+                      {
+                        Ok(s.value().into())
+                      } else {
+                        Err(syn::Error::new(
+                          input.span(),
+                          "unexpected expression for capability",
+                        ))
+                      }
+                    })
+                    .collect::<Result<Vec<_>, syn::Error>>()?,
+                );
+              } else {
+                return Err(syn::Error::new(
+                  input.span(),
+                  "unexpected value for capabilities",
+                ));
+              }
+            }
+            "assets" => {
+              assets.replace(v.value);
+            }
+            name => {
               return Err(syn::Error::new(
                 input.span(),
-                "unexpected value for capabilities",
+                format!("unknown attribute {name}"),
               ));
             }
           }
@@ -113,6 +127,7 @@ impl Parse for ContextItems {
         }
       }),
       capabilities,
+      assets,
     })
   }
 }
@@ -126,6 +141,7 @@ pub(crate) fn generate_context(context: ContextItems) -> TokenStream {
       config_parent,
       root: context.root.to_token_stream(),
       capabilities: context.capabilities,
+      assets: context.assets,
     })
     .and_then(|data| context_codegen(data).map_err(|e| e.to_string()));
 

+ 3 - 3
core/tauri/src/app.rs

@@ -19,7 +19,7 @@ use crate::{
   },
   sealed::{ManagerBase, RuntimeOrDispatch},
   utils::config::Config,
-  utils::{assets::Assets, Env},
+  utils::Env,
   webview::PageLoadPayload,
   Context, DeviceEventFilter, EventLoopMessage, Manager, Monitor, Runtime, Scopes, StateManager,
   Theme, Webview, WebviewWindowBuilder, Window,
@@ -1581,7 +1581,7 @@ tauri::Builder::default()
     feature = "tracing",
     tracing::instrument(name = "app::build", skip_all)
   )]
-  pub fn build<A: Assets>(mut self, context: Context<A>) -> crate::Result<App<R>> {
+  pub fn build(mut self, context: Context) -> crate::Result<App<R>> {
     #[cfg(target_os = "macos")]
     if self.menu.is_none() && self.enable_macos_default_menu {
       self.menu = Some(Box::new(|app_handle| {
@@ -1749,7 +1749,7 @@ tauri::Builder::default()
   }
 
   /// Runs the configured Tauri application.
-  pub fn run<A: Assets>(self, context: Context<A>) -> crate::Result<()> {
+  pub fn run(self, context: Context) -> crate::Result<()> {
     self.build(context)?.run(|_, _| {});
     Ok(())
   }

+ 8 - 8
core/tauri/src/lib.rs

@@ -343,9 +343,9 @@ pub fn dev() -> bool {
 /// # Stability
 /// This is the output of the [`generate_context`] macro, and is not considered part of the stable API.
 /// Unless you know what you are doing and are prepared for this type to have breaking changes, do not create it yourself.
-pub struct Context<A: Assets> {
+pub struct Context {
   pub(crate) config: Config,
-  pub(crate) assets: Box<A>,
+  pub(crate) assets: Box<dyn Assets>,
   pub(crate) default_window_icon: Option<image::Image<'static>>,
   pub(crate) app_icon: Option<Vec<u8>>,
   #[cfg(all(desktop, feature = "tray-icon"))]
@@ -356,7 +356,7 @@ pub struct Context<A: Assets> {
   pub(crate) runtime_authority: RuntimeAuthority,
 }
 
-impl<A: Assets> fmt::Debug for Context<A> {
+impl fmt::Debug for Context {
   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     let mut d = f.debug_struct("Context");
     d.field("config", &self.config)
@@ -372,7 +372,7 @@ impl<A: Assets> fmt::Debug for Context<A> {
   }
 }
 
-impl<A: Assets> Context<A> {
+impl Context {
   /// The config the application was prepared with.
   #[inline(always)]
   pub fn config(&self) -> &Config {
@@ -387,13 +387,13 @@ impl<A: Assets> Context<A> {
 
   /// The assets to be served directly by Tauri.
   #[inline(always)]
-  pub fn assets(&self) -> &A {
-    &self.assets
+  pub fn assets(&self) -> &dyn Assets {
+    self.assets.as_ref()
   }
 
   /// A mutable reference to the assets to be served directly by Tauri.
   #[inline(always)]
-  pub fn assets_mut(&mut self) -> &mut A {
+  pub fn assets_mut(&mut self) -> &mut Box<dyn Assets> {
     &mut self.assets
   }
 
@@ -459,7 +459,7 @@ impl<A: Assets> Context<A> {
   #[allow(clippy::too_many_arguments)]
   pub fn new(
     config: Config,
-    assets: Box<A>,
+    assets: Box<dyn Assets>,
     default_window_icon: Option<image::Image<'static>>,
     app_icon: Option<Vec<u8>>,
     package_info: PackageInfo,

+ 1 - 1
core/tauri/src/manager/mod.rs

@@ -216,7 +216,7 @@ impl<R: Runtime> fmt::Debug for AppManager<R> {
 impl<R: Runtime> AppManager<R> {
   #[allow(clippy::too_many_arguments, clippy::type_complexity)]
   pub(crate) fn with_handlers(
-    #[allow(unused_mut)] mut context: Context<impl Assets>,
+    #[allow(unused_mut)] mut context: Context,
     plugins: PluginStore<R>,
     invoke_handler: Box<InvokeHandler<R>>,
     on_page_load: Option<Arc<OnPageLoad<R>>>,

+ 1 - 1
core/tauri/src/test/mod.rs

@@ -94,7 +94,7 @@ pub fn noop_assets() -> NoopAsset {
 }
 
 /// Creates a new [`crate::Context`] for testing.
-pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
+pub fn mock_context<A: Assets>(assets: A) -> crate::Context {
   Context {
     config: Config {
       schema: None,

+ 1 - 1
examples/splashscreen/main.rs

@@ -78,7 +78,7 @@ mod ui {
   }
 }
 
-fn context() -> tauri::Context<tauri::utils::assets::EmbeddedAssets> {
+fn context() -> tauri::Context {
   tauri::generate_context!("../../examples/splashscreen/tauri.conf.json")
 }