vite_rust/config.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
use std::env;
use crate::utils::check_heart_beat;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ViteMode {
Development,
Manifest,
}
impl ViteMode {
pub(crate) async fn discover(
use_hb: bool,
use_dev_server: bool,
host: &str,
hb_retries: u8,
) -> ViteMode {
if !use_hb {
return ViteMode::Development;
}
if !use_dev_server {
return ViteMode::Manifest;
}
if is_production() {
return ViteMode::Manifest;
}
let dev_server_is_ok = check_heart_beat(host, None, hb_retries).await;
match dev_server_is_ok {
true => ViteMode::Development,
false => ViteMode::Manifest,
}
}
}
fn is_production() -> bool {
env::vars().any(|(k, v)| {
if ["RUST_ENV", "NODE_ENV", "APP_ENV", "__TEST_APP_ENV"].contains(&k.as_str()) {
return v == "production";
}
false
})
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ViteConfig<'a> {
/// The `path/to/manifest.json` file.
/// Currently, Vite won't resolve relative paths, so please consider
/// your current working directory as the root of it and start the path
/// with a root node directory directly.
///
/// **Optionally and experimentally**, you can use the [`resolve_path`]
/// method for the manifest file resolution. However, this method might
/// come to fail at some point, and will also panic in the many situations
/// described on its documentation.
///
/// # Example
/// ```plaintext
/// your_project/
/// |-- public/
/// | |-- dist/
/// | | |-- manifest.json
/// |-- src/
/// | |-- main.rs // <-- you're here!
/// ```
///
/// ```ignore
///
/// use vite_rust::{ViteConfig, utils::resolve_path};
///
/// let config = ViteConfig {
/// manifest_path: Some("public/dist/manifest.json"),
/// // or
/// manifest_path: Some(resolve_path(file!(), "../public/dist/manifest.json")),
/// // ...
/// };
/// ```
pub manifest_path: Option<&'a str>,
/// Defines which entrypoints Vite will use to generate the html `script`,
/// `link` and `stylesheet` tags.
///
/// If `None` is provided, Vite will scan the manifest for files with
/// `isEntry: true` property and consider them the entrypoints.
pub entrypoints: Option<Vec<&'a str>>,
/// If `None` is provided, Vite will discover which one to use considering:
/// - any of `RUST_ENV`, `NODE_ENV` or `APP_ENV` environment variables exists
/// and is set to `true`;
/// - Dev-server is running;
/// - Heart beat check is enabled.
///
/// By setting this option, the discovering phase will be skipped.
/// Refer to the crate's `README.md` file to understand the way it decides which mode to pick.
pub force_mode: Option<ViteMode>,
/// Whether Vite should ping your vite dev-server to check if its running.
/// If false, `ViteMode` will be set to `Development` if not forced by the configuration.
pub use_heart_beat_check: bool,
/// How many times heartbeat checker should try before fallbacking.
pub heart_beat_retries_limit: Option<u8>,
/// Whether dev server should be considered or not.
///
/// If false, `force_mode` should be either `Manifest` or `None`,
/// otherwise, undefined behavior might occur.
pub enable_dev_server: bool,
/// The host in which your vite dev-server is running.
/// Normally, it would be `"http://localhost:5173"`.
///
/// Please, do not forget the protocol (http, https)!
pub server_host: Option<&'a str>,
}
impl<'a> ViteConfig<'a> {
/// Creates a new `ViteConfig` instance with `manifest_path` and `entrypoints` fields set.
pub fn new(manifest_path: &'a str, entrypoints: Vec<&'a str>) -> Self {
ViteConfig::default()
.set_manifest_path(manifest_path)
.set_entrypoints(entrypoints)
}
pub fn set_manifest_path(mut self, manifest_path: &'a str) -> Self {
self.manifest_path = Some(manifest_path);
self
}
pub fn set_entrypoints(mut self, entrypoints: Vec<&'a str>) -> Self {
self.entrypoints = Some(entrypoints);
self
}
pub fn set_force_mode(mut self, mode: ViteMode) -> Self {
self.force_mode = Some(mode);
self
}
pub fn set_server_host(mut self, server_host: &'a str) -> Self {
self.server_host = Some(server_host);
self
}
pub fn set_heart_beat_retries_limit(mut self, limit: u8) -> Self {
self.heart_beat_retries_limit = Some(limit);
self
}
pub fn without_heart_beat_check(mut self) -> Self {
self.use_heart_beat_check = false;
self
}
pub fn without_dev_server(mut self) -> Self {
self.enable_dev_server = false;
self
}
}
impl Default for ViteConfig<'_> {
/// Create a `ViteConfig` instance.
///
/// You can create your config by directly instantiating the struct, or
/// by using some default options. Note that you **must set the manifest
/// path**.
///
/// # Example
/// ```rust
/// use vite_rust::ViteConfig;
///
/// let manual_config = ViteConfig {
/// manifest_path: Some("path/to/manifest.json"),
/// entrypoints: None, // Vite can discover them by itself
/// force_mode: None, // Vite can discover it too
/// use_heart_beat_check: true,
/// enable_dev_server: true,
/// server_host: Some("http://localhost:5173"),
/// heart_beat_retries_limit: Some(5),
/// };
///
/// let with_defaults_config = ViteConfig::default().set_manifest_path("path/to/manifest.json");
///
/// assert_eq!(manual_config, with_defaults_config);
/// ```
fn default() -> Self {
Self {
enable_dev_server: true,
entrypoints: None,
manifest_path: None,
force_mode: None,
server_host: Some("http://localhost:5173"),
use_heart_beat_check: true,
heart_beat_retries_limit: Some(5),
}
}
}
#[cfg(test)]
mod test {
use std::env;
use crate::{config::is_production, ViteMode};
#[tokio::test]
async fn test_discover() {
let host = "http://localhost:3000";
let hb_retries = 1;
assert_eq!(
ViteMode::Development,
ViteMode::discover(false, true, host, hb_retries).await
);
assert_eq!(
ViteMode::Manifest,
ViteMode::discover(true, false, host, hb_retries).await
);
}
#[test]
fn test_is_production() {
env::set_var("__TEST_APP_ENV", "production");
assert!(is_production());
env::remove_var("__TEST_APP_ENV");
assert!(!is_production());
}
}