vite_rs_dev_server/
lib.rs

1#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
2use command_group::GroupChild;
3
4#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
5#[cfg(feature = "ctrlc")]
6pub use ctrlc;
7
8#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
9pub use reqwest; // exported for use in derived code
10
11#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
12use std::sync::{Arc, Mutex};
13
14pub mod util;
15
16#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
17pub struct ViteProcess(pub Arc<Mutex<GroupChild>>);
18
19#[cfg(any(not(debug_assertions), feature = "debug-prod"))]
20pub struct ViteProcess;
21
22#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
23lazy_static::lazy_static! {
24    static ref VITE_PROCESS: Arc<Mutex<Option<ViteProcess>>> = Arc::new(Mutex::new(None));
25}
26
27#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
28fn set_dev_server(process: ViteProcess) {
29    let original = VITE_PROCESS.lock().unwrap().replace(process);
30    if original.is_some() {
31        original
32            .unwrap()
33            .0
34            .lock()
35            .expect("(!) Could not shutdown ViteJS dev server: Mutex poisoned")
36            .kill()
37            .expect("(!) Could not shutdown ViteJS dev server.");
38    }
39}
40
41#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
42fn unset_dev_server() {
43    let process = VITE_PROCESS.lock().unwrap().take();
44    if process.is_some() {
45        process
46            .unwrap()
47            .0
48            .lock()
49            .expect("(!) Could not shutdown ViteJS dev server: Mutex poisoned")
50            .kill()
51            .expect("(!) Could not shutdown ViteJS dev server.");
52    }
53}
54
55#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
56impl Drop for ViteProcess {
57    fn drop(&mut self) {
58        unset_dev_server();
59    }
60}
61
62/// Starts the ViteJS dev server.
63///
64/// Example 1 (with the included `ctrlc` feature enabled):
65///
66/// ```ignore
67/// fn main() {
68///     #[cfg(debug_assertions)]
69///     let _guard = Assets::start_dev_server(true);
70///
71///    // ...
72/// }
73/// ```
74///
75/// Example 2 (using the `ctrlc` crate to handle Ctrl-C):
76///
77/// ```ignore
78/// fn main() {
79///   #[cfg(debug_assertions)]
80///   let _guard = Assets::start_dev_server();
81///
82///   ctrlc::try_set_handler(|| {
83///     #[cfg(debug_assertions)]
84///     Assets::stop_dev_server();
85///     std::process::exit(0);
86///  }).unwrap();
87/// }
88///
89/// ```
90#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
91pub fn start_dev_server(
92    absolute_root_dir: &str,
93    host: &str,
94    port: u16,
95    #[cfg(feature = "ctrlc")] register_ctrl_c_handler: bool,
96) -> Option<ViteProcess> {
97    use command_group::CommandGroup;
98
99    if !util::is_port_free(port as u16) {
100        panic!(
101            "Selected vite-rs dev server port '{}' is not available.\na) If self-selecting a port via #[dev_server_port = XXX], ensure it is free.\nb) Otherwise, remove the #[dev_server_port] attribute and let vite-rs select a free port for you at compile time.",
102            port
103        )
104    }
105
106    // println!("Starting dev server!");
107    // start ViteJS dev server
108    let child = Arc::new(Mutex::new(
109        std::process::Command::new("npx")
110            .arg("vite")
111            .arg("--host")
112            .arg(host)
113            .arg("--port")
114            .arg(port.to_string())
115            .arg("--strictPort")
116            .arg("--clearScreen")
117            .arg("false")
118            // we don't want to send stdin to the dev server; this also
119            // hides the "press h + enter to show help" message that the dev server prints
120            .stdin(std::process::Stdio::null())
121            .current_dir(
122                absolute_root_dir, /*format!(
123                                       "{}/examples/basic_usage",
124                                       std::env::var("CARGO_MANIFEST_DIR").unwrap()
125                                   )*/
126            )
127            .group_spawn()
128            .expect("failed to start ViteJS dev server"),
129    ));
130    set_dev_server(ViteProcess(child.clone()));
131
132    #[cfg(feature = "ctrlc")]
133    {
134        if register_ctrl_c_handler {
135            // We handle Ctrl-C because the node process does not exit properly otherwise
136            ctrlc::try_set_handler({
137                move || {
138                    unset_dev_server();
139                    std::process::exit(0);
140                }
141            })
142            .expect("vite-rs: Error setting Ctrl-C handler; if you are using a custom one, disable the ctrlc feature for the vite-rs crate, and follow the documentation here to integrate it: https://github.com/Wulf/vite-rs#ctrl-c-handler");
143        }
144    }
145
146    // We build an RAII guard around the child process so that the dev server is killed when it's dropped
147    Some(ViteProcess(child.clone()))
148}
149
150#[cfg(any(not(debug_assertions), feature = "debug-prod"))]
151pub fn start_dev_server(
152    #[cfg(feature = "ctrlc")] _register_ctrl_c_handler: bool,
153) -> Option<ViteProcess> {
154    None
155}
156
157#[cfg(all(debug_assertions, not(feature = "debug-prod")))]
158pub fn stop_dev_server() {
159    unset_dev_server();
160}
161
162#[cfg(any(not(debug_assertions), feature = "debug-prod"))]
163pub fn stop_dev_server() {
164    // do nothing
165}