diff --git a/src/assets/autoreload.js b/src/assets/autoreload.js
new file mode 100644
index 000000000..ff4444085
--- /dev/null
+++ b/src/assets/autoreload.js
@@ -0,0 +1,25 @@
+(function () {
+ var protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
+
+ var url = protocol + "//" + window.location.host + "/_dioxus/ws";
+
+ var poll_interval = 2000;
+
+ var reload_upon_connect = () => {
+ window.setTimeout(() => {
+ var ws = new WebSocket(url);
+ ws.onopen = () => window.location.reload();
+ ws.onclose = reload_upon_connect;
+ }, poll_interval);
+ };
+
+ var ws = new WebSocket(url);
+
+ ws.onmessage = (ev) => {
+ if (ev.data == "reload") {
+ window.location.reload();
+ }
+ };
+
+ ws.onclose = reload_upon_connect;
+})();
\ No newline at end of file
diff --git a/src/assets/index.html b/src/assets/index.html
new file mode 100644
index 000000000..12e1e5678
--- /dev/null
+++ b/src/assets/index.html
@@ -0,0 +1,18 @@
+
+
+ {app_title}
+
+
+ {style_include}
+
+
+
+
+
+
+ {script_include}
+
+
diff --git a/src/builder.rs b/src/builder.rs
index 58ee085fc..381ef8b28 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -1,11 +1,12 @@
use crate::{
config::{CrateConfig, ExecutableType},
error::{Error, Result},
+ DioxusConfig,
};
-use std::{io::Write, path::PathBuf, process::Command};
+use std::process::Command;
use wasm_bindgen_cli_support::Bindgen;
-pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> {
+pub fn build(config: &CrateConfig) -> Result<()> {
/*
[1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?)
[2] Generate the appropriate build folders
@@ -15,15 +16,15 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> {
*/
let CrateConfig {
+ out_dir,
crate_dir,
target_dir,
static_dir,
executable,
+ dioxus_config,
..
} = config;
- let out_dir = crate_dir.join(dist);
-
let t_start = std::time::Instant::now();
// [1] Build the .wasm module
@@ -53,7 +54,7 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> {
let reason = String::from_utf8_lossy(&output.stderr).to_string();
return Err(Error::BuildFailed(reason));
}
-
+
// [2] Establish the output directory structure
let bindgen_outdir = out_dir.join("assets");
@@ -83,7 +84,7 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> {
.keep_debug(true)
.remove_name_section(false)
.remove_producers_section(false)
- .out_name("module")
+ .out_name(&dioxus_config.application.name)
.generate(&bindgen_outdir)?;
let copy_options = fs_extra::dir::CopyOptions::new();
@@ -101,28 +102,52 @@ pub fn build(config: &CrateConfig, dist: PathBuf) -> Result<()> {
Ok(())
}
-pub fn gen_page(module: &str) -> String {
- format!(
- r#"
-
-
-
-
-
-
-
-
-
-
-
-
-
-"#,
- module
- )
+pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
+ let mut html = String::from(include_str!("./assets/index.html"));
+
+ let resouces = config.web.resource.clone();
+
+ let mut style_list = resouces.style.unwrap_or(vec![]);
+ let mut script_list = resouces.script.unwrap_or(vec![]);
+
+ if serve {
+ let mut dev_style = resouces.dev.style.clone().unwrap_or(vec![]);
+ let mut dev_script = resouces.dev.script.clone().unwrap_or(vec![]);
+ style_list.append(&mut dev_style);
+ script_list.append(&mut dev_script);
+ }
+
+ let mut style_str = String::new();
+ for style in style_list {
+ style_str.push_str(&format!(
+ "\n",
+ &style.to_str().unwrap(),
+ ))
+ }
+ html = html.replace("{style_include}", &style_str);
+
+ let mut script_str = String::new();
+ for script in script_list {
+ script_str.push_str(&format!(
+ "\n",
+ &script.to_str().unwrap(),
+ ))
+ }
+
+ html = html.replace("{script_include}", &script_str);
+
+ if serve {
+ html += &format!(
+ "",
+ include_str!("./assets/autoreload.js")
+ );
+ }
+
+ html = html.replace("{app_name}", &config.application.name);
+
+ let title = config.web.app.title.clone().unwrap_or("dioxus | βΊ".into());
+
+ html.replace("{app_title}", &title)
}
// use binary_install::{Cache, Download};
diff --git a/src/cli/build/mod.rs b/src/cli/build/mod.rs
index 760c2fd8e..fc329a305 100644
--- a/src/cli/build/mod.rs
+++ b/src/cli/build/mod.rs
@@ -1,5 +1,3 @@
-use std::path::PathBuf;
-
use crate::cfg::ConfigOptsBuild;
use structopt::StructOpt;
@@ -18,10 +16,7 @@ impl Build {
// change the relase state.
crate_config.with_release(self.build.release);
- crate::builder::build(
- &crate_config,
- self.build.dist.unwrap_or(PathBuf::from("dist")),
- )?;
+ crate::builder::build(&crate_config)?;
Ok(())
}
diff --git a/src/cli/cfg.rs b/src/cli/cfg.rs
index 2c5f42a26..ab68ce4f9 100644
--- a/src/cli/cfg.rs
+++ b/src/cli/cfg.rs
@@ -16,14 +16,6 @@ pub struct ConfigOptsBuild {
#[serde(default)]
pub release: bool,
- /// The output dir for all final assets [default: dist]
- #[structopt(short, long, parse(from_os_str))]
- pub dist: Option,
-
- /// The public URL from which assets are to be served [default: /]
- #[structopt(long, parse(from_str=parse_public_url))]
- pub public_url: Option,
-
/// Optional pattern for the app loader script [default: None]
///
/// Patterns should include the sequences `{base}`, `{wasm}`, and `{js}` in order to
@@ -74,14 +66,6 @@ pub struct ConfigOptsServe {
#[structopt(long)]
#[serde(default)]
pub release: bool,
-
- /// The output dir for all final assets [default: dist]
- #[structopt(short, long, parse(from_os_str))]
- pub dist: Option,
-
- /// The public URL from which assets are to be served [default: /]
- #[structopt(long, parse(from_str=parse_public_url))]
- pub public_url: Option,
}
/// Ensure the given value for `--public-url` is formatted correctly.
diff --git a/src/cli/init/mod.rs b/src/cli/init/mod.rs
index dde0ccca3..52dcf4c14 100644
--- a/src/cli/init/mod.rs
+++ b/src/cli/init/mod.rs
@@ -13,9 +13,9 @@ use crate::error::{Error, Result};
#[derive(Clone, Debug, StructOpt)]
#[structopt(name = "init")]
pub struct Init {
- /// Init project path
+ /// Init project name
#[structopt(default_value = ".")]
- path: String,
+ name: String,
/// Template path
#[structopt(default_value = "default", long)]
@@ -24,18 +24,23 @@ pub struct Init {
impl Init {
pub fn init(self) -> Result<()> {
- log::info!("π§ Start to init a new project '{}'.", self.path);
+ if self.name.contains(".") {
+ log::error!("βUnsupported project name.");
+ return Ok(());
+ }
- let project_path = PathBuf::from(&self.path);
+ log::info!("π§ Start to init a new project '{}'.", self.name);
+
+ let project_path = PathBuf::from(&self.name);
if project_path.join("Cargo.toml").is_file() {
- log::warn!("Path '{}' is initialized.", self.path);
+ log::warn!("Folder '{}' is initialized.", self.name);
return Ok(());
}
let output = Command::new("cargo")
.arg("init")
- .arg(&self.path)
+ .arg(&format!("./{}", self.name))
.arg("--bin")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
@@ -58,6 +63,11 @@ impl Init {
let mut file = File::create(main_rs_file)?;
file.write_all(&template_str.as_bytes())?;
+ let mut file = File::create(project_path.join("Dioxus.toml"))?;
+ let dioxus_conf = String::from(include_str!("../../template/config.toml"))
+ .replace("{project-name}", &self.name);
+ file.write_all(dioxus_conf.as_bytes())?;
+
// log::info!("π― Project initialization completed.");
if !Command::new("cargo")
@@ -72,8 +82,9 @@ impl Init {
file.write_all("dioxus = { version = \"0.1.7\", features = [\"web\"] }".as_bytes())?;
}
- log::info!("\nπ‘ Project initialized:");
- log::info!("π―> cd {}", self.path);
+ println!("");
+ log::info!("π‘ Project initialized:");
+ log::info!("π―> cd ./{}", self.name);
log::info!("π―> dioxus serve");
Ok(())
diff --git a/src/cli/serve/mod.rs b/src/cli/serve/mod.rs
index 586d49b7c..7d580f7fb 100644
--- a/src/cli/serve/mod.rs
+++ b/src/cli/serve/mod.rs
@@ -1,4 +1,4 @@
-use crate::{cfg::ConfigOptsServe, server};
+use crate::{cfg::ConfigOptsServe, gen_page, server};
use std::{io::Write, path::PathBuf};
use structopt::StructOpt;
@@ -16,19 +16,31 @@ impl Serve {
// change the relase state.
crate_config.with_release(self.serve.release);
- let dist_path = self.serve.dist.clone().unwrap_or(PathBuf::from("dist"));
+ crate::builder::build(&crate_config).expect("build failed");
- crate::builder::build(&crate_config, dist_path.clone()).expect("build failed");
+ let serve_html = gen_page(&crate_config.dioxus_config, true);
- let serve_html = String::from(include_str!("../../server/serve.html"));
-
- let mut file =
- std::fs::File::create(crate_config.crate_dir.join(dist_path).join("index.html"))?;
+ let mut file = std::fs::File::create(
+ crate_config
+ .crate_dir
+ .join(
+ crate_config
+ .dioxus_config
+ .web
+ .app
+ .out_dir
+ .clone()
+ .unwrap_or(PathBuf::from("dist")),
+ )
+ .join("index.html"),
+ )?;
file.write_all(serve_html.as_bytes())?;
// start the develop server
- server::startup(crate_config.clone(), &self.serve).await?;
+ server::startup(crate_config.clone()).await?;
Ok(())
}
+
+ pub fn regen_page() {}
}
diff --git a/src/config.rs b/src/config.rs
index 9d38160f2..39a3d2038 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,43 +1,76 @@
use crate::error::Result;
use serde::{Deserialize, Serialize};
-use std::path::PathBuf;
-
+use std::{fs::File, io::Read, path::PathBuf};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DioxusConfig {
- application: ApplicationConfig,
- web: WebConfig,
+ pub application: ApplicationConfig,
+ pub web: WebConfig,
+}
+
+impl DioxusConfig {
+ pub fn load() -> crate::error::Result {
+ let crate_dir = crate::cargo::crate_root()?;
+
+ if !crate_dir.join("Dioxus.toml").is_file() {
+ return Err(crate::error::Error::CargoError(
+ "Dioxus.toml not found".into(),
+ ));
+ }
+
+ let mut dioxus_conf_file = File::open(crate_dir.join("Dioxus.toml"))?;
+ let mut meta_str = String::new();
+ dioxus_conf_file.read_to_string(&mut meta_str)?;
+
+ match toml::from_str::(&meta_str) {
+ Ok(v) => return Ok(v),
+ Err(e) => {
+ log::error!("{}", e);
+ return Err(crate::error::Error::Unique(
+ "Dioxus.toml parse failed".into(),
+ ));
+ }
+ }
+ }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationConfig {
- name: String,
- platform: Vec,
+ pub name: String,
+ pub platforms: Vec,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebConfig {
- app: WebAppConfing,
- watcher: WebWatcherConfing,
- resource: WebResourceConfing,
+ pub app: WebAppConfing,
+ pub watcher: WebWatcherConfing,
+ pub resource: WebResourceConfing,
}
-
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebAppConfing {
-
+ pub title: Option,
+ pub out_dir: Option,
+ pub static_dir: Option,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebWatcherConfing {
-
+ pub watch_path: Option>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebResourceConfing {
-
+ pub dev: WebDevResourceConfing,
+ pub style: Option>,
+ pub script: Option>,
}
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct WebDevResourceConfing {
+ pub style: Option>,
+ pub script: Option>,
+}
#[derive(Debug, Clone)]
pub struct CrateConfig {
@@ -48,6 +81,7 @@ pub struct CrateConfig {
pub static_dir: PathBuf,
pub manifest: cargo_toml::Manifest,
pub executable: ExecutableType,
+ pub dioxus_config: DioxusConfig,
pub release: bool,
}
@@ -60,12 +94,23 @@ pub enum ExecutableType {
impl CrateConfig {
pub fn new() -> Result {
+ let dioxus_config = DioxusConfig::load()?;
+
let crate_dir = crate::cargo::crate_root()?;
let workspace_dir = crate::cargo::workspace_root()?;
let target_dir = workspace_dir.join("target");
- let out_dir = crate_dir.join("public");
+
+ let out_dir = match dioxus_config.web.app.out_dir {
+ Some(ref v) => crate_dir.join(v),
+ None => crate_dir.join("dist"),
+ };
+
let cargo_def = &crate_dir.join("Cargo.toml");
- let static_dir = crate_dir.join("static");
+
+ let static_dir = match dioxus_config.web.app.static_dir {
+ Some(ref v) => crate_dir.join(v),
+ None => crate_dir.join("static"),
+ };
let manifest = cargo_toml::Manifest::from_path(&cargo_def).unwrap();
@@ -96,6 +141,7 @@ impl CrateConfig {
manifest,
executable,
release,
+ dioxus_config,
})
}
@@ -124,4 +170,4 @@ impl CrateConfig {
// self.release = options.release;
// self.out_dir = tempfile::Builder::new().tempdir().expect("").into_path();
// }
-}
\ No newline at end of file
+}
diff --git a/src/server/err.html b/src/server/err.html
deleted file mode 100644
index 8fdbf9bae..000000000
--- a/src/server/err.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
- Sorry, but building your application failed.
-
-
- Here's the error:
-
-
- {err}
-
-
-
-
-
diff --git a/src/server/mod.rs b/src/server/mod.rs
index 6b91a2e71..4d33f524e 100644
--- a/src/server/mod.rs
+++ b/src/server/mod.rs
@@ -13,7 +13,7 @@ use std::{
};
use tower_http::services::ServeDir;
-use crate::{builder, CrateConfig};
+use crate::{builder, crate_root, CrateConfig};
struct WsRelodState {
update: bool,
@@ -25,42 +25,54 @@ impl WsRelodState {
}
}
-pub async fn startup(
- config: CrateConfig,
- opts: &crate::cfg::ConfigOptsServe,
-) -> anyhow::Result<()> {
+pub async fn startup(config: CrateConfig) -> anyhow::Result<()> {
log::info!("π Starting development server...");
let (tx, rx) = channel();
- let dist_path = opts.dist.clone().unwrap_or(PathBuf::from("dist"));
+ let dist_path = config.out_dir.clone();
// file watcher: check file change
- let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();
+ let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
watcher
- .watch(
- config.crate_dir.join("src").clone(),
- notify::RecursiveMode::Recursive,
- )
+ .watch(config.crate_dir.clone(), notify::RecursiveMode::Recursive)
.unwrap();
let ws_reload_state = Arc::new(Mutex::new(WsRelodState { update: false }));
let watcher_conf = config.clone();
let watcher_ws_state = ws_reload_state.clone();
- let watcher_dist_path = dist_path.clone();
tokio::spawn(async move {
+ let allow_watch_path = watcher_conf
+ .dioxus_config
+ .web
+ .watcher
+ .watch_path
+ .clone()
+ .unwrap_or(vec![PathBuf::from("src")]);
+ let crate_dir = watcher_conf.crate_dir.clone();
loop {
if let Ok(v) = rx.recv() {
match v {
- DebouncedEvent::Create(_)
- | DebouncedEvent::Write(_)
- | DebouncedEvent::Remove(_)
- | DebouncedEvent::Rename(_, _) => {
- if let Ok(_) = builder::build(&watcher_conf, watcher_dist_path.clone()) {
- // change the websocket reload state to true;
- // the page will auto-reload.
- watcher_ws_state.lock().unwrap().change();
+ DebouncedEvent::Create(e)
+ | DebouncedEvent::Write(e)
+ | DebouncedEvent::Remove(e)
+ | DebouncedEvent::Rename(e, _) => {
+ let mut reload = false;
+ for path in &allow_watch_path {
+ let temp = crate_dir.clone().join(path);
+ if e.starts_with(temp) {
+ reload = true;
+ break;
+ }
+ }
+
+ if reload {
+ if let Ok(_) = builder::build(&watcher_conf) {
+ // change the websocket reload state to true;
+ // the page will auto-reload.
+ watcher_ws_state.lock().unwrap().change();
+ }
}
}
_ => {}
@@ -70,7 +82,7 @@ pub async fn startup(
});
let app = Router::new()
- .route("/ws", get(ws_handler))
+ .route("/_dioxus/ws", get(ws_handler))
.fallback(
get_service(ServeDir::new(config.crate_dir.join(&dist_path))).handle_error(
|error: std::io::Error| async move {
diff --git a/src/server/serve.html b/src/server/serve.html
deleted file mode 100644
index b5268bd68..000000000
--- a/src/server/serve.html
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
- Dioxus-CLI Dev Server
-
-
-
-
-
-
-
-
-
-
diff --git a/src/template/config.toml b/src/template/config.toml
index 9644babc1..ea1efbd4b 100644
--- a/src/template/config.toml
+++ b/src/template/config.toml
@@ -1,9 +1,38 @@
-[package]
-name = "{project}"
-version = "0.1.0"
-edition = "2021"
+[application]
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+# App (Project) Name
+name = "{project-name}"
-[dependencies]
-dioxus = { version = "0.1.7", features = ["web"] }
\ No newline at end of file
+# Dioxus App Support Platform
+# desktop, web, mobile, ssr
+platforms = ["web"]
+
+[web.app]
+
+# HTML title tag content
+title = "dioxus | βΊ"
+
+# Web `build` & `serve` dist path
+out_dir = "dist"
+
+# resource (static) file folder
+static_dir = "static"
+
+[web.watcher]
+
+watch_path = ["src"]
+
+# include `assets` in web platform
+[web.resource]
+
+# CSS style file
+style = []
+
+# Javascript code file
+script = []
+
+[web.resource.dev]
+
+# Javascript code file
+# serve: [dev-server] only
+script = []
\ No newline at end of file
diff --git a/src/template/default.rs b/src/template/default.rs
index ac1614fc4..47b4a2c1d 100644
--- a/src/template/default.rs
+++ b/src/template/default.rs
@@ -8,8 +8,8 @@ fn app(cx: Scope) -> Element {
cx.render(rsx! (
div {
style: "text-align: center;",
- h2 { "ππ Dioxus" }
- p { strong { "Frontend that scales." } }
+ h1 { "π Dioxus π" }
+ h3 { "Frontend that scales." }
p { "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust." }
}
))