Skip to content

Commit

Permalink
feat(core): fallback to file system for AssetResolver::get, closes #8411
Browse files Browse the repository at this point in the history
 (#10356)

* fix(core): fallback to file system for AssetResolver::get, closes #8411

Changes the AssetResolver::get implementation to fallback to reading the distDir directly when using the development mode pointing to a external URL (which is the way most people use the dev mode and means there's no embedded assets to pull from).

* fix clippy

* fix test

* clippy

* clippy2

* update time
  • Loading branch information
lucasfernog authored Jul 31, 2024
1 parent eb58ac3 commit 67b7ca6
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 30 deletions.
6 changes: 6 additions & 0 deletions .changes/asset-resolver-dev-fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri": patch:enhance
"tauri-codegen": patch:enhance
---

Enhance `AssetResolver::get` in development mode by reading distDir directly as a fallback to the embedded assets.
2 changes: 1 addition & 1 deletion core/tauri-build/src/allowlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn check(config: &Config, manifest: &mut Manifest) -> Result<()> {
if deps.is_empty() {
if let Some(alias) = &metadata.alias {
deps = find_dependency(manifest, alias, metadata.kind);
name = alias.clone();
name.clone_from(alias);
}
}

Expand Down
38 changes: 27 additions & 11 deletions core/tauri-codegen/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,17 +437,33 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
#[cfg(not(feature = "shell-scope"))]
let shell_scope_config = quote!();

Ok(quote!(#root::Context::new(
#config,
::std::sync::Arc::new(#assets),
#default_window_icon,
#app_icon,
#system_tray_icon,
#package_info,
#info_plist,
#pattern,
#shell_scope_config
)))
let maybe_config_parent_setter = if dev {
let config_parent = config_parent.to_string_lossy();
quote!({
context.with_config_parent(#config_parent);
})
} else {
quote!()
};

Ok(quote!({
#[allow(unused_mut, clippy::let_and_return)]
let mut context = #root::Context::new(
#config,
::std::sync::Arc::new(#assets),
#default_window_icon,
#app_icon,
#system_tray_icon,
#package_info,
#info_plist,
#pattern,
#shell_scope_config
);

#maybe_config_parent_setter

context
}))
}

fn ico_icon<P: AsRef<Path>>(
Expand Down
2 changes: 1 addition & 1 deletion core/tauri-config-schema/schema.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Config",
"description": "The Tauri configuration object. It is read from a file where you can define your frontend assets, configure the bundler, enable the app updater, define a system tray, enable APIs via the allowlist and more.\n\nThe configuration file is generated by the [`tauri init`](https://tauri.app/v1/api/cli#init) command that lives in your Tauri application source directory (src-tauri).\n\nOnce generated, you may modify it at will to customize your Tauri application.\n\n## File Formats\n\nBy default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\nTauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively. The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`. The TOML file name is `Tauri.toml`.\n\n## Platform-Specific Configuration\n\nIn addition to the default configuration file, Tauri can read a platform-specific configuration from `tauri.linux.conf.json`, `tauri.windows.conf.json`, and `tauri.macos.conf.json` (or `Tauri.linux.toml`, `Tauri.windows.toml` and `Tauri.macos.toml` if the `Tauri.toml` format is used), which gets merged with the main configuration object.\n\n## Configuration Structure\n\nThe configuration is composed of the following objects:\n\n- [`package`](#packageconfig): Package settings - [`tauri`](#tauriconfig): The Tauri config - [`build`](#buildconfig): The build configuration - [`plugins`](#pluginconfig): The plugins config\n\n```json title=\"Example tauri.config.json file\" { \"build\": { \"beforeBuildCommand\": \"\", \"beforeDevCommand\": \"\", \"devPath\": \"../dist\", \"distDir\": \"../dist\" }, \"package\": { \"productName\": \"tauri-app\", \"version\": \"0.1.0\" }, \"tauri\": { \"allowlist\": { \"all\": true }, \"bundle\": {}, \"security\": { \"csp\": null }, \"updater\": { \"active\": false }, \"windows\": [ { \"fullscreen\": false, \"height\": 600, \"resizable\": true, \"title\": \"Tauri App\", \"width\": 800 } ] } } ```",
"description": "The Tauri configuration object. It is read from a file where you can define your frontend assets, configure the bundler, enable the app updater, define a system tray, enable APIs via the allowlist and more.\n\nThe configuration file is generated by the [`tauri init`](https://tauri.app/v1/api/cli#init) command that lives in your Tauri application source directory (src-tauri).\n\nOnce generated, you may modify it at will to customize your Tauri application.\n\n## File Formats\n\nBy default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\nTauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively. The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`. The TOML file name is `Tauri.toml`.\n\n## Platform-Specific Configuration\n\nIn addition to the default configuration file, Tauri can read a platform-specific configuration from `tauri.linux.conf.json`, `tauri.windows.conf.json`, and `tauri.macos.conf.json` (or `Tauri.linux.toml`, `Tauri.windows.toml` and `Tauri.macos.toml` if the `Tauri.toml` format is used), which gets merged with the main configuration object.\n\n## Configuration Structure\n\nThe configuration is composed of the following objects:\n\n- [`package`](#packageconfig): Package settings - [`tauri`](#tauriconfig): The Tauri config - [`build`](#buildconfig): The build configuration - [`plugins`](#pluginconfig): The plugins config\n\nExample tauri.config.json file:\n\n```json { \"build\": { \"beforeBuildCommand\": \"\", \"beforeDevCommand\": \"\", \"devPath\": \"../dist\", \"distDir\": \"../dist\" }, \"package\": { \"productName\": \"tauri-app\", \"version\": \"0.1.0\" }, \"tauri\": { \"allowlist\": { \"all\": true }, \"bundle\": {}, \"security\": { \"csp\": null }, \"updater\": { \"active\": false }, \"windows\": [ { \"fullscreen\": false, \"height\": 600, \"resizable\": true, \"title\": \"Tauri App\", \"width\": 800 } ] } } ```",
"type": "object",
"properties": {
"$schema": {
Expand Down
4 changes: 3 additions & 1 deletion core/tauri-utils/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3196,7 +3196,9 @@ impl PackageConfig {
/// - [`build`](#buildconfig): The build configuration
/// - [`plugins`](#pluginconfig): The plugins config
///
/// ```json title="Example tauri.config.json file"
/// Example tauri.config.json file:
///
/// ```json
/// {
/// "build": {
/// "beforeBuildCommand": "",
Expand Down
41 changes: 41 additions & 0 deletions core/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,48 @@ pub struct AssetResolver<R: Runtime> {

impl<R: Runtime> AssetResolver<R> {
/// Gets the app asset associated with the given path.
///
/// Resolves to the embedded asset that is part of the app
/// in dev when [`devPath`](https://tauri.app/v1/api/config/#buildconfig.devpath) points to a folder in your filesystem
/// or in production when [`distDir`](https://tauri.app/v1/api/config/#buildconfig.distdir)
/// points to your frontend assets.
///
/// Fallbacks to reading the asset from the [distDir] folder so the behavior is consistent in development.
/// Note that the dist directory must exist so you might need to build your frontend assets first.
pub fn get(&self, path: String) -> Option<Asset> {
#[cfg(dev)]
{
// on dev if the devPath is a path to a directory we have the embedded assets
// so we can use get_asset() directly
// we only fallback to reading from distDir directly if we're using an external URL (which is likely)
if let (
crate::utils::config::AppUrl::Url(crate::utils::config::WindowUrl::External(_)),
crate::utils::config::AppUrl::Url(crate::utils::config::WindowUrl::App(dist_path)),
) = (
&self.manager.config().build.dev_path,
&self.manager.config().build.dist_dir,
) {
let asset_path = PathBuf::from(&path)
.components()
.filter(|c| !matches!(c, std::path::Component::RootDir))
.collect::<PathBuf>();

let asset_path = self
.manager
.config_parent()
.map(|p| p.join(dist_path).join(&asset_path))
.unwrap_or_else(|| dist_path.join(&asset_path));
return std::fs::read(asset_path).ok().map(|bytes| {
let mime_type = crate::utils::mime_type::MimeType::parse(&bytes, &path);
Asset {
bytes,
mime_type,
csp_header: None,
}
});
}
}

self.manager.get_asset(path).ok()
}

Expand Down
12 changes: 12 additions & 0 deletions core/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ impl TryFrom<Icon> for runtime::Icon {
/// 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(crate) config: Config,
#[cfg(dev)]
pub(crate) config_parent: Option<std::path::PathBuf>,
pub(crate) assets: Arc<A>,
pub(crate) default_window_icon: Option<Icon>,
pub(crate) app_icon: Option<Vec<u8>>,
Expand Down Expand Up @@ -587,6 +589,8 @@ impl<A: Assets> Context<A> {
) -> Self {
Self {
config,
#[cfg(dev)]
config_parent: None,
assets,
default_window_icon,
app_icon,
Expand All @@ -598,6 +602,14 @@ impl<A: Assets> Context<A> {
shell_scope,
}
}

#[cfg(dev)]
#[doc(hidden)]
pub fn with_config_parent(&mut self, config_parent: impl AsRef<std::path::Path>) {
self
.config_parent
.replace(config_parent.as_ref().to_owned());
}
}

// TODO: expand these docs
Expand Down
9 changes: 9 additions & 0 deletions core/tauri/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ pub struct InnerWindowManager<R: Runtime> {
on_page_load: Box<OnPageLoad<R>>,

config: Arc<Config>,
#[cfg(dev)]
config_parent: Option<std::path::PathBuf>,
assets: Arc<dyn Assets>,
pub(crate) default_window_icon: Option<Icon>,
pub(crate) app_icon: Option<Vec<u8>>,
Expand Down Expand Up @@ -325,6 +327,8 @@ impl<R: Runtime> WindowManager<R> {
invoke_handler,
on_page_load,
config: Arc::new(context.config),
#[cfg(dev)]
config_parent: context.config_parent,
assets: context.assets,
default_window_icon: context.default_window_icon,
app_icon: context.app_icon,
Expand Down Expand Up @@ -1195,6 +1199,11 @@ impl<R: Runtime> WindowManager<R> {
self.inner.config.clone()
}

#[cfg(dev)]
pub fn config_parent(&self) -> Option<&std::path::PathBuf> {
self.inner.config_parent.as_ref()
}

pub fn package_info(&self) -> &PackageInfo {
&self.inner.package_info
}
Expand Down
2 changes: 2 additions & 0 deletions core/tauri/src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
build: Default::default(),
plugins: Default::default(),
},
#[cfg(dev)]
config_parent: None,
assets: Arc::new(assets),
default_window_icon: None,
app_icon: None,
Expand Down
5 changes: 1 addition & 4 deletions core/tests/restart/tests/restart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,7 @@ fn symlink_runner(create_symlinks: impl Fn(&Path) -> io::Result<Symlink>) -> Res

// we expect the output to be the bin path, twice
assert_eq!(stdout, format!("{bin}\n{bin}\n", bin = bin.display()));
} else if cfg!(all(
target_os = "macos",
not(feature = "process-relaunch-dangerous-allow-symlink-macos")
)) {
} else if cfg!(target_os = "macos") {
// we expect this to fail on macOS without the dangerous symlink flag set
let stderr = String::from_utf8(output.stderr)?;

Expand Down
14 changes: 7 additions & 7 deletions examples/api/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions tooling/cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tooling/cli/schema.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Config",
"description": "The Tauri configuration object. It is read from a file where you can define your frontend assets, configure the bundler, enable the app updater, define a system tray, enable APIs via the allowlist and more.\n\nThe configuration file is generated by the [`tauri init`](https://tauri.app/v1/api/cli#init) command that lives in your Tauri application source directory (src-tauri).\n\nOnce generated, you may modify it at will to customize your Tauri application.\n\n## File Formats\n\nBy default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\nTauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively. The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`. The TOML file name is `Tauri.toml`.\n\n## Platform-Specific Configuration\n\nIn addition to the default configuration file, Tauri can read a platform-specific configuration from `tauri.linux.conf.json`, `tauri.windows.conf.json`, and `tauri.macos.conf.json` (or `Tauri.linux.toml`, `Tauri.windows.toml` and `Tauri.macos.toml` if the `Tauri.toml` format is used), which gets merged with the main configuration object.\n\n## Configuration Structure\n\nThe configuration is composed of the following objects:\n\n- [`package`](#packageconfig): Package settings - [`tauri`](#tauriconfig): The Tauri config - [`build`](#buildconfig): The build configuration - [`plugins`](#pluginconfig): The plugins config\n\n```json title=\"Example tauri.config.json file\" { \"build\": { \"beforeBuildCommand\": \"\", \"beforeDevCommand\": \"\", \"devPath\": \"../dist\", \"distDir\": \"../dist\" }, \"package\": { \"productName\": \"tauri-app\", \"version\": \"0.1.0\" }, \"tauri\": { \"allowlist\": { \"all\": true }, \"bundle\": {}, \"security\": { \"csp\": null }, \"updater\": { \"active\": false }, \"windows\": [ { \"fullscreen\": false, \"height\": 600, \"resizable\": true, \"title\": \"Tauri App\", \"width\": 800 } ] } } ```",
"description": "The Tauri configuration object. It is read from a file where you can define your frontend assets, configure the bundler, enable the app updater, define a system tray, enable APIs via the allowlist and more.\n\nThe configuration file is generated by the [`tauri init`](https://tauri.app/v1/api/cli#init) command that lives in your Tauri application source directory (src-tauri).\n\nOnce generated, you may modify it at will to customize your Tauri application.\n\n## File Formats\n\nBy default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\nTauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively. The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`. The TOML file name is `Tauri.toml`.\n\n## Platform-Specific Configuration\n\nIn addition to the default configuration file, Tauri can read a platform-specific configuration from `tauri.linux.conf.json`, `tauri.windows.conf.json`, and `tauri.macos.conf.json` (or `Tauri.linux.toml`, `Tauri.windows.toml` and `Tauri.macos.toml` if the `Tauri.toml` format is used), which gets merged with the main configuration object.\n\n## Configuration Structure\n\nThe configuration is composed of the following objects:\n\n- [`package`](#packageconfig): Package settings - [`tauri`](#tauriconfig): The Tauri config - [`build`](#buildconfig): The build configuration - [`plugins`](#pluginconfig): The plugins config\n\nExample tauri.config.json file:\n\n```json { \"build\": { \"beforeBuildCommand\": \"\", \"beforeDevCommand\": \"\", \"devPath\": \"../dist\", \"distDir\": \"../dist\" }, \"package\": { \"productName\": \"tauri-app\", \"version\": \"0.1.0\" }, \"tauri\": { \"allowlist\": { \"all\": true }, \"bundle\": {}, \"security\": { \"csp\": null }, \"updater\": { \"active\": false }, \"windows\": [ { \"fullscreen\": false, \"height\": 600, \"resizable\": true, \"title\": \"Tauri App\", \"width\": 800 } ] } } ```",
"type": "object",
"properties": {
"$schema": {
Expand Down

0 comments on commit 67b7ca6

Please sign in to comment.