1#![allow(clippy::needless_lifetimes)]
2
3use crate::prelude::*;
4use leptos_config::LeptosOptions;
5use leptos_macro::{component, view};
6
7#[component]
11pub fn AutoReload(
12 #[prop(optional)]
14 disable_watch: bool,
15 options: LeptosOptions,
17) -> impl IntoView {
18 (!disable_watch && std::env::var("LEPTOS_WATCH").is_ok()).then(|| {
19 #[cfg(feature = "nonce")]
20 let nonce = crate::nonce::use_nonce();
21 #[cfg(not(feature = "nonce"))]
22 let nonce = None::<()>;
23
24 let reload_port = match options.reload_external_port {
25 Some(val) => val,
26 None => options.reload_port,
27 };
28 let protocol = match options.reload_ws_protocol {
29 leptos_config::ReloadWSProtocol::WS => "'ws://'",
30 leptos_config::ReloadWSProtocol::WSS => "'wss://'",
31 };
32
33 let script = format!(
34 "(function (reload_port, protocol) {{ {} {} }})({reload_port:?}, \
35 {protocol})",
36 leptos_hot_reload::HOT_RELOAD_JS,
37 include_str!("reload_script.js")
38 );
39 view! { <script nonce=nonce>{script}</script> }
40 })
41}
42
43#[component]
47pub fn HydrationScripts(
48 options: LeptosOptions,
50 #[prop(optional)]
52 islands: bool,
53 #[prop(optional, into)]
55 root: Option<String>,
56) -> impl IntoView {
57 let mut js_file_name = options.output_name.to_string();
58 let mut wasm_file_name = options.output_name.to_string();
59 if options.hash_files {
60 let hash_path = std::env::current_exe()
61 .map(|path| {
62 path.parent().map(|p| p.to_path_buf()).unwrap_or_default()
63 })
64 .unwrap_or_default()
65 .join(options.hash_file.as_ref());
66 if hash_path.exists() {
67 let hashes = std::fs::read_to_string(&hash_path)
68 .expect("failed to read hash file");
69 for line in hashes.lines() {
70 let line = line.trim();
71 if !line.is_empty() {
72 if let Some((file, hash)) = line.split_once(':') {
73 if file == "js" {
74 js_file_name.push_str(&format!(".{}", hash.trim()));
75 } else if file == "wasm" {
76 wasm_file_name
77 .push_str(&format!(".{}", hash.trim()));
78 }
79 }
80 }
81 }
82 }
83 } else if std::option_env!("LEPTOS_OUTPUT_NAME").is_none() {
84 wasm_file_name.push_str("_bg");
85 }
86
87 let pkg_path = &options.site_pkg_dir;
88 #[cfg(feature = "nonce")]
89 let nonce = crate::nonce::use_nonce();
90 #[cfg(not(feature = "nonce"))]
91 let nonce = None::<String>;
92 let script = if islands {
93 if let Some(sc) = Owner::current_shared_context() {
94 sc.set_is_hydrating(false);
95 }
96 include_str!("./island_script.js")
97 } else {
98 include_str!("./hydration_script.js")
99 };
100
101 let root = root.unwrap_or_default();
102 view! {
103 <link rel="modulepreload" href=format!("{root}/{pkg_path}/{js_file_name}.js") nonce=nonce.clone()/>
104 <link
105 rel="preload"
106 href=format!("{root}/{pkg_path}/{wasm_file_name}.wasm")
107 r#as="fetch"
108 r#type="application/wasm"
109 crossorigin=nonce.clone().unwrap_or_default()
110 />
111 <script type="module" nonce=nonce>
112 {format!("{script}({root:?}, {pkg_path:?}, {js_file_name:?}, {wasm_file_name:?})")}
113 </script>
114 }
115}