dioxus/src/builder.rs

328 lines
10 KiB
Rust
Raw Normal View History

2021-07-07 20:54:14 +00:00
use crate::{
2021-12-29 17:03:18 +00:00
config::{CrateConfig, ExecutableType},
error::{Error, Result},
2022-01-23 09:35:59 +00:00
DioxusConfig,
2021-07-07 20:54:14 +00:00
};
2022-01-24 03:55:27 +00:00
use std::{
fs::{copy, create_dir_all, remove_dir_all},
2022-02-11 08:54:35 +00:00
panic,
2022-01-24 03:55:27 +00:00
path::PathBuf,
process::Command,
};
2021-07-07 20:54:14 +00:00
use wasm_bindgen_cli_support::Bindgen;
2022-01-23 09:35:59 +00:00
pub fn build(config: &CrateConfig) -> Result<()> {
2022-02-09 20:02:09 +00:00
// [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
// [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm
// [4] Wasm-opt the .wasm file with whatever optimizations need to be done
// [5] Link up the html page to the wasm module
2021-07-07 20:54:14 +00:00
2021-12-29 17:03:18 +00:00
let CrateConfig {
2022-01-23 09:35:59 +00:00
out_dir,
2021-07-07 20:54:14 +00:00
crate_dir,
target_dir,
2022-02-17 11:28:54 +00:00
asset_dir,
2021-07-07 20:54:14 +00:00
executable,
2022-01-23 09:35:59 +00:00
dioxus_config,
2021-07-07 20:54:14 +00:00
..
} = config;
let t_start = std::time::Instant::now();
// [1] Build the .wasm module
2022-01-23 02:54:24 +00:00
log::info!("🚅 Running build command...");
2021-07-07 20:54:14 +00:00
let mut cmd = Command::new("cargo");
cmd.current_dir(&crate_dir)
.arg("build")
.arg("--target")
.arg("wasm32-unknown-unknown")
2022-01-22 14:19:59 +00:00
.stdout(std::process::Stdio::inherit())
2022-01-22 17:29:36 +00:00
.stderr(std::process::Stdio::inherit());
2021-07-07 20:54:14 +00:00
if config.release {
cmd.arg("--release");
}
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),
};
2022-01-22 14:19:59 +00:00
let output = cmd.output()?;
2022-01-22 02:02:52 +00:00
2022-01-23 04:11:17 +00:00
if !output.status.success() {
2021-12-29 17:03:18 +00:00
log::error!("Build failed!");
2022-01-22 14:19:59 +00:00
let reason = String::from_utf8_lossy(&output.stderr).to_string();
2021-12-29 17:03:18 +00:00
return Err(Error::BuildFailed(reason));
}
2022-01-23 09:35:59 +00:00
2021-07-07 20:54:14 +00:00
// [2] Establish the output directory structure
2022-01-23 14:50:23 +00:00
let bindgen_outdir = out_dir.join("assets").join("dioxus");
2021-07-07 20:54:14 +00:00
let release_type = match config.release {
true => "release",
false => "debug",
};
let input_path = match executable {
ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir
.join(format!("wasm32-unknown-unknown/{}", release_type))
.join(format!("{}.wasm", name)),
ExecutableType::Example(name) => target_dir
.join(format!("wasm32-unknown-unknown/{}/examples", release_type))
.join(format!("{}.wasm", name)),
};
2022-02-11 08:54:35 +00:00
let bindgen_result = panic::catch_unwind(move || {
// [3] Bindgen the final binary for use easy linking
let mut bindgen_builder = Bindgen::new();
bindgen_builder
.input_path(input_path)
.web(true)
.unwrap()
2022-02-11 08:54:35 +00:00
.debug(true)
.demangle(true)
.keep_debug(true)
.remove_name_section(false)
.remove_producers_section(false)
.out_name(&dioxus_config.application.name)
.generate(&bindgen_outdir)
.unwrap();
2022-02-11 08:54:35 +00:00
});
if bindgen_result.is_err() {
2022-02-17 11:32:56 +00:00
log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate.");
2022-02-11 08:54:35 +00:00
}
// this code will copy all public file to the output dir
2022-01-23 14:50:23 +00:00
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
skip_exist: false,
buffer_size: 64000,
copy_inside: false,
content_only: false,
depth: 0,
};
2022-02-17 11:28:54 +00:00
if asset_dir.is_dir() {
for entry in std::fs::read_dir(&asset_dir)? {
2022-01-23 14:50:23 +00:00
let path = entry?.path();
if path.is_file() {
std::fs::copy(&path, out_dir.join(path.file_name().unwrap()))?;
} else {
match fs_extra::dir::copy(&path, out_dir, &copy_options) {
Ok(_) => {}
Err(_e) => {
log::warn!("Error copying dir: {}", _e);
}
}
2022-01-22 02:02:52 +00:00
}
2021-07-07 20:54:14 +00:00
}
}
let t_end = std::time::Instant::now();
2022-01-22 14:19:59 +00:00
log::info!("🏁 Done in {}ms!", (t_end - t_start).as_millis());
2021-07-07 20:54:14 +00:00
Ok(())
}
2022-02-09 13:25:29 +00:00
pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> {
2022-01-24 03:55:27 +00:00
log::info!("🚅 Running build [Desktop] command...");
let mut cmd = Command::new("cargo");
cmd.current_dir(&config.crate_dir)
.arg("build")
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit());
if config.release {
cmd.arg("--release");
}
match &config.executable {
crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
crate::ExecutableType::Example(name) => cmd.arg("--example").arg(name),
};
let output = cmd.output()?;
2022-01-27 15:06:09 +00:00
if !output.status.success() {
return Err(Error::BuildFailed("Program build failed.".into()));
}
2022-01-24 03:55:27 +00:00
if output.status.success() {
2022-02-09 13:25:29 +00:00
// this code will clean the output dir.
// if using the serve, we will not clean the out_dir.
if config.out_dir.is_dir() && !is_serve {
2022-01-24 03:55:27 +00:00
remove_dir_all(&config.out_dir)?;
}
let release_type = match config.release {
true => "release",
false => "debug",
};
let file_name: String;
let mut res_path = match &config.executable {
crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => {
file_name = name.clone();
config
.target_dir
2022-01-25 04:42:27 +00:00
.join(release_type.to_string())
.join(name.to_string())
2022-01-24 03:55:27 +00:00
}
crate::ExecutableType::Example(name) => {
file_name = name.clone();
config
.target_dir
2022-01-25 04:42:27 +00:00
.join(release_type.to_string())
2022-01-24 03:55:27 +00:00
.join("examples")
2022-01-25 04:42:27 +00:00
.join(name.to_string())
2022-01-24 03:55:27 +00:00
}
};
2022-01-25 09:51:36 +00:00
let target_file = if cfg!(windows) {
2022-01-24 03:55:27 +00:00
res_path.set_extension("exe");
2022-01-25 09:51:36 +00:00
format!("{}.exe", &file_name)
2022-01-24 03:55:27 +00:00
} else {
2022-01-25 09:51:36 +00:00
file_name
};
if !config.out_dir.is_dir() {
create_dir_all(&config.out_dir)?;
}
2022-01-24 03:55:27 +00:00
copy(res_path, &config.out_dir.join(target_file))?;
// this code will copy all public file to the output dir
2022-02-17 11:28:54 +00:00
if config.asset_dir.is_dir() {
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
skip_exist: false,
buffer_size: 64000,
copy_inside: false,
content_only: false,
depth: 0,
};
2022-02-17 11:28:54 +00:00
for entry in std::fs::read_dir(&config.asset_dir)? {
let path = entry?.path();
if path.is_file() {
std::fs::copy(&path, &config.out_dir.join(path.file_name().unwrap()))?;
} else {
match fs_extra::dir::copy(&path, &config.out_dir, &copy_options) {
Ok(_) => {}
Err(e) => {
log::warn!("Error copying dir: {}", e);
}
}
}
}
}
2022-01-24 03:55:27 +00:00
log::info!(
"🚩 Build completed: [./{}]",
config
.dioxus_config
.application
.out_dir
.clone()
2022-01-25 05:52:33 +00:00
.unwrap_or_else(|| PathBuf::from("dist"))
2022-01-24 03:55:27 +00:00
.display()
);
}
Ok(())
}
2022-01-23 09:35:59 +00:00
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();
2022-01-25 04:42:27 +00:00
let mut style_list = resouces.style.unwrap_or_default();
let mut script_list = resouces.script.unwrap_or_default();
2022-01-23 09:35:59 +00:00
if serve {
2022-01-25 04:42:27 +00:00
let mut dev_style = resouces.dev.style.clone().unwrap_or_default();
let mut dev_script = resouces.dev.script.unwrap_or_default();
2022-01-23 09:35:59 +00:00
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!(
"<link rel=\"stylesheet\" href=\"{}\">\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!(
"<script src=\"{}\"></script>\n",
&script.to_str().unwrap(),
))
}
html = html.replace("{script_include}", &script_str);
if serve {
html += &format!(
"<script>{}</script>",
include_str!("./assets/autoreload.js")
);
}
html = html.replace("{app_name}", &config.application.name);
html = match &config.web.app.base_path {
Some(path) => html.replace("{base_path}", path),
None => html.replace("{base_path}", "."),
};
2022-01-25 09:51:36 +00:00
let title = config
.web
.app
.title
.clone()
.unwrap_or_else(|| "dioxus | ⛺".into());
2022-01-23 09:35:59 +00:00
html.replace("{app_title}", &title)
2021-07-07 20:54:14 +00:00
}
2021-12-29 16:04:18 +00:00
// use binary_install::{Cache, Download};
// /// Attempts to find `wasm-opt` in `PATH` locally, or failing that downloads a
// /// precompiled binary.
// ///
// /// Returns `Some` if a binary was found or it was successfully downloaded.
// /// Returns `None` if a binary wasn't found in `PATH` and this platform doesn't
// /// have precompiled binaries. Returns an error if we failed to download the
// /// binary.
// pub fn find_wasm_opt(
// cache: &Cache,
// install_permitted: bool,
// ) -> Result<install::Status, failure::Error> {
// // First attempt to look up in PATH. If found assume it works.
// if let Ok(path) = which::which("wasm-opt") {
// PBAR.info(&format!("found wasm-opt at {:?}", path));
// match path.as_path().parent() {
// Some(path) => return Ok(install::Status::Found(Download::at(path))),
// None => {}
// }
// }
// let version = "version_78";
// Ok(install::download_prebuilt(
// &install::Tool::WasmOpt,
// cache,
// version,
// install_permitted,
// )?)
// }