Skip to content

Commit e227fe0

Browse files
authored
feat(core): allow defining global API script on plugin build (#9156)
* feat(core): allow defining global API script on plugin build Adds `tauri_plugin::Builder::global_api_script_path` so plugin authors can define the JavaScript global API bindings (supposed to be injected to `window.__TAURI__`) at compile time, so the string is only part of the binary when withGlobalTauri is true. Currently this needs to be done manually at runtime (and it's always added to the binary via include_str). * prefix variable * use list of scripts instead of combining them * static str * header [skip ci] * slice
1 parent 3f039c1 commit e227fe0

15 files changed

Lines changed: 151 additions & 10 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"tauri": patch:feat
3+
"tauri-codegen": patch:feat
4+
"tauri-build": patch:feat
5+
"tauri-plugin": patch:feat
6+
---
7+
8+
Allow plugins to define (at compile time) JavaScript that are initialized when `withGlobalTauri` is true.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri-plugin": patch:feat
3+
---
4+
5+
Added `Builder::global_api_script_path` to define a JavaScript file containing the initialization script for the plugin API bindings when `withGlobalTauri` is used.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri-utils": patch:feat
3+
---
4+
5+
Added the `plugin` module.

core/tauri-build/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
524524

525525
acl::save_acl_manifests(&acl_manifests)?;
526526

527+
tauri_utils::plugin::load_global_api_scripts(&out_dir);
528+
527529
println!("cargo:rustc-env=TAURI_ENV_TARGET_TRIPLE={target_triple}");
528530

529531
// TODO: far from ideal, but there's no other way to get the target dir, see <https://github.com/rust-lang/cargo/issues/5457>

core/tauri-codegen/src/context.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use tauri_utils::html::{
2222
inject_nonce_token, parse as parse_html, serialize_node as serialize_html_node, NodeRef,
2323
};
2424
use tauri_utils::platform::Target;
25+
use tauri_utils::plugin::GLOBAL_API_SCRIPT_FILE_LIST_PATH;
2526
use tauri_utils::tokens::{map_lit, str_lit};
2627

2728
use crate::embedded_assets::{AssetOptions, CspHashes, EmbeddedAssets, EmbeddedAssetsError};
@@ -456,6 +457,36 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
456457
let resolved = Resolved::resolve(&acl, capabilities, target).expect("failed to resolve ACL");
457458
let runtime_authority = quote!(#root::ipc::RuntimeAuthority::new(#acl_tokens, #resolved));
458459

460+
let plugin_global_api_script_file_list_path = out_dir.join(GLOBAL_API_SCRIPT_FILE_LIST_PATH);
461+
let plugin_global_api_script =
462+
if config.app.with_global_tauri && plugin_global_api_script_file_list_path.exists() {
463+
let file_list_str = std::fs::read_to_string(plugin_global_api_script_file_list_path)
464+
.expect("failed to read plugin global API script paths");
465+
let file_list = serde_json::from_str::<Vec<PathBuf>>(&file_list_str)
466+
.expect("failed to parse plugin global API script paths");
467+
468+
let mut plugins = Vec::new();
469+
for path in file_list {
470+
plugins.push(std::fs::read_to_string(&path).unwrap_or_else(|e| {
471+
panic!(
472+
"failed to read plugin global API script {}: {e}",
473+
path.display()
474+
)
475+
}));
476+
}
477+
478+
Some(plugins)
479+
} else {
480+
None
481+
};
482+
483+
let plugin_global_api_script = if let Some(scripts) = plugin_global_api_script {
484+
let scripts = scripts.into_iter().map(|s| quote!(#s));
485+
quote!(::std::option::Option::Some(&[#(#scripts),*]))
486+
} else {
487+
quote!(::std::option::Option::None)
488+
};
489+
459490
Ok(quote!({
460491
#[allow(unused_mut, clippy::let_and_return)]
461492
let mut context = #root::Context::new(
@@ -466,7 +497,8 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
466497
#package_info,
467498
#info_plist,
468499
#pattern,
469-
#runtime_authority
500+
#runtime_authority,
501+
#plugin_global_api_script
470502
);
471503
#with_tray_icon_code
472504
context

core/tauri-plugin/src/build/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub fn plugin_config<T: DeserializeOwned>(name: &str) -> Option<T> {
3131
pub struct Builder<'a> {
3232
commands: &'a [&'static str],
3333
global_scope_schema: Option<schemars::schema::RootSchema>,
34+
global_api_script_path: Option<PathBuf>,
3435
android_path: Option<PathBuf>,
3536
ios_path: Option<PathBuf>,
3637
}
@@ -40,6 +41,7 @@ impl<'a> Builder<'a> {
4041
Self {
4142
commands,
4243
global_scope_schema: None,
44+
global_api_script_path: None,
4345
android_path: None,
4446
ios_path: None,
4547
}
@@ -51,6 +53,14 @@ impl<'a> Builder<'a> {
5153
self
5254
}
5355

56+
/// Sets the path to the script that is injected in the webview when the `withGlobalTauri` configuration is set to true.
57+
///
58+
/// This is usually an IIFE that injects the plugin API JavaScript bindings to `window.__TAURI__`.
59+
pub fn global_api_script_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
60+
self.global_api_script_path.replace(path.into());
61+
self
62+
}
63+
5464
/// Sets the Android project path.
5565
pub fn android_path<P: Into<PathBuf>>(mut self, android_path: P) -> Self {
5666
self.android_path.replace(android_path.into());
@@ -118,6 +128,10 @@ impl<'a> Builder<'a> {
118128
acl::build::define_global_scope_schema(global_scope_schema, &name, &out_dir)?;
119129
}
120130

131+
if let Some(path) = self.global_api_script_path {
132+
tauri_utils::plugin::define_global_api_script_path(path);
133+
}
134+
121135
mobile::setup(self.android_path, self.ios_path)?;
122136

123137
Ok(())

core/tauri-utils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub mod html;
2929
pub mod io;
3030
pub mod mime_type;
3131
pub mod platform;
32+
pub mod plugin;
3233
/// Prepare application resources and sidecars.
3334
#[cfg(feature = "resources")]
3435
pub mod resources;

core/tauri-utils/src/plugin.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2+
// SPDX-License-Identifier: Apache-2.0
3+
// SPDX-License-Identifier: MIT
4+
5+
//! Compile-time and runtime types for Tauri plugins.
6+
#[cfg(feature = "build")]
7+
pub use build::*;
8+
9+
#[cfg(feature = "build")]
10+
mod build {
11+
use std::{
12+
env::vars_os,
13+
path::{Path, PathBuf},
14+
};
15+
16+
const GLOBAL_API_SCRIPT_PATH_KEY: &str = "GLOBAL_API_SCRIPT_PATH";
17+
/// Known file name of the file that contains an array with the path of all API scripts defined with [`define_global_api_script_path`].
18+
pub const GLOBAL_API_SCRIPT_FILE_LIST_PATH: &str = "__global-api-script.js";
19+
20+
/// Defines the path to the global API script using Cargo instructions.
21+
pub fn define_global_api_script_path(path: PathBuf) {
22+
println!(
23+
"cargo:{GLOBAL_API_SCRIPT_PATH_KEY}={}",
24+
path
25+
.canonicalize()
26+
.expect("failed to canonicalize global API script path")
27+
.display()
28+
)
29+
}
30+
31+
/// Collects the path of all the global API scripts defined with [`define_global_api_script_path`]
32+
/// and saves them to the out dir with filename [`GLOBAL_API_SCRIPT_FILE_LIST_PATH`].
33+
pub fn load_global_api_scripts(out_dir: &Path) {
34+
let mut scripts = Vec::new();
35+
36+
for (key, value) in vars_os() {
37+
let key = key.to_string_lossy();
38+
39+
if key.starts_with("DEP_") && key.ends_with(GLOBAL_API_SCRIPT_PATH_KEY) {
40+
let script_path = PathBuf::from(value);
41+
scripts.push(script_path);
42+
}
43+
}
44+
45+
std::fs::write(
46+
out_dir.join(GLOBAL_API_SCRIPT_FILE_LIST_PATH),
47+
serde_json::to_string(&scripts).expect("failed to serialize global API script paths"),
48+
)
49+
.expect("failed to write global API script");
50+
}
51+
}

core/tauri/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ pub struct Context<R: Runtime> {
388388
pub(crate) _info_plist: (),
389389
pub(crate) pattern: Pattern,
390390
pub(crate) runtime_authority: RuntimeAuthority,
391+
pub(crate) plugin_global_api_scripts: Option<&'static [&'static str]>,
391392
}
392393

393394
impl<R: Runtime> fmt::Debug for Context<R> {
@@ -397,7 +398,8 @@ impl<R: Runtime> fmt::Debug for Context<R> {
397398
.field("default_window_icon", &self.default_window_icon)
398399
.field("app_icon", &self.app_icon)
399400
.field("package_info", &self.package_info)
400-
.field("pattern", &self.pattern);
401+
.field("pattern", &self.pattern)
402+
.field("plugin_global_api_scripts", &self.plugin_global_api_scripts);
401403

402404
#[cfg(all(desktop, feature = "tray-icon"))]
403405
d.field("tray_icon", &self.tray_icon);
@@ -500,6 +502,7 @@ impl<R: Runtime> Context<R> {
500502
info_plist: (),
501503
pattern: Pattern,
502504
runtime_authority: RuntimeAuthority,
505+
plugin_global_api_scripts: Option<&'static [&'static str]>,
503506
) -> Self {
504507
Self {
505508
config,
@@ -512,6 +515,7 @@ impl<R: Runtime> Context<R> {
512515
_info_plist: info_plist,
513516
pattern,
514517
runtime_authority,
518+
plugin_global_api_scripts,
515519
}
516520
}
517521

core/tauri/src/manager/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ pub struct AppManager<R: Runtime> {
188188
/// Application pattern.
189189
pub pattern: Arc<Pattern>,
190190

191+
/// Global API scripts collected from plugins.
192+
pub plugin_global_api_scripts: Arc<Option<&'static [&'static str]>>,
193+
191194
/// Application Resources Table
192195
pub(crate) resources_table: Arc<Mutex<ResourceTable>>,
193196
}
@@ -274,6 +277,7 @@ impl<R: Runtime> AppManager<R> {
274277
app_icon: context.app_icon,
275278
package_info: context.package_info,
276279
pattern: Arc::new(context.pattern),
280+
plugin_global_api_scripts: Arc::new(context.plugin_global_api_scripts),
277281
resources_table: Arc::default(),
278282
}
279283
}

0 commit comments

Comments
 (0)