Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/supersede-kuchikiki.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri-utils": minor:deps
---

Add new `html-manipulation-2` and `build-2` feature flags that use `dom_query` instead of `kuchikiki` for HTML parsing / manipulation.
This allows downstream users to remove `kuchikiki` and its dependencies from their dependency tree.
24 changes: 12 additions & 12 deletions 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 crates/tauri-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ anyhow = "1"
quote = { version = "1", optional = true }
tauri-codegen = { version = "2.5.5", path = "../tauri-codegen", optional = true }
tauri-utils = { version = "2.8.3", path = "../tauri-utils", features = [
"build",
"build-2",
"resources",
] }
cargo_toml = "0.22"
Expand Down
4 changes: 1 addition & 3 deletions crates/tauri-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ tauri-utils = { version = "2.8.3", path = "../tauri-utils", features = [
"schema",
"config-json5",
"config-toml",
"html-manipulation",
"html-manipulation-2",
] }
toml = "1"
jsonschema = { version = "0.33", default-features = false }
Expand All @@ -89,8 +89,6 @@ env_logger = "0.11"
icns = { package = "tauri-icns", version = "0.1" }
image = { version = "0.25", default-features = false, features = ["ico"] }
axum = { version = "0.8", features = ["ws"] }
html5ever = "0.29"
kuchiki = { package = "kuchikiki", version = "=0.8.8-speedreader" }
tokio = { version = "1", features = ["macros", "sync"] }
common-path = "1"
serde-value = "0.7"
Expand Down
30 changes: 6 additions & 24 deletions crates/tauri-cli/src/dev/builtin_dev_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ use axum::{
http::{header, StatusCode, Uri},
response::{IntoResponse, Response},
};
use html5ever::{namespace_url, ns, LocalName, QualName};
use kuchiki::{traits::TendrilSink, NodeRef};
use std::{
net::{IpAddr, SocketAddr},
path::{Path, PathBuf},
Expand Down Expand Up @@ -128,30 +126,14 @@ async fn ws_handler(ws: WebSocketUpgrade, state: State<ServerState>) -> Response
}

fn inject_address(html_bytes: Vec<u8>, address: &SocketAddr) -> Vec<u8> {
fn with_html_head<F: FnOnce(&NodeRef)>(document: &mut NodeRef, f: F) {
if let Ok(ref node) = document.select_first("head") {
f(node.as_node())
} else {
let node = NodeRef::new_element(
QualName::new(None, ns!(html), LocalName::from("head")),
None,
);
f(&node);
document.prepend(node)
}
}
let document = tauri_utils::html2::parse_doc(String::from_utf8_lossy(&html_bytes).into_owned());

let mut document = kuchiki::parse_html()
.one(String::from_utf8_lossy(&html_bytes).into_owned())
.document_node;
with_html_head(&mut document, |head| {
let script = RELOAD_SCRIPT.replace("{{reload_url}}", &format!("ws://{address}/__tauri_cli"));
let script_el = NodeRef::new_element(QualName::new(None, ns!(html), "script".into()), None);
script_el.append(NodeRef::new_text(script));
head.prepend(script_el);
});
tauri_utils::html2::append_script_to_head(
&document,
&RELOAD_SCRIPT.replace("{{reload_url}}", &format!("ws://{address}/__tauri_cli")),
);

tauri_utils::html::serialize_node(&document)
tauri_utils::html2::serialize_doc(&document)
}

fn fs_read_scoped(path: PathBuf, scope: &Path) -> crate::Result<Vec<u8>> {
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri-codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ syn = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tauri-utils = { version = "2.8.3", path = "../tauri-utils", features = [
"build",
"build-2",
] }
thiserror = "2"
walkdir = "2"
Expand Down
54 changes: 26 additions & 28 deletions crates/tauri-codegen/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use tauri_utils::{
},
assets::AssetKey,
config::{Config, FrontendDist, PatternKind},
html::{inject_nonce_token, parse as parse_html, serialize_node as serialize_html_node, NodeRef},
html2::{inject_nonce_token, parse_doc, serialize_doc, Document},
platform::Target,
tokens::{map_lit, str_lit},
};
Expand All @@ -44,27 +44,25 @@ pub struct ContextData {
pub test: bool,
}

