This commit is contained in:
YuKun Liu committed 2022-10-03 09:37:26 -07:00
commit 5104f767b3
10 files changed
+234 -355

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ use std::{
process::{Command, Stdio},
};
/// Build, bundle, & ship your Dioxus app.
/// Build, Bundle & Ship Dioxus Apps.
#[derive(Parser)]
#[clap(name = "dioxus", version)]
pub struct Cli {
+1 -1
View File
@@ -56,7 +56,7 @@ impl Serve {
}
return Ok(());
} else if platform != "web" {
return custom_error!("Unsoppurt platform target.");
return custom_error!("Unsupported platform target.");
}
// generate dev-index page
+1
View File
@@ -6,6 +6,7 @@ pub enum DiffResult {
RsxChanged(Vec<(Macro, TokenStream)>),
}
/// Find any rsx calls in the given file and return a list of all the rsx calls that have changed.
pub fn find_rsx(new: &File, old: &File) -> DiffResult {
let mut rsx_calls = Vec::new();
if new.items.len() != old.items.len() {
+40 -56
View File
@@ -2,14 +2,14 @@ use axum::{
extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade},
response::IntoResponse,
};
use dioxus_rsx_interpreter::SetRsxMessage;
use dioxus_core::{prelude::TemplateId, CodeLocation, OwnedCodeLocation, SetTemplateMsg};
use dioxus_rsx::try_parse_template;
use std::{path::PathBuf, sync::Arc};
use super::BuildManager;
pub use crate::hot_reload::{find_rsx, DiffResult};
use crate::CrateConfig;
pub use dioxus_rsx_interpreter::{error::Error, CodeLocation, SetManyRsxMessage};
pub use proc_macro2::TokenStream;
pub use std::collections::HashMap;
pub use std::sync::Mutex;
@@ -21,7 +21,7 @@ use syn::spanned::Spanned;
use tokio::sync::broadcast;
pub struct HotReloadState {
pub messages: broadcast::Sender<SetManyRsxMessage>,
pub messages: broadcast::Sender<SetTemplateMsg>,
pub build_manager: Arc<BuildManager>,
pub last_file_rebuild: Arc<Mutex<FileMap>>,
pub watcher_config: CrateConfig,
@@ -91,10 +91,12 @@ pub async fn hot_reload_handler(
}
}
let mut new_str = String::new();
file.read_to_string(&mut new_str).expect("Unable to read file");
file.read_to_string(&mut new_str)
.expect("Unable to read file");
if let Ok(new_file) = syn::parse_file(&new_str) {
if let Ok(old_file) = syn::parse_file(&v) {
if let DiffResult::RsxChanged(changed) = find_rsx(&new_file, &old_file) {
if let DiffResult::RsxChanged(changed) = find_rsx(&new_file, &old_file)
{
for (old, new) in changed.into_iter() {
let hr = get_location(
&state.watcher_config.crate_dir,
@@ -116,72 +118,54 @@ pub async fn hot_reload_handler(
if let Some(last) = lines.last_mut() {
// if there is only one line the start index of last line will be the start of the rsx!, not the start of the line
if start.line == end.line {
*last =
last.split_at(end.column - start.column).0;
*last = last.split_at(end.column - start.column).0;
} else {
*last = last.split_at(end.column).0;
}
}
let rsx = lines.join("\n");
messages.push(SetRsxMessage {
location: hr,
new_text: rsx,
});
let old_dyn_ctx = try_parse_template(
&format!("{}", old.tokens),
hr.to_owned(),
None,
)
.map(|(_, old_dyn_ctx)| old_dyn_ctx);
if let Ok((template, _)) =
try_parse_template(&rsx, hr.to_owned(), old_dyn_ctx.ok())
{
messages.push(SetTemplateMsg(TemplateId(hr), template));
}
}
}
}
}
}
log::info!("finished");
}
let msg = SetManyRsxMessage(messages);
if socket
.send(Message::Text(serde_json::to_string(&msg).unwrap()))
.await
.is_err()
{
return;
for msg in messages {
if socket
.send(Message::Text(serde_json::to_string(&msg).unwrap()))
.await
.is_err()
{
return;
}
}
log::info!("finished");
}
let mut rx = state.messages.subscribe();
let hot_reload_handle = tokio::spawn(async move {
loop {
let read_set_rsx = rx.recv();
let read_err = socket.recv();
tokio::select! {
err = read_err => {
if let Some(Ok(err)) = err {
if let Message::Text(err) = err {
let error: Error = serde_json::from_str(&err).unwrap();
match error{
Error::ParseError(parse_error) => {
log::error!("parse error:\n--> at {}:{}:{}\n\t{:?}", parse_error.location.file_path, parse_error.location.line, parse_error.location.column, parse_error.message);
},
Error::RecompileRequiredError(_) => {
if let Err(err) = state.build_manager.rebuild(){
log::error!("{}", err);
}
}
}
}
} else {
break;
}
},
set_rsx = read_set_rsx => {
if let Ok(rsx) = set_rsx {
if socket
.send(Message::Text(serde_json::to_string(&rsx).unwrap()))
.await
.is_err()
{
break;
};
}
}
};
if let Ok(rsx) = rx.recv().await {
if socket
.send(Message::Text(serde_json::to_string(&rsx).unwrap()))
.await
.is_err()
{
break;
};
}
}
});
@@ -192,10 +176,10 @@ pub async fn hot_reload_handler(
pub fn get_location(crate_path: &Path, path: &Path, ts: TokenStream) -> CodeLocation {
let span = ts.span().start();
let relative = path.strip_prefix(crate_path).unwrap();
CodeLocation {
CodeLocation::Dynamic(Box::new(OwnedCodeLocation {
file_path: relative.display().to_string(),
crate_path: crate_path.display().to_string(),
line: span.line as u32,
column: span.column as u32 + 1,
}
}))
}
+107 -82
View File
@@ -8,8 +8,9 @@ use axum::{
};
use cargo_metadata::diagnostic::Diagnostic;
use colored::Colorize;
use dioxus_rsx_interpreter::SetRsxMessage;
use notify::Watcher;
use dioxus_core::{prelude::TemplateId, SetTemplateMsg};
use dioxus_rsx::try_parse_template;
use notify::{RecommendedWatcher, Watcher};
use syn::spanned::Spanned;
use std::{net::UdpSocket, path::PathBuf, process::Command, sync::Arc};
@@ -108,102 +109,124 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
.unwrap_or_else(|| vec![PathBuf::from("src")]);
let watcher_config = config.clone();
let mut watcher = notify::recommended_watcher(move |evt: notify::Result<notify::Event>| {
let config = watcher_config.clone();
if chrono::Local::now().timestamp() > last_update_time {
// Give time for the change to take effect before reading the file
std::thread::sleep(std::time::Duration::from_millis(100));
let mut updated = false;
if let Ok(evt) = evt {
let mut messages = Vec::new();
let mut needs_rebuild = false;
for path in evt.paths.clone() {
if path.extension().map(|p| p.to_str()).flatten() != Some("rs") {
continue;
}
let mut file = File::open(path.clone()).unwrap();
let mut src = String::new();
file.read_to_string(&mut src).expect("Unable to read file");
// find changes to the rsx in the file
if let Ok(syntax) = syn::parse_file(&src) {
let mut last_file_rebuild = last_file_rebuild.lock().unwrap();
if let Some(old_str) = last_file_rebuild.map.get(&path) {
if let Ok(old) = syn::parse_file(&old_str) {
updated = true;
match find_rsx(&syntax, &old) {
DiffResult::CodeChanged => {
needs_rebuild = true;
last_file_rebuild.map.insert(path, src);
}
DiffResult::RsxChanged(changed) => {
log::info!("🪁 reloading rsx");
for (old, new) in changed.into_iter() {
let hr = get_location(
&crate_dir,
&path.to_path_buf(),
old.to_token_stream(),
);
// get the original source code to preserve whitespace
let span = new.span();
let start = span.start();
let end = span.end();
let mut lines: Vec<_> = src
.lines()
.skip(start.line - 1)
.take(end.line - start.line + 1)
.collect();
if let Some(first) = lines.first_mut() {
*first = first.split_at(start.column).1;
}
if let Some(last) = lines.last_mut() {
// if there is only one line the start index of last line will be the start of the rsx!, not the start of the line
if start.line == end.line {
*last =
last.split_at(end.column - start.column).0;
let watcher_config = config.clone();
let mut watcher = RecommendedWatcher::new(
move |evt: notify::Result<notify::Event>| {
let config = watcher_config.clone();
if chrono::Local::now().timestamp() > last_update_time {
// Give time for the change to take effect before reading the file
std::thread::sleep(std::time::Duration::from_millis(100));
let mut updated = false;
if let Ok(evt) = evt {
let mut messages = Vec::new();
let mut needs_rebuild = false;
for path in evt.paths.clone() {
if path.extension().map(|p| p.to_str()).flatten() != Some("rs") {
continue;
}
let mut file = File::open(path.clone()).unwrap();
let mut src = String::new();
file.read_to_string(&mut src).expect("Unable to read file");
// find changes to the rsx in the file
if let Ok(syntax) = syn::parse_file(&src) {
let mut last_file_rebuild = last_file_rebuild.lock().unwrap();
if let Some(old_str) = last_file_rebuild.map.get(&path) {
if let Ok(old) = syn::parse_file(&old_str) {
updated = true;
match find_rsx(&syntax, &old) {
DiffResult::CodeChanged => {
needs_rebuild = true;
last_file_rebuild.map.insert(path, src);
}
DiffResult::RsxChanged(changed) => {
log::info!("🪁 reloading rsx");
for (old, new) in changed.into_iter() {
let hr = get_location(
&crate_dir,
&path.to_path_buf(),
old.to_token_stream(),
);
// get the original source code to preserve whitespace
let span = new.span();
let start = span.start();
let end = span.end();
let mut lines: Vec<_> = src
.lines()
.skip(start.line - 1)
.take(end.line - start.line + 1)
.collect();
if let Some(first) = lines.first_mut() {
*first = first.split_at(start.column).1;
}
if let Some(last) = lines.last_mut() {
// if there is only one line the start index of last line will be the start of the rsx!, not the start of the line
if start.line == end.line {
*last = last
.split_at(end.column - start.column)
.0;
} else {
*last = last.split_at(end.column).0;
}
}
let rsx = lines.join("\n");
let old_dyn_ctx = try_parse_template(
&format!("{}", old.tokens),
hr.to_owned(),
None,
)
.map(|(_, old_dyn_ctx)| old_dyn_ctx);
if let Ok((template, _)) = try_parse_template(
&rsx,
hr.to_owned(),
old_dyn_ctx.ok(),
) {
messages.push(SetTemplateMsg(
TemplateId(hr),
template,
));
} else {
*last = last.split_at(end.column).0;
needs_rebuild = true;
}
}
let rsx = lines.join("\n");
messages.push(SetRsxMessage {
location: hr,
new_text: rsx,
});
}
}
}
} else {
// if this is a new file, rebuild the project
*last_file_rebuild = FileMap::new(crate_dir.clone());
}
} else {
// if this is a new file, rebuild the project
*last_file_rebuild = FileMap::new(crate_dir.clone());
}
}
}
if needs_rebuild {
match build_manager.rebuild() {
Ok(res) => {
print_console_info(
port,
&config,
PrettierOptions {
changed: evt.paths,
warnings: res.warnings,
elapsed_time: res.elapsed_time,
},
);
}
Err(err) => {
log::error!("{}", err);
if needs_rebuild {
match build_manager.rebuild() {
Ok(res) => {
print_console_info(
port,
&config,
PrettierOptions {
changed: evt.paths,
warnings: res.warnings,
elapsed_time: res.elapsed_time,
},
);
}
Err(err) => {
log::error!("{}", err);
}
}
}
for msg in messages {
let _ = hot_reload_tx.send(msg);
}
}
if updated {
last_update_time = chrono::Local::now().timestamp();
}
}
last_update_time = chrono::Local::now().timestamp();
}
})
},
notify::Config::default(),
)
.unwrap();
for sub_path in allow_watch_path {
@@ -215,6 +238,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
.unwrap();
}
// start serve dev-server at 0.0.0.0:8080
print_console_info(
port,
@@ -430,6 +454,7 @@ pub struct PrettierOptions {
}
fn print_console_info(port: u16, config: &CrateConfig, options: PrettierOptions) {
if let Ok(native_clearseq) = Command::new(if cfg!(target_os = "windows") {
"cls"
} else {