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
use crate::{builder::BuildConfig, cli::DevelopOptions, config::Config, error::Result};
use async_std::{channel, prelude::FutureExt};
use async_std::future;
use async_std::prelude::*;
use log::info;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::path::PathBuf;
use std::time::Duration;
pub struct DevelopConfig {}
impl Into<DevelopConfig> for DevelopOptions {
fn into(self) -> DevelopConfig {
DevelopConfig {}
}
}
pub async fn start(config: &Config, _options: &DevelopConfig) -> Result<()> {
log::info!("Starting development server 🚀");
let Config { out_dir, .. } = config;
let server = async_std::task::spawn(launch_server(out_dir.clone()));
let watcher = async_std::task::spawn(watch_directory(config.clone()));
match server.race(watcher).await {
Err(e) => log::warn!("Error running development server, {:?}", e),
_ => {}
}
Ok(())
}
async fn watch_directory(config: Config) -> Result<()> {
let (watcher_tx, watcher_rx) = async_std::channel::bounded(100);
let mut watcher: RecommendedWatcher = Watcher::new_immediate(move |res| {
async_std::task::block_on(watcher_tx.send(res));
})
.expect("failed to make watcher");
let src_dir = crate::cargo::crate_root()?;
watcher
.watch(src_dir.join("src"), RecursiveMode::Recursive)
.expect("Failed to watch dir");
watcher
.watch(src_dir.join("examples"), RecursiveMode::Recursive)
.expect("Failed to watch dir");
let build_config = BuildConfig::default();
'run: loop {
crate::builder::build(&config, &build_config)?;
let _msg = watcher_rx
.recv()
.join(future::ready(1_usize).delay(Duration::from_millis(2000)))
.await;
info!("File updated, rebuilding app");
}
Ok(())
}
async fn launch_server(outdir: PathBuf) -> Result<()> {
let _crate_dir = crate::cargo::crate_root()?;
let _workspace_dir = crate::cargo::workspace_root()?;
let mut app = tide::with_state(ServerState::new(outdir.to_owned()));
let p = outdir.display().to_string();
app.at("/")
.get(|req: tide::Request<ServerState>| async move {
log::info!("Connected to development server");
let state = req.state();
Ok(tide::Body::from_file(state.serv_path.clone().join("index.html")).await?)
})
.serve_dir(p)?;
let port = "8080";
let serve_addr = format!("127.0.0.1:{}", port);
info!("App available at http://{}", serve_addr);
app.listen(serve_addr).await?;
Ok(())
}
#[derive(Clone)]
struct ServerState {
serv_path: PathBuf,
}
impl ServerState {
fn new(serv_path: PathBuf) -> Self {
Self { serv_path }
}
}