script.rs 3.9 KB

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