Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deduplicate serve code with hot reloading in the CLI crate #1446

Merged
merged 1 commit into from
Sep 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 44 additions & 69 deletions packages/cli/src/server/desktop/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
server::{
output::{print_console_info, PrettierOptions},
setup_file_watcher, setup_file_watcher_hot_reload,
setup_file_watcher,
},
BuildResult, CrateConfig, Result,
};
Expand All @@ -19,6 +19,8 @@ use tokio::sync::broadcast::{self};
#[cfg(feature = "plugin")]
use plugin::PluginManager;

use super::HotReloadState;

pub async fn startup(config: CrateConfig) -> Result<()> {
// ctrl-c shutdown checker
let _crate_config = config.clone();
Expand All @@ -28,16 +30,36 @@ pub async fn startup(config: CrateConfig) -> Result<()> {
std::process::exit(0);
});

match config.hot_reload {
true => serve_hot_reload(config).await?,
false => serve_default(config).await?,
}
let hot_reload_state = match config.hot_reload {
true => {
let FileMapBuildResult { map, errors } =
FileMap::<HtmlCtx>::create(config.crate_dir.clone()).unwrap();

for err in errors {
log::error!("{}", err);
}

let file_map = Arc::new(Mutex::new(map));

let hot_reload_tx = broadcast::channel(100).0;

clear_paths();

Some(HotReloadState {
messages: hot_reload_tx.clone(),
file_map: file_map.clone(),
})
}
false => None,
};

serve(config, hot_reload_state).await?;

Ok(())
}

/// Start the server without hot reload
pub async fn serve_default(config: CrateConfig) -> Result<()> {
pub async fn serve(config: CrateConfig, hot_reload_state: Option<HotReloadState>) -> Result<()> {
let (child, first_build_result) = start_desktop(&config)?;
let currently_running_child: RwLock<Child> = RwLock::new(child);

Expand All @@ -59,6 +81,7 @@ pub async fn serve_default(config: CrateConfig) -> Result<()> {
},
&config,
None,
hot_reload_state.clone(),
)
.await?;

Expand All @@ -73,79 +96,29 @@ pub async fn serve_default(config: CrateConfig) -> Result<()> {
None,
);

std::future::pending::<()>().await;
match hot_reload_state {
Some(hot_reload_state) => {
start_desktop_hot_reload(hot_reload_state).await?;
}
None => {
std::future::pending::<()>().await;
}
}

Ok(())
}

/// Start the server without hot reload

/// Start dx serve with hot reload
pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
let (_, first_build_result) = start_desktop(&config)?;

println!("🚀 Starting development server...");

// Setup hot reload
let FileMapBuildResult { map, errors } =
FileMap::<HtmlCtx>::create(config.crate_dir.clone()).unwrap();

println!("🚀 Starting development server...");

for err in errors {
log::error!("{}", err);
}

let file_map = Arc::new(Mutex::new(map));

let (hot_reload_tx, mut hot_reload_rx) = broadcast::channel(100);

// States
// The open interprocess sockets
let channels = Arc::new(Mutex::new(Vec::new()));

// Setup file watcher
// We got to own watcher so that it exists for the duration of serve
// Otherwise hot reload won't work.
let _watcher = setup_file_watcher_hot_reload(
&config,
hot_reload_tx,
file_map.clone(),
{
let config = config.clone();

let channels = channels.clone();
move || {
for channel in &mut *channels.lock().unwrap() {
send_msg(HotReloadMsg::Shutdown, channel);
}
Ok(start_desktop(&config)?.1)
}
},
None,
)
.await?;

// Print serve info
print_console_info(
&config,
PrettierOptions {
changed: vec![],
warnings: first_build_result.warnings,
elapsed_time: first_build_result.elapsed_time,
},
None,
);

clear_paths();

async fn start_desktop_hot_reload(hot_reload_state: HotReloadState) -> Result<()> {
match LocalSocketListener::bind("@dioxusin") {
Ok(local_socket_stream) => {
let aborted = Arc::new(Mutex::new(false));
// States
// The open interprocess sockets
let channels = Arc::new(Mutex::new(Vec::new()));

// listen for connections
std::thread::spawn({
let file_map = file_map.clone();
let file_map = hot_reload_state.file_map.clone();
let channels = channels.clone();
let aborted = aborted.clone();
let _ = local_socket_stream.set_nonblocking(true);
Expand Down Expand Up @@ -180,6 +153,8 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
}
});

let mut hot_reload_rx = hot_reload_state.messages.subscribe();

while let Ok(template) = hot_reload_rx.recv().await {
let channels = &mut *channels.lock().unwrap();
let mut i = 0;
Expand Down
Loading