builder.rs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. use crate::{
  2. config::{CrateConfig, ExecutableType},
  3. error::{Error, Result},
  4. tools::Tool,
  5. };
  6. use cargo_metadata::{diagnostic::Diagnostic, Message};
  7. use indicatif::{ProgressBar, ProgressStyle};
  8. use manganis_cli_support::AssetManifestExt;
  9. use serde::Serialize;
  10. use std::{
  11. fs::{copy, create_dir_all, File},
  12. io::{Read, Write},
  13. panic,
  14. path::PathBuf,
  15. time::Duration,
  16. };
  17. use wasm_bindgen_cli_support::Bindgen;
  18. #[derive(Serialize, Debug, Clone)]
  19. pub struct BuildResult {
  20. pub warnings: Vec<Diagnostic>,
  21. pub elapsed_time: u128,
  22. }
  23. pub fn build(config: &CrateConfig, _: bool, skip_assets: bool) -> Result<BuildResult> {
  24. // [1] Build the project with cargo, generating a wasm32-unknown-unknown target (is there a more specific, better target to leverage?)
  25. // [2] Generate the appropriate build folders
  26. // [3] Wasm-bindgen the .wasm fiile, and move it into the {builddir}/modules/xxxx/xxxx_bg.wasm
  27. // [4] Wasm-opt the .wasm file with whatever optimizations need to be done
  28. // [5][OPTIONAL] Builds the Tailwind CSS file using the Tailwind standalone binary
  29. // [6] Link up the html page to the wasm module
  30. let CrateConfig {
  31. out_dir,
  32. crate_dir,
  33. target_dir,
  34. asset_dir,
  35. executable,
  36. dioxus_config,
  37. ..
  38. } = config;
  39. let _gaurd = WebAssetConfigDropGuard::new();
  40. // start to build the assets
  41. let ignore_files = build_assets(config)?;
  42. let t_start = std::time::Instant::now();
  43. // [1] Build the .wasm module
  44. log::info!("🚅 Running build command...");
  45. let cmd = subprocess::Exec::cmd("cargo");
  46. let cmd = cmd
  47. .cwd(crate_dir)
  48. .arg("build")
  49. .arg("--target")
  50. .arg("wasm32-unknown-unknown")
  51. .arg("--message-format=json")
  52. .arg("--quiet");
  53. let cmd = if config.release {
  54. cmd.arg("--release")
  55. } else {
  56. cmd
  57. };
  58. let cmd = if config.verbose {
  59. cmd.arg("--verbose")
  60. } else {
  61. cmd
  62. };
  63. let cmd = if config.custom_profile.is_some() {
  64. let custom_profile = config.custom_profile.as_ref().unwrap();
  65. cmd.arg("--profile").arg(custom_profile)
  66. } else {
  67. cmd
  68. };
  69. let cmd = if config.features.is_some() {
  70. let features_str = config.features.as_ref().unwrap().join(" ");
  71. cmd.arg("--features").arg(features_str)
  72. } else {
  73. cmd
  74. };
  75. let cmd = match executable {
  76. ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
  77. ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
  78. ExecutableType::Example(name) => cmd.arg("--example").arg(name),
  79. };
  80. let warning_messages = prettier_build(cmd)?;
  81. // [2] Establish the output directory structure
  82. let bindgen_outdir = out_dir.join("assets").join("dioxus");
  83. let build_profile = if config.custom_profile.is_some() {
  84. config.custom_profile.as_ref().unwrap()
  85. } else if config.release {
  86. "release"
  87. } else {
  88. "debug"
  89. };
  90. let input_path = match executable {
  91. ExecutableType::Binary(name) | ExecutableType::Lib(name) => target_dir
  92. .join(format!("wasm32-unknown-unknown/{}", build_profile))
  93. .join(format!("{}.wasm", name)),
  94. ExecutableType::Example(name) => target_dir
  95. .join(format!("wasm32-unknown-unknown/{}/examples", build_profile))
  96. .join(format!("{}.wasm", name)),
  97. };
  98. let bindgen_result = panic::catch_unwind(move || {
  99. // [3] Bindgen the final binary for use easy linking
  100. let mut bindgen_builder = Bindgen::new();
  101. bindgen_builder
  102. .input_path(input_path)
  103. .web(true)
  104. .unwrap()
  105. .debug(true)
  106. .demangle(true)
  107. .keep_debug(true)
  108. .remove_name_section(false)
  109. .remove_producers_section(false)
  110. .out_name(&dioxus_config.application.name)
  111. .generate(&bindgen_outdir)
  112. .unwrap();
  113. });
  114. if bindgen_result.is_err() {
  115. return Err(Error::BuildFailed("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.81` Bindgen crate.".to_string()));
  116. }
  117. // check binaryen:wasm-opt tool
  118. let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default();
  119. if dioxus_tools.contains_key("binaryen") {
  120. let info = dioxus_tools.get("binaryen").unwrap();
  121. let binaryen = crate::tools::Tool::Binaryen;
  122. if binaryen.is_installed() {
  123. if let Some(sub) = info.as_table() {
  124. if sub.contains_key("wasm_opt")
  125. && sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false)
  126. {
  127. log::info!("Optimizing WASM size with wasm-opt...");
  128. let target_file = out_dir
  129. .join("assets")
  130. .join("dioxus")
  131. .join(format!("{}_bg.wasm", dioxus_config.application.name));
  132. if target_file.is_file() {
  133. let mut args = vec![
  134. target_file.to_str().unwrap(),
  135. "-o",
  136. target_file.to_str().unwrap(),
  137. ];
  138. if config.release {
  139. args.push("-Oz");
  140. }
  141. binaryen.call("wasm-opt", args)?;
  142. }
  143. }
  144. }
  145. } else {
  146. log::warn!(
  147. "Binaryen tool not found, you can use `dx tool add binaryen` to install it."
  148. );
  149. }
  150. }
  151. // [5][OPTIONAL] If tailwind is enabled and installed we run it to generate the CSS
  152. if dioxus_tools.contains_key("tailwindcss") {
  153. let info = dioxus_tools.get("tailwindcss").unwrap();
  154. let tailwind = crate::tools::Tool::Tailwind;
  155. if tailwind.is_installed() {
  156. if let Some(sub) = info.as_table() {
  157. log::info!("Building Tailwind bundle CSS file...");
  158. let input_path = match sub.get("input") {
  159. Some(val) => val.as_str().unwrap(),
  160. None => "./public",
  161. };
  162. let config_path = match sub.get("config") {
  163. Some(val) => val.as_str().unwrap(),
  164. None => "./src/tailwind.config.js",
  165. };
  166. let mut args = vec![
  167. "-i",
  168. input_path,
  169. "-o",
  170. "dist/tailwind.css",
  171. "-c",
  172. config_path,
  173. ];
  174. if config.release {
  175. args.push("--minify");
  176. }
  177. tailwind.call("tailwindcss", args)?;
  178. }
  179. } else {
  180. log::warn!(
  181. "Tailwind tool not found, you can use `dx tool add tailwindcss` to install it."
  182. );
  183. }
  184. }
  185. // this code will copy all public file to the output dir
  186. let copy_options = fs_extra::dir::CopyOptions {
  187. overwrite: true,
  188. skip_exist: false,
  189. buffer_size: 64000,
  190. copy_inside: false,
  191. content_only: false,
  192. depth: 0,
  193. };
  194. if asset_dir.is_dir() {
  195. for entry in std::fs::read_dir(asset_dir)? {
  196. let path = entry?.path();
  197. if path.is_file() {
  198. std::fs::copy(&path, out_dir.join(path.file_name().unwrap()))?;
  199. } else {
  200. match fs_extra::dir::copy(&path, out_dir, &copy_options) {
  201. Ok(_) => {}
  202. Err(_e) => {
  203. log::warn!("Error copying dir: {}", _e);
  204. }
  205. }
  206. for ignore in &ignore_files {
  207. let ignore = ignore.strip_prefix(&config.asset_dir).unwrap();
  208. let ignore = config.out_dir.join(ignore);
  209. if ignore.is_file() {
  210. std::fs::remove_file(ignore)?;
  211. }
  212. }
  213. }
  214. }
  215. }
  216. if !skip_assets {
  217. process_assets(config)?;
  218. }
  219. Ok(BuildResult {
  220. warnings: warning_messages,
  221. elapsed_time: t_start.elapsed().as_millis(),
  222. })
  223. }
  224. pub fn build_desktop(
  225. config: &CrateConfig,
  226. _is_serve: bool,
  227. skip_assets: bool,
  228. ) -> Result<BuildResult> {
  229. log::info!("🚅 Running build [Desktop] command...");
  230. let t_start = std::time::Instant::now();
  231. let ignore_files = build_assets(config)?;
  232. let mut cmd = subprocess::Exec::cmd("cargo")
  233. .cwd(&config.crate_dir)
  234. .arg("build")
  235. .arg("--message-format=json");
  236. if config.release {
  237. cmd = cmd.arg("--release");
  238. }
  239. if config.verbose {
  240. cmd = cmd.arg("--verbose");
  241. }
  242. if config.custom_profile.is_some() {
  243. let custom_profile = config.custom_profile.as_ref().unwrap();
  244. cmd = cmd.arg("--profile").arg(custom_profile);
  245. }
  246. if config.features.is_some() {
  247. let features_str = config.features.as_ref().unwrap().join(" ");
  248. cmd = cmd.arg("--features").arg(features_str);
  249. }
  250. let cmd = match &config.executable {
  251. crate::ExecutableType::Binary(name) => cmd.arg("--bin").arg(name),
  252. crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name),
  253. crate::ExecutableType::Example(name) => cmd.arg("--example").arg(name),
  254. };
  255. let warning_messages = prettier_build(cmd)?;
  256. let release_type = match config.release {
  257. true => "release",
  258. false => "debug",
  259. };
  260. let file_name: String;
  261. let mut res_path = match &config.executable {
  262. crate::ExecutableType::Binary(name) | crate::ExecutableType::Lib(name) => {
  263. file_name = name.clone();
  264. config.target_dir.join(release_type).join(name)
  265. }
  266. crate::ExecutableType::Example(name) => {
  267. file_name = name.clone();
  268. config
  269. .target_dir
  270. .join(release_type)
  271. .join("examples")
  272. .join(name)
  273. }
  274. };
  275. let target_file = if cfg!(windows) {
  276. res_path.set_extension("exe");
  277. format!("{}.exe", &file_name)
  278. } else {
  279. file_name
  280. };
  281. if !config.out_dir.is_dir() {
  282. create_dir_all(&config.out_dir)?;
  283. }
  284. copy(res_path, &config.out_dir.join(target_file))?;
  285. // this code will copy all public file to the output dir
  286. if config.asset_dir.is_dir() {
  287. let copy_options = fs_extra::dir::CopyOptions {
  288. overwrite: true,
  289. skip_exist: false,
  290. buffer_size: 64000,
  291. copy_inside: false,
  292. content_only: false,
  293. depth: 0,
  294. };
  295. for entry in std::fs::read_dir(&config.asset_dir)? {
  296. let path = entry?.path();
  297. if path.is_file() {
  298. std::fs::copy(&path, &config.out_dir.join(path.file_name().unwrap()))?;
  299. } else {
  300. match fs_extra::dir::copy(&path, &config.out_dir, &copy_options) {
  301. Ok(_) => {}
  302. Err(e) => {
  303. log::warn!("Error copying dir: {}", e);
  304. }
  305. }
  306. for ignore in &ignore_files {
  307. let ignore = ignore.strip_prefix(&config.asset_dir).unwrap();
  308. let ignore = config.out_dir.join(ignore);
  309. if ignore.is_file() {
  310. std::fs::remove_file(ignore)?;
  311. }
  312. }
  313. }
  314. }
  315. }
  316. if !skip_assets {
  317. // Collect assets
  318. process_assets(config)?;
  319. // Create the __assets_head.html file for bundling
  320. create_assets_head(config)?;
  321. }
  322. log::info!(
  323. "🚩 Build completed: [./{}]",
  324. config
  325. .dioxus_config
  326. .application
  327. .out_dir
  328. .clone()
  329. .unwrap_or_else(|| PathBuf::from("dist"))
  330. .display()
  331. );
  332. println!("build desktop done");
  333. Ok(BuildResult {
  334. warnings: warning_messages,
  335. elapsed_time: t_start.elapsed().as_millis(),
  336. })
  337. }
  338. fn create_assets_head(config: &CrateConfig) -> Result<()> {
  339. let manifest = config.asset_manifest();
  340. let mut file = File::create(config.out_dir.join("__assets_head.html"))?;
  341. file.write_all(manifest.head().as_bytes())?;
  342. Ok(())
  343. }
  344. fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result<Vec<Diagnostic>> {
  345. let mut warning_messages: Vec<Diagnostic> = vec![];
  346. let pb = ProgressBar::new_spinner();
  347. pb.enable_steady_tick(Duration::from_millis(200));
  348. pb.set_style(
  349. ProgressStyle::with_template("{spinner:.dim.bold} {wide_msg}")
  350. .unwrap()
  351. .tick_chars("/|\\- "),
  352. );
  353. pb.set_message("💼 Waiting to start build the project...");
  354. struct StopSpinOnDrop(ProgressBar);
  355. impl Drop for StopSpinOnDrop {
  356. fn drop(&mut self) {
  357. self.0.finish_and_clear();
  358. }
  359. }
  360. let stdout = cmd.detached().stream_stdout()?;
  361. let reader = std::io::BufReader::new(stdout);
  362. for message in cargo_metadata::Message::parse_stream(reader) {
  363. match message.unwrap() {
  364. Message::CompilerMessage(msg) => {
  365. let message = msg.message;
  366. match message.level {
  367. cargo_metadata::diagnostic::DiagnosticLevel::Error => {
  368. return {
  369. Err(anyhow::anyhow!(message
  370. .rendered
  371. .unwrap_or("Unknown".into())))
  372. };
  373. }
  374. cargo_metadata::diagnostic::DiagnosticLevel::Warning => {
  375. warning_messages.push(message.clone());
  376. }
  377. _ => {}
  378. }
  379. }
  380. Message::CompilerArtifact(artifact) => {
  381. pb.set_message(format!("⚙️ Compiling {} ", artifact.package_id));
  382. pb.tick();
  383. }
  384. Message::BuildScriptExecuted(script) => {
  385. let _package_id = script.package_id.to_string();
  386. }
  387. Message::BuildFinished(finished) => {
  388. if finished.success {
  389. log::info!("👑 Build done.");
  390. } else {
  391. std::process::exit(1);
  392. }
  393. }
  394. _ => (), // Unknown message
  395. }
  396. }
  397. Ok(warning_messages)
  398. }
  399. pub fn gen_page(config: &CrateConfig, serve: bool, skip_assets: bool) -> String {
  400. let _gaurd = WebAssetConfigDropGuard::new();
  401. let crate_root = crate::cargo::crate_root().unwrap();
  402. let custom_html_file = crate_root.join("index.html");
  403. let mut html = if custom_html_file.is_file() {
  404. let mut buf = String::new();
  405. let mut file = File::open(custom_html_file).unwrap();
  406. if file.read_to_string(&mut buf).is_ok() {
  407. buf
  408. } else {
  409. String::from(include_str!("./assets/index.html"))
  410. }
  411. } else {
  412. String::from(include_str!("./assets/index.html"))
  413. };
  414. let resources = config.dioxus_config.web.resource.clone();
  415. let mut style_list = resources.style.unwrap_or_default();
  416. let mut script_list = resources.script.unwrap_or_default();
  417. if serve {
  418. let mut dev_style = resources.dev.style.clone().unwrap_or_default();
  419. let mut dev_script = resources.dev.script.unwrap_or_default();
  420. style_list.append(&mut dev_style);
  421. script_list.append(&mut dev_script);
  422. }
  423. let mut style_str = String::new();
  424. for style in style_list {
  425. style_str.push_str(&format!(
  426. "<link rel=\"stylesheet\" href=\"{}\">\n",
  427. &style.to_str().unwrap(),
  428. ))
  429. }
  430. if config
  431. .dioxus_config
  432. .application
  433. .tools
  434. .clone()
  435. .unwrap_or_default()
  436. .contains_key("tailwindcss")
  437. {
  438. style_str.push_str("<link rel=\"stylesheet\" href=\"tailwind.css\">\n");
  439. }
  440. if !skip_assets {
  441. let manifest = config.asset_manifest();
  442. style_str.push_str(&manifest.head());
  443. }
  444. replace_or_insert_before("{style_include}", &style_str, "</head", &mut html);
  445. let mut script_str = String::new();
  446. for script in script_list {
  447. script_str.push_str(&format!(
  448. "<script src=\"{}\"></script>\n",
  449. &script.to_str().unwrap(),
  450. ))
  451. }
  452. replace_or_insert_before("{script_include}", &script_str, "</body", &mut html);
  453. if serve {
  454. html += &format!(
  455. "<script>{}</script>",
  456. include_str!("./assets/autoreload.js")
  457. );
  458. }
  459. let base_path = match &config.dioxus_config.web.app.base_path {
  460. Some(path) => path,
  461. None => ".",
  462. };
  463. let app_name = &config.dioxus_config.application.name;
  464. // Check if a script already exists
  465. if html.contains("{app_name}") && html.contains("{base_path}") {
  466. html = html.replace("{app_name}", app_name);
  467. html = html.replace("{base_path}", base_path);
  468. } else {
  469. // If not, insert the script
  470. html = html.replace(
  471. "</body",
  472. &format!(
  473. r#"<script type="module">
  474. import init from "/{base_path}/assets/dioxus/{app_name}.js";
  475. init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => {{
  476. if (wasm.__wbindgen_start == undefined) {{
  477. wasm.main();
  478. }}
  479. }});
  480. </script>
  481. </body"#
  482. ),
  483. );
  484. }
  485. let title = config
  486. .dioxus_config
  487. .web
  488. .app
  489. .title
  490. .clone()
  491. .unwrap_or_else(|| "dioxus | ⛺".into());
  492. replace_or_insert_before("{app_title}", &title, "</title", &mut html);
  493. html
  494. }
  495. fn replace_or_insert_before(
  496. replace: &str,
  497. with: &str,
  498. or_insert_before: &str,
  499. content: &mut String,
  500. ) {
  501. if content.contains(replace) {
  502. *content = content.replace(replace, with);
  503. } else {
  504. *content = content.replace(or_insert_before, &format!("{}{}", with, or_insert_before));
  505. }
  506. }
  507. // this function will build some assets file
  508. // like sass tool resources
  509. // this function will return a array which file don't need copy to out_dir.
  510. fn build_assets(config: &CrateConfig) -> Result<Vec<PathBuf>> {
  511. let mut result = vec![];
  512. let dioxus_config = &config.dioxus_config;
  513. let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default();
  514. // check sass tool state
  515. let sass = Tool::Sass;
  516. if sass.is_installed() && dioxus_tools.contains_key("sass") {
  517. let sass_conf = dioxus_tools.get("sass").unwrap();
  518. if let Some(tab) = sass_conf.as_table() {
  519. let source_map = tab.contains_key("source_map");
  520. let source_map = if source_map && tab.get("source_map").unwrap().is_bool() {
  521. if tab.get("source_map").unwrap().as_bool().unwrap_or_default() {
  522. "--source-map"
  523. } else {
  524. "--no-source-map"
  525. }
  526. } else {
  527. "--source-map"
  528. };
  529. if tab.contains_key("input") {
  530. if tab.get("input").unwrap().is_str() {
  531. let file = tab.get("input").unwrap().as_str().unwrap().trim();
  532. if file == "*" {
  533. // if the sass open auto, we need auto-check the assets dir.
  534. let asset_dir = config.asset_dir.clone();
  535. if asset_dir.is_dir() {
  536. for entry in walkdir::WalkDir::new(&asset_dir)
  537. .into_iter()
  538. .filter_map(|e| e.ok())
  539. {
  540. let temp = entry.path();
  541. if temp.is_file() {
  542. let suffix = temp.extension();
  543. if suffix.is_none() {
  544. continue;
  545. }
  546. let suffix = suffix.unwrap().to_str().unwrap();
  547. if suffix == "scss" || suffix == "sass" {
  548. // if file suffix is `scss` / `sass` we need transform it.
  549. let out_file = format!(
  550. "{}.css",
  551. temp.file_stem().unwrap().to_str().unwrap()
  552. );
  553. let target_path = config
  554. .out_dir
  555. .join(
  556. temp.strip_prefix(&asset_dir)
  557. .unwrap()
  558. .parent()
  559. .unwrap(),
  560. )
  561. .join(out_file);
  562. let res = sass.call(
  563. "sass",
  564. vec![
  565. temp.to_str().unwrap(),
  566. target_path.to_str().unwrap(),
  567. source_map,
  568. ],
  569. );
  570. if res.is_ok() {
  571. result.push(temp.to_path_buf());
  572. }
  573. }
  574. }
  575. }
  576. }
  577. } else {
  578. // just transform one file.
  579. let relative_path = if &file[0..1] == "/" {
  580. &file[1..file.len()]
  581. } else {
  582. file
  583. };
  584. let path = config.asset_dir.join(relative_path);
  585. let out_file =
  586. format!("{}.css", path.file_stem().unwrap().to_str().unwrap());
  587. let target_path = config
  588. .out_dir
  589. .join(PathBuf::from(relative_path).parent().unwrap())
  590. .join(out_file);
  591. if path.is_file() {
  592. let res = sass.call(
  593. "sass",
  594. vec![
  595. path.to_str().unwrap(),
  596. target_path.to_str().unwrap(),
  597. source_map,
  598. ],
  599. );
  600. if res.is_ok() {
  601. result.push(path);
  602. } else {
  603. log::error!("{:?}", res);
  604. }
  605. }
  606. }
  607. } else if tab.get("input").unwrap().is_array() {
  608. // check files list.
  609. let list = tab.get("input").unwrap().as_array().unwrap();
  610. for i in list {
  611. if i.is_str() {
  612. let path = i.as_str().unwrap();
  613. let relative_path = if &path[0..1] == "/" {
  614. &path[1..path.len()]
  615. } else {
  616. path
  617. };
  618. let path = config.asset_dir.join(relative_path);
  619. let out_file =
  620. format!("{}.css", path.file_stem().unwrap().to_str().unwrap());
  621. let target_path = config
  622. .out_dir
  623. .join(PathBuf::from(relative_path).parent().unwrap())
  624. .join(out_file);
  625. if path.is_file() {
  626. let res = sass.call(
  627. "sass",
  628. vec![
  629. path.to_str().unwrap(),
  630. target_path.to_str().unwrap(),
  631. source_map,
  632. ],
  633. );
  634. if res.is_ok() {
  635. result.push(path);
  636. }
  637. }
  638. }
  639. }
  640. }
  641. }
  642. }
  643. }
  644. // SASS END
  645. Ok(result)
  646. }
  647. /// Process any assets collected from the binary
  648. fn process_assets(config: &CrateConfig) -> anyhow::Result<()> {
  649. let manifest = config.asset_manifest();
  650. let static_asset_output_dir = PathBuf::from(
  651. config
  652. .dioxus_config
  653. .web
  654. .app
  655. .base_path
  656. .clone()
  657. .unwrap_or_default(),
  658. );
  659. let static_asset_output_dir = config.out_dir.join(static_asset_output_dir);
  660. manifest.copy_static_assets_to(static_asset_output_dir)?;
  661. Ok(())
  662. }
  663. // use binary_install::{Cache, Download};
  664. // /// Attempts to find `wasm-opt` in `PATH` locally, or failing that downloads a
  665. // /// precompiled binary.
  666. // ///
  667. // /// Returns `Some` if a binary was found or it was successfully downloaded.
  668. // /// Returns `None` if a binary wasn't found in `PATH` and this platform doesn't
  669. // /// have precompiled binaries. Returns an error if we failed to download the
  670. // /// binary.
  671. // pub fn find_wasm_opt(
  672. // cache: &Cache,
  673. // install_permitted: bool,
  674. // ) -> Result<install::Status, failure::Error> {
  675. // // First attempt to look up in PATH. If found assume it works.
  676. // if let Ok(path) = which::which("wasm-opt") {
  677. // PBAR.info(&format!("found wasm-opt at {:?}", path));
  678. // match path.as_path().parent() {
  679. // Some(path) => return Ok(install::Status::Found(Download::at(path))),
  680. // None => {}
  681. // }
  682. // }
  683. // let version = "version_78";
  684. // Ok(install::download_prebuilt(
  685. // &install::Tool::WasmOpt,
  686. // cache,
  687. // version,
  688. // install_permitted,
  689. // )?)
  690. // }
  691. pub(crate) struct WebAssetConfigDropGuard;
  692. impl WebAssetConfigDropGuard {
  693. pub fn new() -> Self {
  694. // Set up the collect asset config
  695. manganis_cli_support::Config::default()
  696. .with_assets_serve_location("/")
  697. .save();
  698. Self {}
  699. }
  700. }
  701. impl Drop for WebAssetConfigDropGuard {
  702. fn drop(&mut self) {
  703. // Reset the config
  704. manganis_cli_support::Config::default().save();
  705. }
  706. }