Explorar el Código

feat: build without proc macros (#1226)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
chip hace 4 años
padre
commit
c88838aa76
Se han modificado 100 ficheros con 637 adiciones y 79 borrados
  1. 0 3
      .gitignore
  2. 17 3
      Cargo.toml
  3. 4 2
      cli/core/src/build/rust.rs
  4. 14 9
      cli/tauri.js/src/template/index.ts
  5. 5 5
      cli/tauri.js/templates/src-tauri/Cargo.toml
  6. 1 14
      cli/tauri.js/templates/src-tauri/src/build.rs
  7. 3 7
      cli/tauri.js/templates/src-tauri/src/main.rs
  8. 4 6
      cli/tauri.js/test/jest/fixtures/app/src-tauri/src/main.rs
  9. 30 0
      core/tauri-build/Cargo.toml
  10. 134 0
      core/tauri-build/src/codegen/context.rs
  11. 1 0
      core/tauri-build/src/codegen/mod.rs
  12. 56 0
      core/tauri-build/src/lib.rs
  13. 20 0
      core/tauri-codegen/Cargo.toml
  14. 69 0
      core/tauri-codegen/src/context.rs
  15. 135 0
      core/tauri-codegen/src/embedded_assets.rs
  16. 80 0
      core/tauri-codegen/src/lib.rs
  17. 0 0
      examples/api/.gitignore
  18. 0 0
      examples/api/README.md
  19. 2 2
      examples/api/package.json
  20. 0 0
      examples/api/public/__tauri.js
  21. 0 0
      examples/api/public/build/bundle.js
  22. 0 0
      examples/api/public/build/bundle.js.map
  23. 0 0
      examples/api/public/favicon.png
  24. 0 0
      examples/api/public/global.css
  25. 0 0
      examples/api/public/icon.png
  26. 0 0
      examples/api/public/index.html
  27. 0 0
      examples/api/rollup.config.js
  28. 0 0
      examples/api/screenshot.png
  29. 0 0
      examples/api/src-tauri/.gitignore
  30. 17 0
      examples/api/src-tauri/Cargo.toml
  31. 3 0
      examples/api/src-tauri/build.rs
  32. 0 0
      examples/api/src-tauri/icons/128x128.png
  33. 0 0
      examples/api/src-tauri/icons/128x128@2x.png
  34. 0 0
      examples/api/src-tauri/icons/32x32.png
  35. 0 0
      examples/api/src-tauri/icons/Square107x107Logo.png
  36. 0 0
      examples/api/src-tauri/icons/Square142x142Logo.png
  37. 0 0
      examples/api/src-tauri/icons/Square150x150Logo.png
  38. 0 0
      examples/api/src-tauri/icons/Square284x284Logo.png
  39. 0 0
      examples/api/src-tauri/icons/Square30x30Logo.png
  40. 0 0
      examples/api/src-tauri/icons/Square310x310Logo.png
  41. 0 0
      examples/api/src-tauri/icons/Square44x44Logo.png
  42. 0 0
      examples/api/src-tauri/icons/Square71x71Logo.png
  43. 0 0
      examples/api/src-tauri/icons/Square89x89Logo.png
  44. 0 0
      examples/api/src-tauri/icons/StoreLogo.png
  45. 0 0
      examples/api/src-tauri/icons/icon.icns
  46. 0 0
      examples/api/src-tauri/icons/icon.ico
  47. 0 0
      examples/api/src-tauri/icons/icon.png
  48. 0 0
      examples/api/src-tauri/src/cmd.rs
  49. 4 6
      examples/api/src-tauri/src/main.rs
  50. 0 0
      examples/api/src-tauri/tauri.conf.json
  51. 0 0
      examples/api/src/App.svelte
  52. 0 0
      examples/api/src/components/Cli.svelte
  53. 0 0
      examples/api/src/components/Communication.svelte
  54. 0 0
      examples/api/src/components/Dialog.svelte
  55. 0 0
      examples/api/src/components/FileSystem.svelte
  56. 0 0
      examples/api/src/components/Http.svelte
  57. 0 0
      examples/api/src/components/Notifications.svelte
  58. 0 0
      examples/api/src/components/Shortcuts.svelte
  59. 0 0
      examples/api/src/components/Window.svelte
  60. 0 0
      examples/api/src/main.js
  61. 3 2
      examples/api/yarn.lock
  62. 0 0
      examples/helloworld/package.json
  63. 0 0
      examples/helloworld/public/__tauri.js
  64. 0 0
      examples/helloworld/public/index.html
  65. 0 0
      examples/helloworld/src-tauri/.gitignore
  66. 5 13
      examples/helloworld/src-tauri/Cargo.toml
  67. 4 0
      examples/helloworld/src-tauri/build.rs
  68. 0 0
      examples/helloworld/src-tauri/icons/128x128.png
  69. 0 0
      examples/helloworld/src-tauri/icons/128x128@2x.png
  70. 0 0
      examples/helloworld/src-tauri/icons/32x32.png
  71. 0 0
      examples/helloworld/src-tauri/icons/Square107x107Logo.png
  72. 0 0
      examples/helloworld/src-tauri/icons/Square142x142Logo.png
  73. 0 0
      examples/helloworld/src-tauri/icons/Square150x150Logo.png
  74. 0 0
      examples/helloworld/src-tauri/icons/Square284x284Logo.png
  75. 0 0
      examples/helloworld/src-tauri/icons/Square30x30Logo.png
  76. 0 0
      examples/helloworld/src-tauri/icons/Square310x310Logo.png
  77. 0 0
      examples/helloworld/src-tauri/icons/Square44x44Logo.png
  78. 0 0
      examples/helloworld/src-tauri/icons/Square71x71Logo.png
  79. 0 0
      examples/helloworld/src-tauri/icons/Square89x89Logo.png
  80. 0 0
      examples/helloworld/src-tauri/icons/StoreLogo.png
  81. 0 0
      examples/helloworld/src-tauri/icons/icon.icns
  82. 0 0
      examples/helloworld/src-tauri/icons/icon.ico
  83. 0 0
      examples/helloworld/src-tauri/icons/icon.png
  84. 4 7
      examples/helloworld/src-tauri/src/main.rs
  85. 0 0
      examples/helloworld/src-tauri/tauri.conf.json
  86. 0 0
      examples/multiwindow/dist/__tauri.js
  87. 0 0
      examples/multiwindow/dist/index.html
  88. 0 0
      examples/multiwindow/package.json
  89. 0 0
      examples/multiwindow/src-tauri/.gitignore
  90. 18 0
      examples/multiwindow/src-tauri/Cargo.toml
  91. 4 0
      examples/multiwindow/src-tauri/build.rs
  92. 0 0
      examples/multiwindow/src-tauri/icons/128x128.png
  93. 0 0
      examples/multiwindow/src-tauri/icons/128x128@2x.png
  94. 0 0
      examples/multiwindow/src-tauri/icons/32x32.png
  95. 0 0
      examples/multiwindow/src-tauri/icons/Square107x107Logo.png
  96. 0 0
      examples/multiwindow/src-tauri/icons/Square142x142Logo.png
  97. 0 0
      examples/multiwindow/src-tauri/icons/Square150x150Logo.png
  98. 0 0
      examples/multiwindow/src-tauri/icons/Square284x284Logo.png
  99. 0 0
      examples/multiwindow/src-tauri/icons/Square30x30Logo.png
  100. 0 0
      examples/multiwindow/src-tauri/icons/Square310x310Logo.png

+ 0 - 3
.gitignore

@@ -85,8 +85,5 @@ target
 # todo: needs a proper fic
 /cli/tauri.js/tauri.conf.js
 
-# doing this because the task-runner (`mask prepare`) will clone gh:tauri-apps/examples
-/examples
-
 # ignore frida handlers
 __handlers__/

+ 17 - 3
Cargo.toml

@@ -4,7 +4,21 @@ members = [
   "tauri-api",
   "tauri-macros",
   "tauri-utils",
+
+  # core
+  "core/tauri-build",
+  "core/tauri-codegen",
+
+  # examples
+  "examples/api/src-tauri",
+  "examples/helloworld/src-tauri",
+  "examples/multiwindow/src-tauri",
 ]
-exclude = [
-  "examples",
-]
+
+# default to small, optimized workspace release binaries
+[profile.release]
+panic = "abort"
+codegen-units = 1
+lto = true
+incremental = false
+opt-level = "s"

+ 4 - 2
cli/core/src/build/rust.rs

@@ -135,8 +135,10 @@ pub fn get_bundler_settings(config: &Config, debug: bool) -> crate::Result<Bundl
     }
   }
 
