Fix bundling/path errors, sidecar support, iOS/Android simulator support, asset hotreload fixes, serverfn hotrelad, native tailwind support (#2779)
* wip: fix manganis import path * upgrade tauri bundler, convert todo!() to unimplemented!() * feat: mobile hotreloading + ios asset configuration * remove oid demo and its associated env vars * nuke all the things that cause cache thrashing * swap to Asset type * add some more logs * display impl for attrvalue * dont panic on collect failure * cut down web deps to 150 * clean up deps in a lot of places, simplify build scripts * clean up asset resolution and cli-dev profile * wire up absolute paths for manganis asset in a particular mode * move document related things around to shorten compile times * move most things to `document::Item` and then decompose the cli-config * switch link to stylesheet for clarity in examples * move manganis workspace example to examples folder * decompose manganis-cli-support * dont need mobile demo anymore * remove gloo dialogs * html doesnt need document * rename hotreload to devtools * really clean up the html crate * fix weird rsx spacing * clean up desktop to use callback * clean up document a bit * re-wire up devsocket * fix utf css * yeeeet that js out of here * synthetic web system works * web crate almost done being cleaned up * desktop mostly cleaned up too * clean up cli a bit * more cli cleanup * cli builds again * clean up cli, inline structs, cut down number of unique types where possible * hotreload works again for desktop and this time, mobile too * cfg out tungstenite * devserver err * more refactor to cli builder * switch to unbounded_send * new structure is much cleaner * add http serve subcommand * bundled hotreload * kick stylsheets * clean up a bit more, split up eventloop * amazingly serve seems done * change from pub to pub(crate) in cli * remove tools * bit more polish to cli * fix issue with join * gracefully handle fullstack without a server * fullstack mobile demo * fix launch function, move projects into example-projects folder * hoist examples * add "run" command * clean up launch * remove old manual websocket receiver * doctor command * allow desktop to scroll * cut apart router crate * dont put launch in prelude * use dioxus::launch where possible * rename rsx, cut out hotreload tests * remove liveview project * bump native * fix compile for renderers * move sync event response out of interpreter * move render in serve * rollback settings change * cli compiles, huzzah! * change uris for asset * fix asset * new tui screen * new cargo-like tui works * very very verty close * it works! very small bug with incorrect grapheme calc * Clean up devserver a bit * status sytem * tidy up debug filters * clean up logging situation * Fix a number of bugs with log printing * new printing system is more reliable * wire up more stuff * things working but fullstack is having issues * fullstack works again! * hotreloading bundled assets works again * bundled hotreload and beginnings of macos bundling * Hotreload desktop * combined server builds * add build handle * fix fullstack assets * make open async, add some hooks for ios * migrate filemap to runner * wip global crate system * fixup bundles + organize asset * fix asset location bug * all the bundled reloading! * open ios simulator! * full hotreload support for mobile + serverfn * basic cleanups * clean up dx * Move filemap * fix cutting of newlines * assets workibg, some android * hoist wry/tao * use sync locks and headers to fix issues with android * desktop -> mac/win/linux with alias * better logging * feat: workspace (entire computer!) hotreload * should rebuild toggle, ios simulator bootup * proper mobile support in launch * more robust handling of assets * fix cargo * bring back some of tauri bundle * make warnings go away, clippy happy on cli * some final clippy cleanups * fmt * move manganis to its own folder * upgrade bundle to stable * drastically slim down manganis, prepping for merge * typos, failing test, docsrs config * remove static gen test * nix static gen test * we use --platform web instead of --platform fullstack now * only bind dev urls in desktop/mobile * install gtk * nix static gen * split build dir by app name
This commit is contained in:
1 parent
ef436e4ed0
commit
7ec3453ca3
156 files changed
+11544
-9005
No files matched your search
+127
-149
@@ -14,108 +14,106 @@
|
||||
//! 3. Build CLI layer for routing tracing logs to the TUI.
|
||||
//! 4. Build fmt layer for non-interactive logging with a custom writer that prevents output during interactive mode.
|
||||
|
||||
use crate::builder::TargetPlatform;
|
||||
use console::strip_ansi_codes;
|
||||
use crate::{serve::ServeUpdate, Platform as TargetPlatform};
|
||||
use cargo_metadata::{diagnostic::DiagnosticLevel, CompilerMessage};
|
||||
use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
|
||||
use std::fmt::Display;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env,
|
||||
fmt::{Debug, Write as _},
|
||||
fmt::{Debug, Display, Write as _},
|
||||
fs,
|
||||
io::{self, Write},
|
||||
path::PathBuf,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex,
|
||||
Mutex,
|
||||
},
|
||||
};
|
||||
use tracing::Level;
|
||||
use tracing::{field::Visit, Subscriber};
|
||||
use tracing_subscriber::{
|
||||
filter::filter_fn, fmt::format, prelude::*, registry::LookupSpan, EnvFilter, Layer,
|
||||
};
|
||||
use tracing::{field::Visit, Level, Subscriber};
|
||||
use tracing_subscriber::{fmt::format, prelude::*, registry::LookupSpan, EnvFilter, Layer};
|
||||
|
||||
const LOG_ENV: &str = "DIOXUS_LOG";
|
||||
const LOG_FILE_NAME: &str = "dx.log";
|
||||
const DX_SRC_FLAG: &str = "dx_src";
|
||||
const DX_NO_FMT_FLAG: &str = "dx_no_fmt";
|
||||
|
||||
pub fn log_path() -> PathBuf {
|
||||
let tmp_dir = std::env::temp_dir();
|
||||
tmp_dir.join(LOG_FILE_NAME)
|
||||
}
|
||||
|
||||
/// Build tracing infrastructure.
|
||||
pub fn build_tracing() -> CLILogControl {
|
||||
let mut filter = EnvFilter::new("error,dx=info,dioxus-cli=info,manganis-cli-support=info");
|
||||
if env::var(LOG_ENV).is_ok() {
|
||||
filter = EnvFilter::from_env(LOG_ENV);
|
||||
static TUI_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
static TUI_TX: OnceCell<UnboundedSender<TraceMsg>> = OnceCell::new();
|
||||
|
||||
pub(crate) struct TraceController {
|
||||
pub(crate) tui_rx: UnboundedReceiver<TraceMsg>,
|
||||
}
|
||||
|
||||
impl TraceController {
|
||||
/// Get a handle to the trace controller.
|
||||
pub fn redirect() -> Self {
|
||||
let (tui_tx, tui_rx) = unbounded();
|
||||
TUI_ENABLED.store(true, Ordering::SeqCst);
|
||||
TUI_TX.set(tui_tx.clone()).unwrap();
|
||||
Self { tui_rx }
|
||||
}
|
||||
|
||||
// Log file
|
||||
let log_path = log_path();
|
||||
_ = std::fs::write(&log_path, "");
|
||||
let file_append_layer = match FileAppendLayer::new(log_path) {
|
||||
Ok(f) => Some(f),
|
||||
Err(e) => {
|
||||
tracing::error!(dx_src = ?TraceSrc::Dev, err = ?e, "failed to init log file");
|
||||
None
|
||||
/// Wait for the internal logger to send a message
|
||||
pub(crate) async fn wait(&mut self) -> ServeUpdate {
|
||||
use futures_util::StreamExt;
|
||||
let log = self.tui_rx.next().await.expect("tracer should never die");
|
||||
ServeUpdate::TracingLog { log }
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown(&self) {
|
||||
TUI_ENABLED.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// Build tracing infrastructure.
|
||||
pub fn initialize() {
|
||||
let mut filter =
|
||||
EnvFilter::new("error,dx=trace,dioxus-cli=debug,manganis-cli-support=debug");
|
||||
|
||||
if env::var(LOG_ENV).is_ok() {
|
||||
filter = EnvFilter::from_env(LOG_ENV);
|
||||
}
|
||||
};
|
||||
|
||||
// Create writer controller and custom writer.
|
||||
let (output_tx, output_rx) = unbounded();
|
||||
let output_enabled = Arc::new(AtomicBool::new(false));
|
||||
let writer_control = CLILogControl {
|
||||
output_rx,
|
||||
output_enabled: output_enabled.clone(),
|
||||
};
|
||||
|
||||
// Build CLI layer
|
||||
let cli_layer = CLILayer::new(output_enabled.clone(), output_tx);
|
||||
|
||||
// Build fmt layer
|
||||
let formatter = format::debug_fn(|writer, field, value| {
|
||||
write!(writer, "{}", format_field(field.name(), value))
|
||||
})
|
||||
.delimited(" ");
|
||||
|
||||
// Format subscriber
|
||||
let fmt_writer = Mutex::new(FmtLogWriter::new(output_enabled));
|
||||
let fmt_layer = tracing_subscriber::fmt::layer()
|
||||
.fmt_fields(formatter)
|
||||
.with_writer(fmt_writer)
|
||||
.without_time()
|
||||
.with_filter(filter_fn(|meta| {
|
||||
// Filter any logs with "dx_no_fmt" or is not user facing (no dx_src)
|
||||
let mut fields = meta.fields().iter();
|
||||
let has_src_flag = fields.any(|f| f.name() == DX_SRC_FLAG);
|
||||
|
||||
if !has_src_flag {
|
||||
return false;
|
||||
// Log file
|
||||
let log_path = log_path();
|
||||
_ = std::fs::write(&log_path, "");
|
||||
let file_append_layer = match FileAppendLayer::new(log_path) {
|
||||
Ok(f) => Some(f),
|
||||
Err(e) => {
|
||||
tracing::error!(dx_src = ?TraceSrc::Dev, err = ?e, "failed to init log file");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let has_fmt_flag = fields.any(|f| f.name() == DX_NO_FMT_FLAG);
|
||||
if has_fmt_flag {
|
||||
return false;
|
||||
}
|
||||
// Build CLI layer
|
||||
let cli_layer = CLILayer;
|
||||
|
||||
true
|
||||
}));
|
||||
// Build fmt layer
|
||||
let fmt_layer = tracing_subscriber::fmt::layer()
|
||||
.fmt_fields(
|
||||
format::debug_fn(|writer, field, value| {
|
||||
write!(writer, "{}", format_field(field.name(), value))
|
||||
})
|
||||
.delimited(" "),
|
||||
)
|
||||
.with_writer(Mutex::new(FmtLogWriter {}))
|
||||
.with_timer(tracing_subscriber::fmt::time::time());
|
||||
|
||||
let sub = tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(file_append_layer)
|
||||
.with(cli_layer)
|
||||
.with(fmt_layer);
|
||||
let sub = tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(file_append_layer)
|
||||
.with(cli_layer)
|
||||
.with(fmt_layer);
|
||||
|
||||
#[cfg(feature = "tokio-console")]
|
||||
let sub = sub.with(console_subscriber::spawn());
|
||||
#[cfg(feature = "tokio-console")]
|
||||
let sub = sub.with(console_subscriber::spawn());
|
||||
|
||||
sub.init();
|
||||
|
||||
writer_control
|
||||
sub.init();
|
||||
}
|
||||
}
|
||||
|
||||
/// A logging layer that appends to a file.
|
||||
@@ -148,9 +146,7 @@ where
|
||||
let mut visitor = CollectVisitor::new();
|
||||
event.record(&mut visitor);
|
||||
|
||||
let new_line = if visitor.source == TraceSrc::Cargo
|
||||
|| event.fields().any(|f| f.name() == DX_NO_FMT_FLAG)
|
||||
{
|
||||
let new_line = if visitor.source == TraceSrc::Cargo {
|
||||
visitor.message
|
||||
} else {
|
||||
let meta = event.metadata();
|
||||
@@ -172,7 +168,7 @@ where
|
||||
};
|
||||
|
||||
// Append logs
|
||||
let new_data = strip_ansi_codes(&new_line).to_string();
|
||||
let new_data = console::strip_ansi_codes(&new_line).to_string();
|
||||
|
||||
if let Ok(mut buf) = self.buffer.lock() {
|
||||
*buf += &new_data;
|
||||
@@ -183,22 +179,7 @@ where
|
||||
}
|
||||
|
||||
/// This is our "subscriber" (layer) that records structured data for the tui output.
|
||||
struct CLILayer {
|
||||
internal_output_enabled: Arc<AtomicBool>,
|
||||
output_tx: UnboundedSender<TraceMsg>,
|
||||
}
|
||||
|
||||
impl CLILayer {
|
||||
pub fn new(
|
||||
internal_output_enabled: Arc<AtomicBool>,
|
||||
output_tx: UnboundedSender<TraceMsg>,
|
||||
) -> Self {
|
||||
Self {
|
||||
internal_output_enabled,
|
||||
output_tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
struct CLILayer;
|
||||
|
||||
impl<S> Layer<S> for CLILayer
|
||||
where
|
||||
@@ -210,21 +191,13 @@ where
|
||||
event: &tracing::Event<'_>,
|
||||
_ctx: tracing_subscriber::layer::Context<'_, S>,
|
||||
) {
|
||||
// We only care about user-facing logs.
|
||||
let has_src_flag = event.fields().any(|f| f.name() == DX_SRC_FLAG);
|
||||
if !has_src_flag {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut visitor = CollectVisitor::new();
|
||||
event.record(&mut visitor);
|
||||
|
||||
// If the TUI output is disabled we let fmt subscriber handle the logs
|
||||
// EXCEPT for cargo logs which we just print.
|
||||
if !self.internal_output_enabled.load(Ordering::SeqCst) {
|
||||
if visitor.source == TraceSrc::Cargo
|
||||
|| event.fields().any(|f| f.name() == DX_NO_FMT_FLAG)
|
||||
{
|
||||
if !TUI_ENABLED.load(Ordering::SeqCst) {
|
||||
if visitor.source == TraceSrc::Cargo {
|
||||
println!("{}", visitor.message);
|
||||
}
|
||||
return;
|
||||
@@ -244,8 +217,10 @@ where
|
||||
visitor.source = TraceSrc::Dev;
|
||||
}
|
||||
|
||||
self.output_tx
|
||||
.unbounded_send(TraceMsg::new(visitor.source, *level, final_msg))
|
||||
TUI_TX
|
||||
.get()
|
||||
.unwrap()
|
||||
.unbounded_send(TraceMsg::text(visitor.source, *level, final_msg))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -256,7 +231,6 @@ where
|
||||
struct CollectVisitor {
|
||||
message: String,
|
||||
source: TraceSrc,
|
||||
dx_user_msg: bool,
|
||||
fields: HashMap<String, String>,
|
||||
}
|
||||
|
||||
@@ -265,7 +239,7 @@ impl CollectVisitor {
|
||||
Self {
|
||||
message: String::new(),
|
||||
source: TraceSrc::Unknown,
|
||||
dx_user_msg: false,
|
||||
|
||||
fields: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@@ -285,7 +259,6 @@ impl Visit for CollectVisitor {
|
||||
|
||||
if name == DX_SRC_FLAG {
|
||||
self.source = TraceSrc::from(value_string);
|
||||
self.dx_user_msg = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -293,42 +266,15 @@ impl Visit for CollectVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
// Contains the sync primitives to control the CLIWriter.
|
||||
pub struct CLILogControl {
|
||||
pub output_rx: UnboundedReceiver<TraceMsg>,
|
||||
pub output_enabled: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
struct FmtLogWriter {
|
||||
stdout: io::Stdout,
|
||||
output_enabled: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl FmtLogWriter {
|
||||
pub fn new(output_enabled: Arc<AtomicBool>) -> Self {
|
||||
Self {
|
||||
stdout: io::stdout(),
|
||||
output_enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
struct FmtLogWriter {}
|
||||
|
||||
impl Write for FmtLogWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// Handle selection between TUI or Terminal output.
|
||||
if !self.output_enabled.load(Ordering::SeqCst) {
|
||||
self.stdout.write(buf)
|
||||
} else {
|
||||
Ok(buf.len())
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
if !self.output_enabled.load(Ordering::SeqCst) {
|
||||
self.stdout.flush()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,8 +282,6 @@ impl Write for FmtLogWriter {
|
||||
fn format_field(field_name: &str, value: &dyn Debug) -> String {
|
||||
let mut out = String::new();
|
||||
match field_name {
|
||||
DX_SRC_FLAG => write!(out, ""),
|
||||
DX_NO_FMT_FLAG => write!(out, ""),
|
||||
"message" => write!(out, "{:?}", value),
|
||||
_ => write!(out, "{}={:?}", field_name, value),
|
||||
}
|
||||
@@ -350,15 +294,44 @@ fn format_field(field_name: &str, value: &dyn Debug) -> String {
|
||||
pub struct TraceMsg {
|
||||
pub source: TraceSrc,
|
||||
pub level: Level,
|
||||
pub content: String,
|
||||
pub content: TraceContent,
|
||||
pub timestamp: chrono::DateTime<chrono::Local>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum TraceContent {
|
||||
Cargo(CompilerMessage),
|
||||
Text(String),
|
||||
}
|
||||
|
||||
impl TraceMsg {
|
||||
pub fn new(source: TraceSrc, level: Level, content: String) -> Self {
|
||||
pub fn text(source: TraceSrc, level: Level, content: String) -> Self {
|
||||
Self {
|
||||
source,
|
||||
level,
|
||||
content,
|
||||
content: TraceContent::Text(content),
|
||||
timestamp: chrono::Local::now(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new trace message from a cargo compiler message
|
||||
///
|
||||
/// All `cargo` messages are logged at the `TRACE` level since they get *very* noisy during development
|
||||
pub fn cargo(content: CompilerMessage) -> Self {
|
||||
Self {
|
||||
level: match content.message.level {
|
||||
DiagnosticLevel::Ice => Level::ERROR,
|
||||
DiagnosticLevel::Error => Level::ERROR,
|
||||
DiagnosticLevel::FailureNote => Level::ERROR,
|
||||
DiagnosticLevel::Warning => Level::TRACE,
|
||||
DiagnosticLevel::Note => Level::TRACE,
|
||||
DiagnosticLevel::Help => Level::TRACE,
|
||||
_ => Level::TRACE,
|
||||
},
|
||||
timestamp: chrono::Local::now(),
|
||||
source: TraceSrc::Cargo,
|
||||
content: TraceContent::Cargo(content),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,9 +341,8 @@ pub enum TraceSrc {
|
||||
App(TargetPlatform),
|
||||
Dev,
|
||||
Build,
|
||||
/// Provides no formatting.
|
||||
Bundle,
|
||||
Cargo,
|
||||
/// Avoid using this
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@@ -385,12 +357,13 @@ impl From<String> for TraceSrc {
|
||||
fn from(value: String) -> Self {
|
||||
match value.as_str() {
|
||||
"dev" => Self::Dev,
|
||||
"build" => Self::Build,
|
||||
"bld" => Self::Build,
|
||||
"cargo" => Self::Cargo,
|
||||
"web" => Self::App(TargetPlatform::Web),
|
||||
"desktop" => Self::App(TargetPlatform::Desktop),
|
||||
"app" => Self::App(TargetPlatform::Web),
|
||||
"windows" => Self::App(TargetPlatform::Windows),
|
||||
"macos" => Self::App(TargetPlatform::MacOS),
|
||||
"linux" => Self::App(TargetPlatform::Linux),
|
||||
"server" => Self::App(TargetPlatform::Server),
|
||||
"liveview" => Self::App(TargetPlatform::Liveview),
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
@@ -401,14 +374,19 @@ impl Display for TraceSrc {
|
||||
match self {
|
||||
Self::App(platform) => match platform {
|
||||
TargetPlatform::Web => write!(f, "web"),
|
||||
TargetPlatform::Desktop => write!(f, "desktop"),
|
||||
TargetPlatform::MacOS => write!(f, "macos"),
|
||||
TargetPlatform::Windows => write!(f, "windows"),
|
||||
TargetPlatform::Linux => write!(f, "linux"),
|
||||
TargetPlatform::Server => write!(f, "server"),
|
||||
TargetPlatform::Liveview => write!(f, "server"),
|
||||
TargetPlatform::Ios => write!(f, "ios"),
|
||||
TargetPlatform::Android => write!(f, "android"),
|
||||
TargetPlatform::Liveview => write!(f, "liveview"),
|
||||
},
|
||||
Self::Dev => write!(f, "dev"),
|
||||
Self::Build => write!(f, "build"),
|
||||
Self::Cargo => write!(f, "cargo"),
|
||||
Self::Unknown => write!(f, "n/a"),
|
||||
Self::Bundle => write!(f, "bundle"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user