Skip to main content

nfw_core/hmr/
reload.rs

1use crate::routing::Route;
2
3pub struct ModuleReloader {
4    cache: std::collections::HashMap<String, ModuleState>,
5}
6
7#[derive(Debug, Clone)]
8pub enum ModuleState {
9    Loaded,
10    Reloading,
11    Failed(String),
12}
13
14impl ModuleReloader {
15    pub fn new() -> Self {
16        Self {
17            cache: std::collections::HashMap::new(),
18        }
19    }
20
21    pub fn mark_loading(&mut self, module_path: &str) {
22        self.cache
23            .insert(module_path.to_string(), ModuleState::Reloading);
24    }
25
26    pub fn mark_loaded(&mut self, module_path: &str) {
27        self.cache
28            .insert(module_path.to_string(), ModuleState::Loaded);
29    }
30
31    pub fn mark_failed(&mut self, module_path: &str, error: String) {
32        self.cache
33            .insert(module_path.to_string(), ModuleState::Failed(error));
34    }
35
36    pub fn get_state(&self, module_path: &str) -> Option<&ModuleState> {
37        self.cache.get(module_path)
38    }
39}
40
41impl Default for ModuleReloader {
42    fn default() -> Self {
43        Self::new()
44    }
45}
46
47pub struct HotReloader {
48    #[allow(dead_code)]
49    reloader: ModuleReloader,
50    routes: Vec<Route>,
51}
52
53impl HotReloader {
54    pub fn new(routes: Vec<Route>) -> Self {
55        Self {
56            reloader: ModuleReloader::new(),
57            routes,
58        }
59    }
60
61    pub fn reload_page(&self, page_path: &str) -> anyhow::Result<String> {
62        let route = self.routes.iter().find(|r| r.path == page_path);
63
64        match route {
65            Some(route) => {
66                tracing::info!("Hot reloading page: {}", route.file_path);
67                Ok(format!("Reloaded: {}", route.file_path))
68            }
69            None => {
70                anyhow::bail!("Page not found: {}", page_path)
71            }
72        }
73    }
74
75    pub fn get_module_dependencies(&self, module_path: &str) -> Vec<String> {
76        let mut deps = Vec::new();
77
78        for route in &self.routes {
79            if route.file_path.contains(module_path) {
80                deps.push(route.file_path.clone());
81            }
82        }
83
84        deps
85    }
86
87    pub fn generate_vite_config(&self) -> String {
88        r#"
89import { defineConfig } from 'vite';
90import react from '@vitejs/plugin-react';
91import nestforgeWeb from 'nestforge-web/vite';
92
93export default defineConfig({
94    plugins: [
95        react(),
96        nestforgeWeb({
97            hotReload: true,
98            hmrPort: 3001,
99        }),
100    ],
101    server: {
102        port: 3000,
103    },
104});
105"#
106        .to_string()
107    }
108}