dioxus_document/elements/
script.rs

1use super::*;
2use crate::document;
3use dioxus_html as dioxus_elements;
4
5#[non_exhaustive]
6#[derive(Clone, Props, PartialEq)]
7pub struct ScriptProps {
8    /// The contents of the script tag. If present, the children must be a single text node.
9    pub children: Element,
10    /// Scripts are deduplicated by their src attribute
11    pub src: Option<String>,
12    pub defer: Option<bool>,
13    pub crossorigin: Option<String>,
14    pub fetchpriority: Option<String>,
15    pub integrity: Option<String>,
16    pub nomodule: Option<bool>,
17    pub nonce: Option<String>,
18    pub referrerpolicy: Option<String>,
19    pub r#type: Option<String>,
20    #[props(extends = script, extends = GlobalAttributes)]
21    pub additional_attributes: Vec<Attribute>,
22}
23
24impl ScriptProps {
25    /// Get all the attributes for the script tag
26    pub fn attributes(&self) -> Vec<(&'static str, String)> {
27        let mut attributes = Vec::new();
28        extend_attributes(&mut attributes, &self.additional_attributes);
29        if let Some(defer) = &self.defer {
30            attributes.push(("defer", defer.to_string()));
31        }
32        if let Some(crossorigin) = &self.crossorigin {
33            attributes.push(("crossorigin", crossorigin.clone()));
34        }
35        if let Some(fetchpriority) = &self.fetchpriority {
36            attributes.push(("fetchpriority", fetchpriority.clone()));
37        }
38        if let Some(integrity) = &self.integrity {
39            attributes.push(("integrity", integrity.clone()));
40        }
41        if let Some(nomodule) = &self.nomodule {
42            attributes.push(("nomodule", nomodule.to_string()));
43        }
44        if let Some(nonce) = &self.nonce {
45            attributes.push(("nonce", nonce.clone()));
46        }
47        if let Some(referrerpolicy) = &self.referrerpolicy {
48            attributes.push(("referrerpolicy", referrerpolicy.clone()));
49        }
50        if let Some(r#type) = &self.r#type {
51            attributes.push(("type", r#type.clone()));
52        }
53        if let Some(src) = &self.src {
54            attributes.push(("src", src.clone()));
55        }
56        attributes
57    }
58
59    pub fn script_contents(&self) -> Result<String, ExtractSingleTextNodeError<'_>> {
60        extract_single_text_node(&self.children)
61    }
62}
63
64/// Render a [`script`](crate::elements::script) tag into the head of the page.
65///
66///
67/// If present, the children of the script component must be a single static or formatted string. If there are more children or the children contain components, conditionals, loops, or fragments, the script will not be added.
68///
69///
70/// Any scripts you add will be deduplicated by their `src` attribute (if present).
71///
72/// # Example
73/// ```rust, no_run
74/// # use dioxus::prelude::*;
75/// fn LoadScript() -> Element {
76///     rsx! {
77///         // You can use the Script component to render a script tag into the head of the page
78///         document::Script {
79///             src: asset!("/assets/script.js"),
80///         }
81///     }
82/// }
83/// ```
84///
85/// <div class="warning">
86///
87/// Any updates to the props after the first render will not be reflected in the head.
88///
89/// </div>
90#[component]
91pub fn Script(props: ScriptProps) -> Element {
92    use_update_warning(&props, "Script {}");
93
94    use_hook(|| {
95        let document = document();
96        let mut insert_script = document.create_head_component();
97        if let Some(src) = &props.src {
98            if !should_insert_script(src) {
99                insert_script = false;
100            }
101        }
102
103        if !insert_script {
104            return;
105        }
106
107        // Make sure the props are in a valid form - they must either have a source or children
108        if let (None, Err(err)) = (&props.src, props.script_contents()) {
109            // If the script has neither contents nor src, log an error
110            err.log("Script")
111        }
112
113        document.create_script(props);
114    });
115
116    VNode::empty()
117}
118
119#[derive(Default, Clone)]
120struct ScriptContext(DeduplicationContext);
121
122fn should_insert_script(src: &str) -> bool {
123    get_or_insert_root_context::<ScriptContext>()
124        .0
125        .should_insert(src)
126}