-  if binaries.len() == 1 {
-    binaries.get_mut(0).unwrap().set_main(true);
+  match binaries.len() {
+    0 => binaries.push(BundleBinary::new(package.name.clone(), true)),
+    1 => binaries.get_mut(0).unwrap().set_main(true),
+    _ => {}
   }
 
   Ok(BundlerSettings {

+ 14 - 9
cli/tauri.js/src/template/index.ts

@@ -77,29 +77,34 @@ Run \`tauri init --force template\` to overwrite.`)
     if (!force) return false
   }
 
-  const resolveTauriPath = (tauriPath: string): string => {
+  const resolveTauriPath = (tauriPath: string, crate: string): string => {
     const resolvedPath = isAbsolute(tauriPath)
-      ? join(tauriPath, 'tauri') // we received a full path as argument
-      : join('..', tauriPath, 'tauri') // we received a relative path
+      ? join(tauriPath, crate) // we received a full path as argument
+      : join('..', tauriPath, crate) // we received a relative path
     return resolvedPath.replace(/\\/g, '/')
   }
 
-  const resolveCurrentTauriVersion = (): string => {
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access
-    const tauriManifest = require('../../../../tauri/Cargo.toml') as CargoManifest
+  const resolveCurrentTauriVersion = (crate: string): string => {
+    const manifestPath = `../../../../${crate}/Cargo.toml`
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access, security/detect-non-literal-require
+    const tauriManifest = require(manifestPath) as CargoManifest
     const version = tauriManifest.package.version
     return version.substring(0, version.lastIndexOf('.'))
   }
 
   const tauriDep = tauriPath
-    ? `{ path = "${resolveTauriPath(tauriPath)}" }`
-    : `{ version = "${resolveCurrentTauriVersion()}" }`
+    ? `{ path = "${resolveTauriPath(tauriPath, 'tauri')}" }`
+    : `{ version = "${resolveCurrentTauriVersion('tauri')}" }`
+  const tauriBuildDep = tauriPath
+    ? `{ path = "${resolveTauriPath(tauriPath, 'core/tauri-build')}" }`
+    : `{ version = "${resolveCurrentTauriVersion('core/tauri-build')}" }`
 
   removeSync(dir)
   copyTemplates({
     source: resolve(__dirname, '../../templates/src-tauri'),
     scope: {
-      tauriDep
+      tauriDep,
+      tauriBuildDep
     },
     target: dir
   })

+ 5 - 5
cli/tauri.js/templates/src-tauri/Cargo.toml

@@ -11,17 +11,17 @@ build = "src/build.rs"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
+[build-dependencies]
+tauri-build = <%= tauriBuildDep %>
+
 [dependencies]
 serde_json = "1.0"
 serde = { version = "1.0", features = ["derive"] }
-tauri = <%= tauriDep || `{ version = "0.5" }` %>
+tauri = <%= tauriDep %>
 
 [target."cfg(windows)".build-dependencies]
 winres = "0.1"
 
 [features]
+default = [ "custom-protocol" ]
 custom-protocol = [ "tauri/custom-protocol" ]
-
-[[bin]]
-name = "app"
-path = "src/main.rs"

+ 1 - 14
cli/tauri.js/templates/src-tauri/src/build.rs

@@ -1,16 +1,3 @@
-#[cfg(windows)]
-extern crate winres;
-
-#[cfg(windows)]
 fn main() {
-  if std::path::Path::new("icons/icon.ico").exists() {
-    let mut res = winres::WindowsResource::new();
-    res.set_icon_with_id("icons/icon.ico", "32512");
-    res.compile().expect("Unable to find visual studio tools");
-  } else {
-    panic!("No Icon.ico found. Please add one or check the path");
-  }
+  tauri_build::build()
 }
-
-#[cfg(not(windows))]
-fn main() {}

+ 3 - 7
cli/tauri.js/templates/src-tauri/src/main.rs

@@ -3,12 +3,8 @@
   windows_subsystem = "windows"
 )]
 
-#[derive(tauri::FromTauriContext)]
-struct Context;
-
 fn main() {
-  tauri::AppBuilder::<Context>::new()
-    .build()
-    .unwrap()
-    .run();
+  let context = tauri::generate_tauri_context!();
+
+  tauri::AppBuilder::default().build(context).run();
 }

+ 4 - 6
cli/tauri.js/test/jest/fixtures/app/src-tauri/src/main.rs

@@ -1,10 +1,9 @@
 use tauri::ApplicationDispatcherExt;
 
-#[derive(tauri::FromTauriContext)]
-struct Context;
-
 fn main() {
-  tauri::AppBuilder::<tauri::flavors::Wry, Context>::new()
+  let context = tauri::generate_tauri_context!();
+
+  tauri::AppBuilder::default()
     .setup(|webview_manager| async move {
       let mut webview_manager_ = webview_manager.clone();
       tauri::event::listen(String::from("hello"), move |_| {
@@ -24,7 +23,6 @@ fn main() {
         webview_manager.close().unwrap();
       }
     })
-    .build()
-    .unwrap()
+    .build(context)
     .run();
 }

+ 30 - 0
core/tauri-build/Cargo.toml

@@ -0,0 +1,30 @@
+[package]
+name = "tauri-build"
+version = "0.1.0"
+authors = [ "Tauri Community" ]
+categories = [ "gui", "web-programming" ]
+license = "MIT"
+homepage = "https://tauri.studio"
+repository = "https://github.com/tauri-apps/tauri/tree/dev/core/tauri-build"
+description = "build time code to pair with https://crates.io/crates/tauri"
+edition = "2018"
+
+[dependencies]
+anyhow = "1"
+
+# context dependencies
+proc-macro2 = "1"
+quote = "1"
+tauri-codegen = { path = "../tauri-codegen", optional = true }
+
+[target."cfg(windows)".dependencies]
+winres = "0.1"
+
+[features]
+# keep context non-default to prevent some relatively large deps being pulled
+codegen = ["tauri-codegen"]
+
+# enable feature flags on https://docs.rs/tauri-build
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "doc_cfg"]

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

@@ -0,0 +1,134 @@
+use anyhow::{Context, Result};
+use proc_macro2::Ident;
+use quote::format_ident;
+use std::{
+  env::var,
+  fs::{create_dir_all, File},
+  io::{BufWriter, Write},
+  path::PathBuf,
+};
+use tauri_codegen::{context_codegen, ContextData};
+
+/// A builder for generating a Tauri application context during compile time.
+///
+/// Meant to be used with [`tauri::include_codegen_context!`] inside your application code.
+///
+/// [`tauri::include_codegen_context!`]: https://docs.rs/tauri/0.12/tauri/macro.include_codegen_context.html
+#[cfg_attr(doc_cfg, doc(cfg(feature = "codegen")))]
+#[derive(Debug)]
+pub struct CodegenContext {
+  config_path: PathBuf,
+  struct_ident: Ident,
+  out_file: PathBuf,
+}
+
+impl Default for CodegenContext {
+  fn default() -> Self {
+    Self {
+      config_path: PathBuf::from("tauri.conf.json"),
+      struct_ident: format_ident!("TauriBuildCodegenContext"),
+      out_file: PathBuf::from("tauri-build-context.rs"),
+    }
+  }
+}
+
+impl CodegenContext {
+  /// Create a new [`CodegenContext`] builder that is already filled with the default options.
+  pub fn new() -> Self {
+    Self::default()
+  }
+
+  /// Set the path to the `tauri.conf.json` (relative to the package's directory).
+  ///
+  /// This defaults to a file called `tauri.conf.json` inside of the current working directory of
+  /// the package compiling; does not need to be set manually if that config file is in the same
+  /// directory as your `Cargo.toml`.
+  pub fn config_path(mut self, config_path: impl Into<PathBuf>) -> Self {
+    self.config_path = config_path.into();
+    self
+  }
+
+  /// Set the name of the generated struct.
+  ///
+  /// Don't set this if you are using [`tauri::include_codegen_context!`] as that helper macro
+  /// expects the default value. This option can be useful if you are not using the helper and
+  /// instead using [`std::include!`] on the generated code yourself.
+  ///
+  /// Defaults to `TauriBuildCodegenContext`.
+  ///
+  /// [`tauri::include_codegen_context!`]: https://docs.rs/tauri/0.12/tauri/macro.include_codegen_context.html
+  pub fn struct_ident(mut self, ident: impl AsRef<str>) -> Self {
+    self.struct_ident = format_ident!("{}", ident.as_ref());
+    self
+  }
+
+  /// Sets the output file's path.
+  ///
+  /// **Note:** This path should be relative to the `OUT_DIR`.
+  ///
+  /// Don't set this if you are using [`tauri::include_codegen_context!`] as that helper macro
+  /// expects the default value. This option can be useful if you are not using the helper and
+  /// instead using [`std::include!`] on the generated code yourself.
+  ///
+  /// Defaults to `tauri-build-context.rs`.
+  ///
+  /// [`tauri::include_codegen_context!`]: https://docs.rs/tauri/0.12/tauri/macro.include_codegen_context.html
+  pub fn out_file(mut self, filename: PathBuf) -> Self {
+    self.out_file = filename;
+    self
+  }
+
+  /// Generate the code and write it to the output file - returning the path it was saved to.
+  ///
+  /// Unless you are doing something special with this builder, you don't need to do anything with
+  /// the returned output path.
+  ///
+  /// # Panics
+  ///
+  /// If any parts of the codegen fail, this will panic with the related error message. This is
+  /// typically desirable when running inside a build script; see [`Self::try_build`] for no panics.
+  pub fn build(self) -> PathBuf {
+    match self.try_build() {
+      Ok(out) => out,
+      Err(error) => panic!("Error found during Codegen::build: {}", error),
+    }
+  }
+
+  /// Non-panicking [`Self::build`]
+  pub fn try_build(self) -> Result<PathBuf> {
+    let (config, config_parent) = tauri_codegen::get_config(&self.config_path)?;
+    let code = context_codegen(ContextData {
+      config,
+      config_parent,
+      struct_ident: self.struct_ident.clone(),
+    })?;
+
+    // get the full output file path
+    let out = var("OUT_DIR")
+      .map(PathBuf::from)
+      .map(|path| path.join(&self.out_file))
+      .with_context(|| "unable to find OUT_DIR during tauri-build")?;
+
+    // make sure any nested directories in OUT_DIR are created
+    let parent = out.parent().with_context(|| {
+      "`Codegen` could not find the parent to `out_file` while creating the file"
+    })?;
+    create_dir_all(parent)?;
+
+    let mut file = File::create(&out).map(BufWriter::new).with_context(|| {
+      format!(
+        "Unable to create output file during tauri-build {}",
+        out.display()
+      )
+    })?;
+
+    writeln!(&mut file, "{}", code).with_context(|| {
+      format!(
+        "Unable to write tokenstream to out file during tauri-build {}",
+        out.display()
+      )
+    })?;
+
+    Ok(out)
+  }
+}

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

@@ -0,0 +1 @@
+pub(crate) mod context;

+ 56 - 0
core/tauri-build/src/lib.rs

@@ -0,0 +1,56 @@
+#![cfg_attr(doc_cfg, feature(doc_cfg))]
+
+pub use anyhow::Result;
+
+#[cfg(feature = "codegen")]
+mod codegen;
+
+#[cfg(feature = "codegen")]
+pub use codegen::context::CodegenContext;
+
+/// Run all build time helpers for your Tauri Application.
+///
+/// The current helpers include the following:
+/// * Generates a Windows Resource file when targeting Windows.
+///
+/// # Platforms
+///
+/// [`build()`] should be called inside of `build.rs` regardless of the platform:
+/// * New helpers may target more platforms in the future.
+/// * Platform specific code is handled by the helpers automatically.
+/// * A build script is required in order to activate some cargo environmental variables that are
+///   used when generating code and embedding assets - so [`build()`] may as well be called.
+///
+/// In short, this is saying don't put the call to [`build()`] behind a `#[cfg(windows)]`.
+///
+/// # Panics
+///
+/// If any of the build time helpers fail, they will [`std::panic!`] with the related error message.
+/// This is typically desirable when running inside a build script; see [`try_build`] for no panics.
+pub fn build() {
+  if let Err(error) = try_build() {
+    panic!("error found during tauri-build: {}", error);
+  }
+}
+
+/// Non-panicking [`build()`].
+pub fn try_build() -> Result<()> {
+  #[cfg(windows)]
+  {
+    use anyhow::{anyhow, Context};
+    use std::path::Path;
+    use winres::WindowsResource;
+
+    if Path::new("icons/icon.ico").exists() {
+      let mut res = WindowsResource::new();
+      res.set_icon_with_id("icons/icon.ico", "32512");
+      res.compile().with_context(|| {
+        "failed to compile icons/icon.ico into a Windows Resource file during tauri-build"
+      })?;
+    } else {
+      return Err(anyhow!("no icons/icon.ico file found; required for generating a Windows Resource file during tauri-build"));
+    }
+  }
+
+  Ok(())
+}

+ 20 - 0
core/tauri-codegen/Cargo.toml

@@ -0,0 +1,20 @@
+[package]
+name = "tauri-codegen"
+version = "0.1.0"
+authors = [ "Tauri Community" ]
+categories = [ "gui", "web-programming" ]
+license = "MIT"
+homepage = "https://tauri.studio"
+repository = "https://github.com/tauri-apps/tauri/tree/dev/core/tauri-codegen"
+description = "code generation meant to be consumed inside of `tauri` through `tauri-build` or `tauri-macros`"
+edition = "2018"
+
+[dependencies]
+proc-macro2 = "1"
+quote = "1"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+tauri-api = { path = "../../tauri-api", features = ["build"] }
+thiserror = "1"
+walkdir = "2"
+zstd = "0.6"

+ 69 - 0
core/tauri-codegen/src/context.rs

@@ -0,0 +1,69 @@
+use crate::embedded_assets::{EmbeddedAssets, EmbeddedAssetsError};
+use proc_macro2::{Ident, TokenStream};
+use quote::quote;
+use std::path::PathBuf;
+use tauri_api::config::Config;
+
+/// Necessary data needed by [`codegen_context`] to generate code for a Tauri application context.
+pub struct ContextData {
+  pub config: Config,
+  pub config_parent: PathBuf,
+  pub struct_ident: Ident,
+}
+
+/// Build an `AsTauriContext` implementation for including in application code.
+pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsError> {
+  let ContextData {
+    config,
+    config_parent,
+    struct_ident,
+  } = data;
+  let dist_dir = config_parent.join(&config.build.dist_dir);
+
+  // generate the assets inside the dist dir into a perfect hash function
+  let assets = EmbeddedAssets::new(&dist_dir)?;
+
+  // handle default window icons for Windows targets
+  let default_window_icon = if cfg!(windows) {
+    let icon_path = config_parent.join("icons/icon.ico").display().to_string();
+    quote!(Some(include_bytes!(#icon_path)))
+  } else {
+    quote!(None)
+  };
+
+  let tauri_script_path = dist_dir.join("__tauri.js").display().to_string();
+
+  // double braces are purposeful to force the code into a block expression
+  Ok(quote! {{
+    use ::tauri::api::private::{OnceCell, AsTauriContext};
+
+    static CONFIG: OnceCell<::tauri::api::config::Config>= OnceCell::new();
+
+    /// Generated by `tauri-codegen`.
+    struct #struct_ident;
+
+    impl AsTauriContext for #struct_ident {
+        /// Return a static reference to the config we parsed at build time
+        fn config() -> &'static ::tauri::api::config::Config {
+            CONFIG.get_or_init(|| #config)
+        }
+
+        /// Inject assets we generated during build time
+        fn assets() -> &'static ::tauri::api::assets::EmbeddedAssets {
+          #assets
+        }
+
+        /// Make the __tauri.js a dependency for the compiler
+        fn raw_tauri_script() -> &'static str {
+          include_str!(#tauri_script_path)
+        }
+
+        /// Default window icon to set automatically if exists
+        fn default_window_icon() -> Option<&'static [u8]> {
+          #default_window_icon
+        }
+      }
+
+      #struct_ident {}
+  }})
+}

+ 135 - 0
core/tauri-codegen/src/embedded_assets.rs

@@ -0,0 +1,135 @@
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens, TokenStreamExt};
+use std::{
+  collections::HashMap,
+  env::var,
+  fs::File,
+  io::BufReader,
+  path::{Path, PathBuf},
+};
+use tauri_api::assets::AssetKey;
+use thiserror::Error;
+use walkdir::WalkDir;
+
+/// (key, (original filepath, compressed bytes))
+type Asset = (AssetKey, (String, Vec<u8>));
+
+/// All possible errors while reading and compressing an [`EmbeddedAssets`] directory
+#[derive(Debug, Error)]
+pub enum EmbeddedAssetsError {
+  #[error("failed to read asset at {path} because {error}")]
+  AssetRead {
+    path: PathBuf,
+    error: std::io::Error,
+  },
+
+  #[error("failed to write asset from {path} to Vec<u8> because {error}")]
+  AssetWrite {
+    path: PathBuf,
+    error: std::io::Error,
+  },
+
+  #[error("invalid prefix {prefix} used while including path {path}")]
+  PrefixInvalid { prefix: PathBuf, path: PathBuf },
+
+  #[error("failed to walk directory {path} because {error}")]
+  Walkdir {
+    path: PathBuf,
+    error: walkdir::Error,
+  },
+}
+
+/// Represent a directory of assets that are compressed and embedded.
+///
+/// This is the compile time generation of [`tauri_api::assets::Assets`] from a directory. Assets
+/// from the directory are added as compiler dependencies by dummy including the original,
+/// uncompressed assets.
+///
+/// The assets are compressed during this runtime, and can only be represented as a [`TokenStream`]
+/// through [`ToTokens`]. The generated code is meant to be injected into an application to include
+/// the compressed assets in that application's binary.
+pub struct EmbeddedAssets(HashMap<AssetKey, (String, Vec<u8>)>);
+
+impl EmbeddedAssets {
+  /// Compress a directory of assets, ready to be generated into a [`tauri_api::assets::Assets`].
+  pub fn new(path: &Path) -> Result<Self, EmbeddedAssetsError> {
+    WalkDir::new(&path)
+      .follow_links(true)
+      .into_iter()
+      .filter_map(|entry| match entry {
+        // we only serve files, not directory listings
+        Ok(entry) if entry.file_type().is_dir() => None,
+
+        // compress all files encountered
+        Ok(entry) => Some(Self::compress_file(path, entry.path())),
+
+        // pass down error through filter to fail when encountering any error
+        Err(error) => Some(Err(EmbeddedAssetsError::Walkdir {
+          path: path.to_owned(),
+          error,
+        })),
+      })
+      .collect::<Result<_, _>>()
+      .map(Self)
+  }
+
+  /// Use highest compression level for release, the fastest one for everything else
+  fn compression_level() -> i32 {
+    match var("PROFILE").as_ref().map(String::as_str) {
+      Ok("release") => 22,
+      _ => -5,
+    }
+  }
+
+  /// Compress a file and spit out the information in a [`HashMap`] friendly form.
+  fn compress_file(prefix: &Path, path: &Path) -> Result<Asset, EmbeddedAssetsError> {
+    let reader =
+      File::open(&path)
+        .map(BufReader::new)
+        .map_err(|error| EmbeddedAssetsError::AssetRead {
+          path: path.to_owned(),
+          error,
+        })?;
+
+    // entirely read compressed asset into bytes
+    let bytes = zstd::encode_all(reader, Self::compression_level()).map_err(|error| {
+      EmbeddedAssetsError::AssetWrite {
+        path: path.to_owned(),
+        error,
+      }
+    })?;
+
+    // get a key to the asset path without the asset directory prefix
+    let key = path
+      .strip_prefix(prefix)
+      .map(AssetKey::from) // format the path for use in assets
+      .map_err(|_| EmbeddedAssetsError::PrefixInvalid {
+        prefix: prefix.to_owned(),
+        path: path.to_owned(),
+      })?;
+
+    Ok((key, (path.display().to_string(), bytes)))
+  }
+}
+
+impl ToTokens for EmbeddedAssets {
+  fn to_tokens(&self, tokens: &mut TokenStream) {
+    let mut map = TokenStream::new();
+    for (key, (original, bytes)) in &self.0 {
+      let key: &str = key.as_ref();
+
+      // add original asset as a compiler dependency, rely on dead code elimination to clean it up
+      map.append_all(quote!(#key => {
+        const _: &[u8] = include_bytes!(#original);
+        &[#(#bytes),*]
+      },));
+    }
+
+    // we expect phf related items to be in path when generating the path code
+    tokens.append_all(quote! {
+        use ::tauri::api::assets::{EmbeddedAssets, phf, phf::phf_map};
+        static ASSETS: EmbeddedAssets = EmbeddedAssets::from_zstd(phf_map! { #map });
+        &ASSETS
+    });
+  }
+}

+ 80 - 0
core/tauri-codegen/src/lib.rs

@@ -0,0 +1,80 @@
+pub use context::{context_codegen, ContextData};
+use std::{
+  borrow::Cow,
+  fs::File,
+  io::BufReader,
+  path::{Path, PathBuf},
+};
+pub use tauri_api::config::Config;
+use thiserror::Error;
+
+mod context;
+pub mod embedded_assets;
+
+/// Represents all the errors that can happen while reading the config.
+#[derive(Debug, Error)]
+pub enum ConfigError {
+  #[error("unable to access current working directory: {0}")]
+  CurrentDir(std::io::Error),
+
+  // this error should be "impossible" because we use std::env::current_dir() - cover it anyways
+  #[error("Tauri config file has no parent, this shouldn't be possible. file an issue on https://github.com/tauri-apps/tauri - target {0}")]
+  Parent(PathBuf),
+
+  #[error("unable to parse inline TAURI_CONFIG env var: {0}")]
+  FormatInline(serde_json::Error),
+
+  #[error("unable to parse Tauri config file at {path} because {error}")]
+  Format {
+    path: PathBuf,
+    error: serde_json::Error,
+  },
+
+  #[error("unable to read Tauri config file at {path} because {error}")]
+  Io {
+    path: PathBuf,
+    error: std::io::Error,
+  },
+}
+
+/// Get the [`Config`] from the `TAURI_CONFIG` environmental variable, or read from the passed path.
+///
+/// If the passed path is relative, it should be relative to the current working directory of the
+/// compiling crate.
+pub fn get_config(path: &Path) -> Result<(Config, PathBuf), ConfigError> {
+  let path = if path.is_relative() {
+    let cwd = std::env::current_dir().map_err(ConfigError::CurrentDir)?;
+    Cow::Owned(cwd.join(path))
+  } else {
+    Cow::Borrowed(path)
+  };
+
+  // in the future we may want to find a way to not need the TAURI_CONFIG env var so that
+  // it is impossible for the content of two separate configs to get mixed up. The chances are
+  // already unlikely unless the developer goes out of their way to run the cli on a different
+  // project than the target crate.
+  let config = if let Ok(env) = std::env::var("TAURI_CONFIG") {
+    serde_json::from_str(&env).map_err(ConfigError::FormatInline)?
+  } else {
+    File::open(&path)
+      .map_err(|error| ConfigError::Io {
+        path: path.clone().into_owned(),
+        error,
+      })
+      .map(BufReader::new)
+      .and_then(|file| {
+        serde_json::from_reader(file).map_err(|error| ConfigError::Format {
+          path: path.clone().into_owned(),
+          error,
+        })
+      })?
+  };
+
+  // this should be impossible because of the use of `current_dir()` above, but handle it anyways
+  let parent = path
+    .parent()
+    .map(ToOwned::to_owned)
+    .ok_or_else(|| ConfigError::Parent(path.into_owned()))?;
+
+  Ok((config, parent))
+}

+ 0 - 0
tauri/examples/api/.gitignore → examples/api/.gitignore


+ 0 - 0
tauri/examples/api/README.md → examples/api/README.md


+ 2 - 2
tauri/examples/api/package.json → examples/api/package.json

@@ -5,7 +5,7 @@
     "build": "rollup -c",
     "dev": "rollup -c -w",
     "start": "sirv public",
-    "tauri": "node ../../../cli/tauri.js/bin/tauri"
+    "tauri": "node ../../cli/tauri.js/bin/tauri"
   },
   "devDependencies": {
     "@rollup/plugin-commonjs": "17.1.0",
@@ -17,7 +17,7 @@
     "svelte": "3.35.0"
   },
   "dependencies": {
-    "@tauri-apps/api": "link:../../../api",
+    "@tauri-apps/api": "link:../../api",
     "sirv-cli": "1.0.11"
   }
 }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
examples/api/public/__tauri.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
examples/api/public/build/bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
examples/api/public/build/bundle.js.map


+ 0 - 0
tauri/examples/api/public/favicon.png → examples/api/public/favicon.png


+ 0 - 0
tauri/examples/api/public/global.css → examples/api/public/global.css


+ 0 - 0
tauri/examples/api/public/icon.png → examples/api/public/icon.png


+ 0 - 0
tauri/examples/api/public/index.html → examples/api/public/index.html


+ 0 - 0
tauri/examples/api/rollup.config.js → examples/api/rollup.config.js


+ 0 - 0
tauri/examples/api/screenshot.png → examples/api/screenshot.png


+ 0 - 0
tauri/examples/api/src-tauri/.gitignore → examples/api/src-tauri/.gitignore


+ 17 - 0
examples/api/src-tauri/Cargo.toml

@@ -0,0 +1,17 @@
+[package]
+name = "api"
+version = "0.1.0"
+description = "An example Tauri Application showcasing the api"
+edition = "2018"
+
+[build-dependencies]
+tauri-build = { path = "../../../core/tauri-build" }
+
+[dependencies]
+serde_json = "1.0"
+serde = { version = "1.0", features = [ "derive" ] }
+tauri = { path = "../../../tauri", features =["api-all", "cli"]}
+
+[features]
+default = [ "custom-protocol" ]
+custom-protocol = [ "tauri/custom-protocol" ]

+ 3 - 0
examples/api/src-tauri/build.rs

@@ -0,0 +1,3 @@
+fn main() {
+  tauri_build::build()
+}

+ 0 - 0
tauri/examples/api/src-tauri/icons/128x128.png → examples/api/src-tauri/icons/128x128.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/128x128@2x.png → examples/api/src-tauri/icons/128x128@2x.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/32x32.png → examples/api/src-tauri/icons/32x32.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square107x107Logo.png → examples/api/src-tauri/icons/Square107x107Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square142x142Logo.png → examples/api/src-tauri/icons/Square142x142Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square150x150Logo.png → examples/api/src-tauri/icons/Square150x150Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square284x284Logo.png → examples/api/src-tauri/icons/Square284x284Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square30x30Logo.png → examples/api/src-tauri/icons/Square30x30Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square310x310Logo.png → examples/api/src-tauri/icons/Square310x310Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square44x44Logo.png → examples/api/src-tauri/icons/Square44x44Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square71x71Logo.png → examples/api/src-tauri/icons/Square71x71Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/Square89x89Logo.png → examples/api/src-tauri/icons/Square89x89Logo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/StoreLogo.png → examples/api/src-tauri/icons/StoreLogo.png


+ 0 - 0
tauri/examples/api/src-tauri/icons/icon.icns → examples/api/src-tauri/icons/icon.icns


+ 0 - 0
tauri/examples/api/src-tauri/icons/icon.ico → examples/api/src-tauri/icons/icon.ico


+ 0 - 0
tauri/examples/api/src-tauri/icons/icon.png → examples/api/src-tauri/icons/icon.png


+ 0 - 0
tauri/examples/api/src-tauri/src/cmd.rs → examples/api/src-tauri/src/cmd.rs


+ 4 - 6
tauri/examples/api/src-tauri/src/main.rs → examples/api/src-tauri/src/main.rs

@@ -12,11 +12,10 @@ struct Reply {
   data: String,
 }
 
-#[derive(tauri::FromTauriContext)]
-struct Context;
-
 fn main() {
-  tauri::AppBuilder::<Context>::new()
+  let context = tauri::generate_tauri_context!();
+
+  tauri::AppBuilder::default()
     .setup(|webview_manager| async move {
       let dispatcher = webview_manager.current_webview().await.unwrap();
       let dispatcher_ = dispatcher.clone();
@@ -35,7 +34,6 @@ fn main() {
       cmd::log_operation,
       cmd::perform_request
     ])
-    .build()
-    .unwrap()
+    .build(context)
     .run();
 }

+ 0 - 0
tauri/examples/api/src-tauri/tauri.conf.json → examples/api/src-tauri/tauri.conf.json


+ 0 - 0
tauri/examples/api/src/App.svelte → examples/api/src/App.svelte


+ 0 - 0
tauri/examples/api/src/components/Cli.svelte → examples/api/src/components/Cli.svelte


+ 0 - 0
tauri/examples/api/src/components/Communication.svelte → examples/api/src/components/Communication.svelte


+ 0 - 0
tauri/examples/api/src/components/Dialog.svelte → examples/api/src/components/Dialog.svelte


+ 0 - 0
tauri/examples/api/src/components/FileSystem.svelte → examples/api/src/components/FileSystem.svelte


+ 0 - 0
tauri/examples/api/src/components/Http.svelte → examples/api/src/components/Http.svelte


+ 0 - 0
tauri/examples/api/src/components/Notifications.svelte → examples/api/src/components/Notifications.svelte


+ 0 - 0
tauri/examples/api/src/components/Shortcuts.svelte → examples/api/src/components/Shortcuts.svelte


+ 0 - 0
tauri/examples/api/src/components/Window.svelte → examples/api/src/components/Window.svelte


+ 0 - 0
tauri/examples/api/src/main.js → examples/api/src/main.js


+ 3 - 2
tauri/examples/api/yarn.lock → examples/api/yarn.lock

@@ -62,8 +62,9 @@
     estree-walker "^1.0.1"
     picomatch "^2.2.2"
 
-"@tauri-apps/api@link:../../../api":
-  version "0.1.0"
+"@tauri-apps/api@link:../../api":
+  version "0.0.0"
+  uid ""
 
 "@types/estree@*":
   version "0.0.46"

+ 0 - 0
tauri/examples/helloworld/package.json → examples/helloworld/package.json


+ 0 - 0
tauri/examples/helloworld/public/__tauri.js → examples/helloworld/public/__tauri.js


+ 0 - 0
tauri/examples/helloworld/public/index.html → examples/helloworld/public/index.html


+ 0 - 0
tauri/examples/helloworld/src-tauri/.gitignore → examples/helloworld/src-tauri/.gitignore


+ 5 - 13
tauri/examples/helloworld/src-tauri/Cargo.toml → examples/helloworld/src-tauri/Cargo.toml

@@ -1,20 +1,16 @@
-workspace = { }
-
 [package]
 name = "helloworld"
 version = "0.1.0"
-description = "A Tauri App"
-authors = [ "you" ]
-license = ""
-repository = ""
-default-run = "helloworld"
+description = "A very simple Tauri Appplication"
 edition = "2018"
-build = "src/build.rs"
+
+[build-dependencies]
+tauri-build = { path = "../../../core/tauri-build", features = [ "codegen" ]}
 
 [dependencies]
 serde_json = "1.0"
 serde = { version = "1.0", features = [ "derive" ] }
-tauri = { path = "../../..", features =["api-all"]}
+tauri = { path = "../../../tauri", features =["api-all"]}
 
 [target."cfg(windows)".build-dependencies]
 winres = "0.1"
@@ -22,7 +18,3 @@ winres = "0.1"
 [features]
 default = [ "custom-protocol" ]
 custom-protocol = [ "tauri/custom-protocol" ]
-
-[[bin]]
-name = "helloworld"
-path = "src/main.rs"

+ 4 - 0
examples/helloworld/src-tauri/build.rs

@@ -0,0 +1,4 @@
+fn main() {
+  tauri_build::CodegenContext::default().build();
+  tauri_build::build();
+}

+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/128x128.png → examples/helloworld/src-tauri/icons/128x128.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/128x128@2x.png → examples/helloworld/src-tauri/icons/128x128@2x.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/32x32.png → examples/helloworld/src-tauri/icons/32x32.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square107x107Logo.png → examples/helloworld/src-tauri/icons/Square107x107Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square142x142Logo.png → examples/helloworld/src-tauri/icons/Square142x142Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square150x150Logo.png → examples/helloworld/src-tauri/icons/Square150x150Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square284x284Logo.png → examples/helloworld/src-tauri/icons/Square284x284Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square30x30Logo.png → examples/helloworld/src-tauri/icons/Square30x30Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square310x310Logo.png → examples/helloworld/src-tauri/icons/Square310x310Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square44x44Logo.png → examples/helloworld/src-tauri/icons/Square44x44Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square71x71Logo.png → examples/helloworld/src-tauri/icons/Square71x71Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/Square89x89Logo.png → examples/helloworld/src-tauri/icons/Square89x89Logo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/StoreLogo.png → examples/helloworld/src-tauri/icons/StoreLogo.png


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/icon.icns → examples/helloworld/src-tauri/icons/icon.icns


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/icon.ico → examples/helloworld/src-tauri/icons/icon.ico


+ 0 - 0
tauri/examples/helloworld/src-tauri/icons/icon.png → examples/helloworld/src-tauri/icons/icon.png


+ 4 - 7
tauri/examples/helloworld/src-tauri/src/main.rs → examples/helloworld/src-tauri/src/main.rs

@@ -3,19 +3,16 @@
   windows_subsystem = "windows"
 )]
 
-#[derive(tauri::FromTauriContext)]
-#[config_path = "examples/helloworld/src-tauri/tauri.conf.json"]
-struct Context;
-
 #[tauri::command]
 fn my_custom_command(argument: String) {
   println!("{}", argument);
 }
 
 fn main() {
-  tauri::AppBuilder::<Context>::new()
+  let context = tauri::generate_tauri_context!();
+
+  tauri::AppBuilder::default()
     .invoke_handler(tauri::generate_handler![my_custom_command])
-    .build()
-    .unwrap()
+    .build(context)
     .run();
 }

+ 0 - 0
tauri/examples/helloworld/src-tauri/tauri.conf.json → examples/helloworld/src-tauri/tauri.conf.json


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
examples/multiwindow/dist/__tauri.js


+ 0 - 0
tauri/examples/multiwindow/dist/index.html → examples/multiwindow/dist/index.html


+ 0 - 0
tauri/examples/multiwindow/package.json → examples/multiwindow/package.json


+ 0 - 0
tauri/examples/multiwindow/src-tauri/.gitignore → examples/multiwindow/src-tauri/.gitignore


+ 18 - 0
examples/multiwindow/src-tauri/Cargo.toml

@@ -0,0 +1,18 @@
+[package]
+name = "multiwindow"
+version = "0.1.0"
+description = "An example Tauri Multi-Window Application"
+edition = "2018"
+
+[build-dependencies]
+tauri-build = { path = "../../../core/tauri-build", features = ["codegen"] }
+
+[dependencies]
+tauri = { path = "../../../tauri", features =["api-all"]}
+
+[target."cfg(windows)".build-dependencies]
+winres = "0.1"
+
+[features]
+default = [ "custom-protocol" ]
+custom-protocol = [ "tauri/custom-protocol" ]

+ 4 - 0
examples/multiwindow/src-tauri/build.rs

@@ -0,0 +1,4 @@
+fn main() {
+  tauri_build::CodegenContext::default().build();
+  tauri_build::build();
+}

+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/128x128.png → examples/multiwindow/src-tauri/icons/128x128.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/128x128@2x.png → examples/multiwindow/src-tauri/icons/128x128@2x.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/32x32.png → examples/multiwindow/src-tauri/icons/32x32.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/Square107x107Logo.png → examples/multiwindow/src-tauri/icons/Square107x107Logo.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/Square142x142Logo.png → examples/multiwindow/src-tauri/icons/Square142x142Logo.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/Square150x150Logo.png → examples/multiwindow/src-tauri/icons/Square150x150Logo.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/Square284x284Logo.png → examples/multiwindow/src-tauri/icons/Square284x284Logo.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/Square30x30Logo.png → examples/multiwindow/src-tauri/icons/Square30x30Logo.png


+ 0 - 0
tauri/examples/multiwindow/src-tauri/icons/Square310x310Logo.png → examples/multiwindow/src-tauri/icons/Square310x310Logo.png


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio