Don't use inline scripts and function constructor (#4310)

* Don't use inline scripts and function constructor.

This allows a stricter Content-Security-Policy which is required for web extensions.

* Load module scripts asynchronously

* Extract common code into method

* Fix injecting loading script

* Append to the file instead of reading and appending to the file string

---------

Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-06-26 12:08:02 -05:00
1 parent 0dd0f05db0
commit 6cc379718b
5 files changed
+114 -70

No files matched your search

+28 -14
View File
@@ -1,8 +1,7 @@
use dioxus_core::prelude::queue_effect;
use dioxus_core::ScopeId;
use dioxus_document::{
create_element_in_head, Document, Eval, EvalError, Evaluator, LinkProps, MetaProps,
ScriptProps, StyleProps,
Document, Eval, EvalError, Evaluator, LinkProps, MetaProps, ScriptProps, StyleProps,
};
use dioxus_history::History;
use futures_util::FutureExt;
@@ -97,45 +96,60 @@ impl Document for WebDocument {
/// Create a new meta tag in the head
fn create_meta(&self, props: MetaProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head("meta", &props.attributes(), None));
append_element_to_head("meta", &props.attributes(), None);
});
}
/// Create a new script tag in the head
fn create_script(&self, props: ScriptProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head(
append_element_to_head(
"script",
&props.attributes(),
props.script_contents().ok(),
));
props.script_contents().ok().as_deref(),
);
});
}
/// Create a new style tag in the head
fn create_style(&self, props: StyleProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head(
append_element_to_head(
"style",
&props.attributes(),
props.style_contents().ok(),
));
props.style_contents().ok().as_deref(),
);
});
}
/// Create a new link tag in the head
fn create_link(&self, props: LinkProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head("link", &props.attributes(), None));
append_element_to_head("link", &props.attributes(), None);
});
}
}
fn append_element_to_head(
local_name: &str,
attributes: &Vec<(&'static str, String)>,
text_content: Option<&str>,
) {
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let head = document.head().expect("document should have a head");
let element = document.create_element(local_name).unwrap();
for (name, value) in attributes {
element.set_attribute(name, value).unwrap();
}
if text_content.is_some() {
element.set_text_content(text_content);
}
head.append_child(&element).unwrap();
}
/// Required to avoid blocking the Rust WASM thread.
const PROMISE_WRAPPER: &str = r#"
return (async function(){