Use Manganis Linker System (#2561)

* feat: new manganis linker

* revision: fmt, clippy, cleanup

* revision: link subcommand

* fix: async runtime

* revision: remove working dir arg

* revision: switch dep source

* fix: matrix, playwright

* fix: fullstack manganis
This commit is contained in:
Miles Murgaw 2024-07-03 00:36:44 -04:00 committed by GitHub
parent 90c46afd12
commit 2ef406982e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 332 additions and 172 deletions

View file

@ -222,7 +222,7 @@ jobs:
- {
target: x86_64-pc-windows-msvc,
os: windows-latest,
toolchain: "1.75.0",
toolchain: "1.76.0",
cross: false,
command: "test",
args: "--all --tests",
@ -230,7 +230,7 @@ jobs:
- {
target: x86_64-apple-darwin,
os: macos-latest,
toolchain: "1.75.0",
toolchain: "1.76.0",
cross: false,
command: "test",
args: "--all --tests",
@ -238,7 +238,7 @@ jobs:
- {
target: aarch64-apple-ios,
os: macos-latest,
toolchain: "1.75.0",
toolchain: "1.76.0",
cross: false,
command: "build",
args: "--package dioxus-mobile",
@ -246,7 +246,7 @@ jobs:
- {
target: aarch64-linux-android,
os: ubuntu-latest,
toolchain: "1.75.0",
toolchain: "1.76.0",
cross: true,
command: "build",
args: "--package dioxus-mobile",

73
Cargo.lock generated
View file

@ -906,7 +906,7 @@ dependencies = [
"cfg-if",
"libc",
"miniz_oxide",
"object",
"object 0.32.2",
"rustc-demangle",
]
@ -1936,7 +1936,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa 1.0.11",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@ -5918,8 +5918,7 @@ dependencies = [
[[package]]
name = "manganis-cli-support"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d502b0db0ef8c880fecff174903815efedfacbcd5ea9a8bef96752f1e0d7eb6"
source = "git+https://github.com/DogeDark/dioxus-collect-assets/#6b6077150c854af6497d8b96d3a070635ab9b6c4"
dependencies = [
"anyhow",
"cargo-lock",
@ -5928,8 +5927,9 @@ dependencies = [
"image 0.25.1",
"imagequant",
"lightningcss",
"manganis-common",
"manganis-common 0.2.4 (git+https://github.com/DogeDark/dioxus-collect-assets/)",
"mozjpeg",
"object 0.36.0",
"petgraph",
"png",
"railwind",
@ -5938,6 +5938,7 @@ dependencies = [
"reqwest 0.11.27",
"rustc-hash",
"serde",
"serde_json",
"toml 0.7.8",
"tracing",
"url",
@ -5960,13 +5961,29 @@ dependencies = [
"url",
]
[[package]]
name = "manganis-common"
version = "0.2.4"
source = "git+https://github.com/DogeDark/dioxus-collect-assets/#6b6077150c854af6497d8b96d3a070635ab9b6c4"
dependencies = [
"anyhow",
"base64 0.21.7",
"home",
"infer 0.11.0",
"reqwest",
"serde",
"toml 0.7.8",
"tracing",
"url",
]
[[package]]
name = "manganis-macro"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704a0123ac90fa630b21a04fde56c29dfd5a7665c5e8f3639567989daa2d29d1"
dependencies = [
"manganis-common",
"manganis-common 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn 2.0.60",
@ -6554,6 +6571,18 @@ dependencies = [
"memchr",
]
[[package]]
name = "object"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
dependencies = [
"flate2",
"memchr",
"ruzstd",
"wasmparser 0.208.1",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@ -8117,6 +8146,17 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "ruzstd"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b"
dependencies = [
"byteorder",
"derive_more",
"twox-hash",
]
[[package]]
name = "ryu"
version = "1.0.17"
@ -9899,6 +9939,16 @@ dependencies = [
"utf-8",
]
[[package]]
name = "twox-hash"
version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [
"cfg-if",
"static_assertions",
]
[[package]]
name = "typenum"
version = "1.17.0"
@ -10132,7 +10182,7 @@ dependencies = [
"log",
"walrus-macro",
"wasm-encoder",
"wasmparser",
"wasmparser 0.80.2",
]
[[package]]
@ -10419,6 +10469,15 @@ version = "0.80.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b"
[[package]]
name = "wasmparser"
version = "0.208.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd921789c9dcc495f589cb37d200155dee65b4a4beeb853323b5e24e0a5f9c58"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "web-sys"
version = "0.3.69"

View file

@ -98,7 +98,7 @@ wasm-bindgen-futures = "0.4.42"
html_parser = "0.7.0"
thiserror = "1.0.40"
prettyplease = { version = "0.2.16", features = ["verbatim"] }
manganis-cli-support = { version = "0.2.1", features = ["html"] }
manganis-cli-support = { git = "https://github.com/DogeDark/dioxus-collect-assets/", features = ["html"] }
manganis = { version = "0.2.1" }
interprocess = { version = "1.2.2", package = "interprocess-docfix" }

View file

@ -1,4 +1,5 @@
use brotli::enc::BrotliEncoderParams;
use std::fs;
use std::path::Path;
use std::{ffi::OsString, path::PathBuf};
use walkdir::WalkDir;
@ -10,12 +11,16 @@ use dioxus_cli_config::CrateConfig;
use dioxus_cli_config::Platform;
use manganis_cli_support::{AssetManifest, AssetManifestExt};
pub fn asset_manifest(bin: Option<&str>, crate_config: &CrateConfig) -> AssetManifest {
AssetManifest::load_from_path(
bin,
crate_config.crate_dir.join("Cargo.toml"),
crate_config.workspace_dir.join("Cargo.lock"),
)
/// The temp file name for passing manganis json from linker to current exec.
pub const MG_JSON_OUT: &str = "mg-out";
pub fn asset_manifest(config: &CrateConfig) -> AssetManifest {
let file_path = config.out_dir().join(MG_JSON_OUT);
let read = fs::read_to_string(&file_path).unwrap();
_ = fs::remove_file(file_path);
let json: Vec<String> = serde_json::from_str(&read).unwrap();
AssetManifest::load(json)
}
/// Create a head file that contains all of the imports for assets that the user project uses

View file

@ -4,6 +4,7 @@ use crate::{
AssetConfigDropGuard,
},
error::{Error, Result},
link::LinkCommand,
tools::Tool,
};
use anyhow::Context;
@ -83,13 +84,12 @@ pub fn build_web(
let CrateConfig {
crate_dir,
target_dir,
executable,
dioxus_config,
..
} = config;
let out_dir = config.out_dir();
let _guard = AssetConfigDropGuard::new();
let _asset_guard = AssetConfigDropGuard::new();
let _manganis_support = ManganisSupportGuard::default();
// start to build the assets
@ -114,54 +114,76 @@ pub fn build_web(
}
}
let cmd = subprocess::Exec::cmd("cargo")
let mut cargo_args = vec!["--target".to_string(), "wasm32-unknown-unknown".to_string()];
let mut cmd = subprocess::Exec::cmd("cargo")
.set_rust_flags(rust_flags)
.env("CARGO_TARGET_DIR", target_dir)
.cwd(crate_dir)
.arg("build")
.arg("--target")
.arg("wasm32-unknown-unknown")
.arg("--message-format=json-render-diagnostics");
// TODO: make the initial variable mutable to simplify all the expressions
// below. Look inside the `build_desktop()` as an example.
let cmd = if config.release {
cmd.arg("--release")
if config.release {
cargo_args.push("--release".to_string());
}
if config.verbose {
cargo_args.push("--verbose".to_string());
} else {
cmd
};
let cmd = if config.verbose {
cmd.arg("--verbose")
} else {
cmd.arg("--quiet")
};
cargo_args.push("--quiet".to_string());
}
let cmd = if config.custom_profile.is_some() {
if config.custom_profile.is_some() {
let custom_profile = config.custom_profile.as_ref().unwrap();
cmd.arg("--profile").arg(custom_profile)
} else {
cmd
};
cargo_args.push("--profile".to_string());
cargo_args.push(custom_profile.to_string());
}
let cmd = if config.features.is_some() {
if config.features.is_some() {
let features_str = config.features.as_ref().unwrap().join(" ");
cmd.arg("--features").arg(features_str)
} else {
cmd
};
let cmd = cmd.args(&config.cargo_args);
let cmd = match executable {
ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
ExecutableType::Example(name) => cmd.arg("--example").arg(name),
cargo_args.push("--features".to_string());
cargo_args.push(features_str);
}
if let Some(target) = &config.target {
cargo_args.push("--target".to_string());
cargo_args.push(target.clone());
}
cargo_args.append(&mut config.cargo_args.clone());
match &config.executable {
ExecutableType::Binary(name) => {
cargo_args.push("--bin".to_string());
cargo_args.push(name.to_string());
}
ExecutableType::Lib(name) => {
cargo_args.push("--lib".to_string());
cargo_args.push(name.to_string());
}
ExecutableType::Example(name) => {
cargo_args.push("--example".to_string());
cargo_args.push(name.to_string());
}
};
cmd = cmd.args(&cargo_args);
let CargoBuildResult {
warnings,
output_location,
} = prettier_build(cmd)?;
// Start Manganis linker intercept.
let linker_args = vec![format!("{}", config.out_dir().display())];
manganis_cli_support::start_linker_intercept(
&LinkCommand::command_name(),
cargo_args,
Some(linker_args),
)
.unwrap();
let output_location = output_location.context("No output location found")?;
// [2] Establish the output directory structure
@ -277,7 +299,7 @@ pub fn build_web(
let assets = if !skip_assets {
tracing::info!("Processing assets");
let assets = asset_manifest(executable.executable(), config);
let assets = asset_manifest(config);
process_assets(config, &assets)?;
Some(assets)
} else {
@ -337,7 +359,9 @@ pub fn build_desktop(
build_assets(config)?;
let _guard = dioxus_cli_config::__private::save_config(config);
let _manganis_support = ManganisSupportGuard::default();
let _guard = AssetConfigDropGuard::new();
let _asset_guard = AssetConfigDropGuard::new();
let mut cargo_args = Vec::new();
let mut cmd = subprocess::Exec::cmd("cargo")
.set_rust_flags(rust_flags)
@ -347,38 +371,60 @@ pub fn build_desktop(
.arg("--message-format=json-render-diagnostics");
if config.release {
cmd = cmd.arg("--release");
cargo_args.push("--release".to_string());
}
if config.verbose {
cmd = cmd.arg("--verbose");
cargo_args.push("--verbose".to_string());
} else {
cmd = cmd.arg("--quiet");
cargo_args.push("--quiet".to_string());
}
if config.custom_profile.is_some() {
let custom_profile = config.custom_profile.as_ref().unwrap();
cmd = cmd.arg("--profile").arg(custom_profile);
cargo_args.push("--profile".to_string());
cargo_args.push(custom_profile.to_string());
}
if config.features.is_some() {
let features_str = config.features.as_ref().unwrap().join(" ");
cmd = cmd.arg("--features").arg(features_str);
cargo_args.push("--features".to_string());
cargo_args.push(features_str);
}
if let Some(target) = &config.target {
cmd = cmd.arg("--target").arg(target);
cargo_args.push("--target".to_string());
cargo_args.push(target.clone());
}
cmd = cmd.args(&config.cargo_args);
cargo_args.append(&mut config.cargo_args.clone());
let cmd = match &config.executable {
ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
ExecutableType::Example(name) => cmd.arg("--example").arg(name),
match &config.executable {
ExecutableType::Binary(name) => {
cargo_args.push("--bin".to_string());
cargo_args.push(name.to_string());
}
ExecutableType::Lib(name) => {
cargo_args.push("--lib".to_string());
cargo_args.push(name.to_string());
}
ExecutableType::Example(name) => {
cargo_args.push("--example".to_string());
cargo_args.push(name.to_string());
}
};
cmd = cmd.args(&cargo_args);
let warning_messages = prettier_build(cmd)?;
// Start Manganis linker intercept.
let linker_args = vec![format!("{}", config.out_dir().display())];
manganis_cli_support::start_linker_intercept(
&LinkCommand::command_name(),
cargo_args,
Some(linker_args),
)?;
let file_name: String = config.executable.executable().unwrap().to_string();
let target_file = if cfg!(windows) {
@ -399,7 +445,7 @@ pub fn build_desktop(
let assets = if !skip_assets {
tracing::info!("Processing assets");
let assets = asset_manifest(config.executable.executable(), config);
let assets = asset_manifest(config);
// Collect assets
process_assets(config, &assets)?;
// Create the __assets_head.html file for bundling

View file

@ -16,22 +16,26 @@ pub struct Check {
impl Check {
// Todo: check the entire crate
pub async fn check(self) -> Result<()> {
match self.file {
// Default to checking the project
None => {
if let Err(e) = check_project_and_report().await {
eprintln!("error checking project: {}", e);
exit(1);
pub fn check(self) -> Result<()> {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async move {
match self.file {
// Default to checking the project
None => {
if let Err(e) = check_project_and_report().await {
eprintln!("error checking project: {}", e);
exit(1);
}
}
Some(file) => {
if let Err(e) = check_file_and_report(file).await {
eprintln!("failed to check file: {}", e);
exit(1);
}
}
}
Some(file) => {
if let Err(e) = check_file_and_report(file).await {
eprintln!("failed to check file: {}", e);
exit(1);
}
}
}
});
Ok(())
}

View file

@ -0,0 +1,39 @@
use crate::{assets, error::Result};
use clap::Parser;
use std::{fs, path::PathBuf};
#[derive(Clone, Debug, Parser)]
#[clap(name = "link", hide = true)]
pub struct LinkCommand {
// Allow us to accept any argument after `dx link`
#[clap(trailing_var_arg = true, allow_hyphen_values = true)]
pub args: Vec<String>,
}
impl LinkCommand {
pub fn link(self) -> Result<()> {
let Some((link_args, object_files)) = manganis_cli_support::linker_intercept(self.args)
else {
tracing::warn!("Invalid linker arguments.");
return Ok(());
};
// Parse object files, deserialize JSON, & create a file to propogate JSON.
let json = manganis_cli_support::get_json_from_object_files(object_files);
let parsed = serde_json::to_string(&json).unwrap();
let out_dir = PathBuf::from(link_args.first().unwrap());
fs::create_dir_all(&out_dir).unwrap();
let path = out_dir.join(assets::MG_JSON_OUT);
fs::write(path, parsed).unwrap();
Ok(())
}
/// We need to pass the subcommand name to Manganis so this
/// helps centralize where we set the subcommand "name".
pub fn command_name() -> String {
"link".to_string()
}
}

View file

@ -7,6 +7,7 @@ pub mod clean;
pub mod config;
pub mod create;
pub mod init;
pub mod link;
pub mod plugin;
pub mod serve;
pub mod translate;
@ -85,6 +86,10 @@ pub enum Commands {
#[cfg(feature = "plugin")]
#[clap(subcommand)]
Plugin(plugin::Plugin),
/// Handles parsing of linker arguments for linker-based systems
/// such as Manganis and binary patching.
Link(link::LinkCommand),
}
impl Display for Commands {
@ -100,6 +105,7 @@ impl Display for Commands {
Commands::Autoformat(_) => write!(f, "fmt"),
Commands::Check(_) => write!(f, "check"),
Commands::Bundle(_) => write!(f, "bundle"),
Commands::Link(_) => write!(f, "link"),
#[cfg(feature = "plugin")]
Commands::Plugin(_) => write!(f, "plugin"),

View file

@ -15,7 +15,7 @@ pub enum Plugin {
}
impl Plugin {
pub async fn plugin(self) -> Result<()> {
pub fn plugin(self) -> Result<()> {
match self {
Plugin::List {} => {
for item in crate::plugin::PluginManager::plugin_list() {

View file

@ -14,7 +14,7 @@ pub struct Serve {
}
impl Serve {
pub async fn serve(self, bin: Option<PathBuf>) -> Result<()> {
pub fn serve(self, bin: Option<PathBuf>) -> Result<()> {
let mut crate_config = dioxus_cli_config::CrateConfig::new(bin)?;
let serve_cfg = self.serve.clone();
@ -65,10 +65,10 @@ impl Serve {
// start the develop server
use server::{desktop, fullstack, web};
match platform {
Platform::Web => web::startup(crate_config.clone(), &serve_cfg).await?,
Platform::Desktop => desktop::startup(crate_config.clone(), &serve_cfg).await?,
Platform::Web => web::startup(crate_config.clone(), &serve_cfg)?,
Platform::Desktop => desktop::startup(crate_config.clone(), &serve_cfg)?,
Platform::Fullstack | Platform::StaticGeneration => {
fullstack::startup(crate_config.clone(), &serve_cfg).await?
fullstack::startup(crate_config.clone(), &serve_cfg)?
}
_ => unreachable!(),
}

View file

@ -2,7 +2,7 @@
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
mod assets;
pub mod assets;
pub mod builder;
pub mod server;
pub mod tools;

View file

@ -10,8 +10,7 @@ use Commands::*;
const LOG_ENV: &str = "DIOXUS_LOG";
#[tokio::main]
async fn main() -> anyhow::Result<()> {
fn main() -> anyhow::Result<()> {
let args = Cli::parse();
// If {LOG_ENV} is set, default to env, otherwise filter to cli
@ -40,19 +39,17 @@ async fn main() -> anyhow::Result<()> {
.context(error_wrapper("Configuring new project failed")),
#[cfg(feature = "plugin")]
Plugin(opts) => opts
.plugin()
.await
.context(error_wrapper("Error with plugin")),
Plugin(opts) => opts.plugin().context(error_wrapper("Error with plugin")),
Autoformat(opts) => opts
.autoformat()
.context(error_wrapper("Error autoformatting RSX")),
Check(opts) => opts
.check()
.await
.context(error_wrapper("Error checking RSX")),
Check(opts) => opts.check().context(error_wrapper("Error checking RSX")),
Link(opts) => opts
.link()
.context(error_wrapper("Error with linker passthrough")),
action => {
let bin = get_bin(args.bin)?;
@ -81,7 +78,6 @@ async fn main() -> anyhow::Result<()> {
Serve(opts) => opts
.serve(Some(bin.clone()))
.await
.context(error_wrapper("Serving project failed")),
Bundle(opts) => opts

View file

@ -23,11 +23,11 @@ use crate::plugin::PluginManager;
use super::HotReloadState;
pub async fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> {
startup_with_platform::<DesktopPlatform>(config, serve).await
pub fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> {
startup_with_platform::<DesktopPlatform>(config, serve)
}
pub(crate) async fn startup_with_platform<P: Platform + Send + 'static>(
pub(crate) fn startup_with_platform<P: Platform + Send + 'static>(
config: CrateConfig,
serve_cfg: &ConfigOptsServe,
) -> Result<()> {
@ -54,7 +54,7 @@ pub(crate) async fn startup_with_platform<P: Platform + Send + 'static>(
file_map,
};
serve::<P>(config, serve_cfg, hot_reload_state).await?;
serve::<P>(config, serve_cfg, hot_reload_state)?;
Ok(())
}
@ -70,53 +70,55 @@ fn set_ctrl_c(config: &CrateConfig) {
}
/// Start the server without hot reload
async fn serve<P: Platform + Send + 'static>(
fn serve<P: Platform + Send + 'static>(
config: CrateConfig,
serve: &ConfigOptsServe,
hot_reload_state: HotReloadState,
) -> Result<()> {
let hot_reload: tokio::task::JoinHandle<Result<()>> = tokio::spawn({
let hot_reload_state = hot_reload_state.clone();
async move {
match hot_reload_state.file_map.clone() {
Some(file_map) => {
// The open interprocess sockets
start_desktop_hot_reload(hot_reload_state, file_map).await?;
}
None => {
std::future::pending::<()>().await;
}
}
Ok(())
}
});
let platform = RwLock::new(P::start(&config, serve, Vec::new())?);
tracing::info!("🚀 Starting development server...");
// We got to own watcher so that it exists for the duration of serve
// Otherwise full reload won't work.
let _watcher = setup_file_watcher(
{
let config = config.clone();
let serve = serve.clone();
move || {
platform
.write()
.unwrap()
.rebuild(&config, &serve, Vec::new())
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async move {
let hot_reload: tokio::task::JoinHandle<Result<()>> = tokio::spawn({
let hot_reload_state = hot_reload_state.clone();
async move {
match hot_reload_state.file_map.clone() {
Some(file_map) => {
// The open interprocess sockets
start_desktop_hot_reload(hot_reload_state, file_map).await?;
}
None => {
std::future::pending::<()>().await;
}
}
Ok(())
}
},
&config,
None,
hot_reload_state,
)
.await?;
});
hot_reload.await.unwrap()?;
tracing::info!("🚀 Starting development server...");
Ok(())
// We got to own watcher so that it exists for the duration of serve
// Otherwise full reload won't work.
let _watcher = setup_file_watcher(
{
let config = config.clone();
let serve = serve.clone();
move || {
platform
.write()
.unwrap()
.rebuild(&config, &serve, Vec::new())
}
},
&config,
None,
hot_reload_state,
)
.await?;
hot_reload.await.unwrap()?;
Ok(())
})
}
async fn start_desktop_hot_reload(

View file

@ -36,8 +36,8 @@ pub fn server_rust_flags(build: &ConfigOptsBuild) -> String {
rust_flags(build, SERVER_RUST_FLAGS)
}
pub async fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> {
desktop::startup_with_platform::<FullstackPlatform>(config, serve).await
pub fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> {
desktop::startup_with_platform::<FullstackPlatform>(config, serve)
}
fn start_web_build_thread(

View file

@ -22,7 +22,7 @@ use server::*;
use super::HotReloadState;
pub async fn startup(config: CrateConfig, serve_cfg: &ConfigOptsServe) -> Result<()> {
pub fn startup(config: CrateConfig, serve_cfg: &ConfigOptsServe) -> Result<()> {
set_ctrlc_handler(&config);
let ip = serve_cfg
@ -33,11 +33,11 @@ pub async fn startup(config: CrateConfig, serve_cfg: &ConfigOptsServe) -> Result
let hot_reload_state = build_hotreload_filemap(&config);
serve(ip, config, hot_reload_state, serve_cfg).await
serve(ip, config, hot_reload_state, serve_cfg)
}
/// Start the server without hot reload
pub async fn serve(
pub fn serve(
ip: IpAddr,
config: CrateConfig,
hot_reload_state: HotReloadState,
@ -55,42 +55,45 @@ pub async fn serve(
tracing::info!("🚀 Starting development server...");
// We got to own watcher so that it exists for the duration of serve
// Otherwise full reload won't work.
let _watcher = setup_file_watcher(
{
let config = config.clone();
let hot_reload_state = hot_reload_state.clone();
move || build(&config, &hot_reload_state, skip_assets)
},
&config,
Some(WebServerInfo { ip, port }),
hot_reload_state.clone(),
)
.await?;
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async move {
// We got to own watcher so that it exists for the duration of serve
// Otherwise full reload won't work.
let _watcher = setup_file_watcher(
{
let config = config.clone();
let hot_reload_state = hot_reload_state.clone();
move || build(&config, &hot_reload_state, skip_assets)
},
&config,
Some(WebServerInfo { ip, port }),
hot_reload_state.clone(),
)
.await?;
// HTTPS
// Before console info so it can stop if mkcert isn't installed or fails
let rustls_config = get_rustls(&config).await?;
// HTTPS
// Before console info so it can stop if mkcert isn't installed or fails
let rustls_config = get_rustls(&config).await?;
// Print serve info
print_console_info(
&config,
PrettierOptions {
changed: vec![],
warnings: first_build_result.warnings,
elapsed_time: first_build_result.elapsed_time,
},
Some(WebServerInfo { ip, port }),
);
// Print serve info
print_console_info(
&config,
PrettierOptions {
changed: vec![],
warnings: first_build_result.warnings,
elapsed_time: first_build_result.elapsed_time,
},
Some(WebServerInfo { ip, port }),
);
// Router
let router = setup_router(config.clone(), hot_reload_state).await?;
// Router
let router = setup_router(config.clone(), hot_reload_state).await?;
// Start server
start_server(ip, port, router, opts.open, rustls_config, &config).await?;
// Start server
start_server(ip, port, router, opts.open, rustls_config, &config).await?;
Ok(())
Ok(())
})
}
/// Starts dx serve with no hot reload