fn inject_script_hashes(document: &NodeRef, key: &AssetKey, csp_hashes: &mut CspHashes) {
if let Ok(inline_script_elements) = document.select("script:not(:empty)") {
let mut scripts = Vec::new();
for inline_script_el in inline_script_elements {
let script = inline_script_el.as_node().text_contents();
let mut hasher = Sha256::new();
hasher.update(tauri_utils::html::normalize_script_for_csp(
script.as_bytes(),
));
let hash = hasher.finalize();
scripts.push(format!(
"'sha256-{}'",
base64::engine::general_purpose::STANDARD.encode(hash)
));
}
csp_hashes
.inline_scripts
.entry(key.clone().into())
.or_default()
.append(&mut scripts);
}
fn inject_script_hashes(document: &Document, key: &AssetKey, csp_hashes: &mut CspHashes) {
let script_elements = document.select("script:not(:empty)");

let scripts = script_elements
.iter()
.map(|element| {
let script = tauri_utils::html2::normalize_script_for_csp(element.text().as_bytes());
let script_hash = Sha256::digest(script);
let hash_base64 = base64::engine::general_purpose::STANDARD.encode(script_hash);

format!("'sha256-{hash_base64}'")
})
.collect::<Vec<_>>();

csp_hashes
.inline_scripts
.entry(key.clone().into())
.or_default()
.extend(scripts);
}

fn map_core_assets(
Expand All @@ -77,15 +75,15 @@ fn map_core_assets(
if path.extension() == Some(OsStr::new("html")) {
#[allow(clippy::collapsible_if)]
if csp {
let document = parse_html(String::from_utf8_lossy(input).into_owned());
let document = parse_doc(String::from_utf8_lossy(input).into_owned());

inject_nonce_token(&document, &dangerous_disable_asset_csp_modification);

if dangerous_disable_asset_csp_modification.can_modify("script-src") {
inject_script_hashes(&document, key, csp_hashes);
}

*input = serialize_html_node(&document);
*input = serialize_doc(&document);
}
}
Ok(())
Expand All @@ -108,13 +106,13 @@ fn map_isolation(

move |key, path, input, csp_hashes| {
if path.extension() == Some(OsStr::new("html")) {
let isolation_html = parse_html(String::from_utf8_lossy(input).into_owned());
let isolation_html = parse_doc(String::from_utf8_lossy(input).into_owned());

// this is appended, so no need to reverse order it
tauri_utils::html::inject_codegen_isolation_script(&isolation_html);
tauri_utils::html2::inject_codegen_isolation_script(&isolation_html);

// temporary workaround for windows not loading assets
tauri_utils::html::inline_isolation(&isolation_html, &dir);
tauri_utils::html2::inline_isolation(&isolation_html, &dir);

inject_nonce_token(
&isolation_html,
Expand All @@ -125,7 +123,7 @@ fn map_isolation(

csp_hashes.styles.push(iframe_style_csp_hash.clone());

*input = isolation_html.to_string().as_bytes().to_vec()
*input = serialize_doc(&isolation_html)
}

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri-codegen/src/embedded_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ impl CspHashes {
let mut hasher = Sha256::new();
hasher.update(
&std::fs::read(path)
.map(|b| tauri_utils::html::normalize_script_for_csp(&b))
.map(|b| tauri_utils::html2::normalize_script_for_csp(&b))
.map_err(|error| EmbeddedAssetsError::AssetRead {
path: path.to_path_buf(),
error,
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri-plugin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ runtime = []
anyhow = { version = "1", optional = true }
serde = { version = "1", optional = true }
tauri-utils = { version = "2.8.3", default-features = false, features = [
"build",
"build-2",
], path = "../tauri-utils" }
serde_json = { version = "1", optional = true }
glob = { version = "0.3", optional = true }
Expand Down
12 changes: 12 additions & 0 deletions crates/tauri-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ brotli = { version = "8", optional = true, default-features = false, features =
url = { version = "2", features = ["serde"] }
html5ever = { version = "0.29", optional = true }
kuchiki = { package = "kuchikiki", version = "0.8.8-speedreader", optional = true }
dom_query = { version = "0.27", optional = true, default-features = false }
proc-macro2 = { version = "1", optional = true }
quote = { version = "1", optional = true }
# Our code requires at least 0.8.21 so don't change this to 0.8
Expand Down Expand Up @@ -59,6 +60,7 @@ swift-rs = { version = "1", optional = true, features = ["build"] }
getrandom = { version = "0.3", features = ["std"] }
serial_test = "3"
tauri = { path = "../tauri" }
tempfile = "3.15.0"

[features]
build = [
Expand All @@ -69,6 +71,15 @@ build = [
"swift-rs",
"html-manipulation",
]
# Same as `build` but uses `html-manipulation-2` to avoid the `kuchikiki` dependency.
build-2 = [
"proc-macro2",
"quote",
"cargo_metadata",
"schema",
"swift-rs",
"html-manipulation-2",
]
compression = ["brotli"]
schema = ["schemars"]
isolation = ["aes-gcm", "getrandom", "serialize-to-javascript"]
Expand All @@ -77,3 +88,4 @@ config-json5 = ["json5"]
config-toml = []
resources = ["walkdir"]
html-manipulation = ["dep:html5ever", "dep:kuchiki"]
html-manipulation-2 = ["dep:dom_query"]
2 changes: 1 addition & 1 deletion crates/tauri-utils/src/acl/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl FromStr for CapabilityFile {
}
}

#[cfg(feature = "build")]
#[cfg(any(feature = "build", feature = "build-2"))]
mod build {
use std::convert::identity;

Expand Down
2 changes: 1 addition & 1 deletion crates/tauri-utils/src/acl/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ mod tests {
}
}

#[cfg(feature = "build")]
#[cfg(any(feature = "build", feature = "build-2"))]
mod build {
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri-utils/src/acl/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl Manifest {
}
}

#[cfg(feature = "build")]
#[cfg(any(feature = "build", feature = "build-2"))]
mod build {
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
Expand Down
Loading
Loading