beet_cli/commands/
build_steps.rs

1use crate::prelude::*;
2use anyhow::Result;
3use beet::prelude::*;
4use std::os::unix::process::CommandExt;
5use std::path::Path;
6use std::path::PathBuf;
7use std::process::Command;
8use sweet::prelude::GracefulChild;
9
10pub struct BuildNative {
11	build_cmd: CargoBuildCmd,
12}
13
14impl BuildNative {
15	pub fn new(build_cmd: &CargoBuildCmd, watch_args: &BuildArgs) -> Self {
16		let mut build_cmd = build_cmd.clone();
17		if !watch_args.as_static {
18			build_cmd.cargo_args = Some("--features beet/server".to_string());
19		}
20		Self { build_cmd }
21	}
22}
23
24impl BuildStep for BuildNative {
25	fn run(&self) -> Result<()> {
26		println!("🌱 Compiling native binary");
27		self.build_cmd.run()?;
28		Ok(())
29	}
30}
31
32/// Run the native app with the `--static` flag, exporting client islands and html files
33pub struct ExportStatic {
34	exe_path: PathBuf,
35	build_args: BuildArgs,
36}
37
38impl ExportStatic {
39	pub fn new(build_args: &BuildArgs, exe_path: &Path) -> Self {
40		Self {
41			build_args: build_args.clone(),
42			exe_path: exe_path.to_path_buf(),
43		}
44	}
45}
46
47impl BuildStep for ExportStatic {
48	/// run the built binary with the `--static` flag, instructing
49	/// it to not spin up a server, and instead just build the static files,
50	/// saving them to the `html_dir`
51	fn run(&self) -> Result<()> {
52		println!(
53			"🌱 Running native binary to generate static files \nExecuting {}",
54			self.exe_path.display()
55		);
56		Command::new(&self.exe_path)
57			.arg("--html-dir")
58			.arg(&self.build_args.html_dir)
59			.arg("--static")
60			.status()?
61			.exit_ok()?;
62		Ok(())
63	}
64}
65
66
67pub struct BuildWasm {
68	build_cmd: CargoBuildCmd,
69	exe_path: PathBuf,
70	build_args: BuildArgs,
71}
72
73impl BuildWasm {
74	pub fn new(
75		build_native: &CargoBuildCmd,
76		build_args: &BuildArgs,
77	) -> Result<Self> {
78		let mut build_cmd = build_native.clone();
79		build_cmd.target = Some("wasm32-unknown-unknown".to_string());
80		let exe_path = build_cmd.exe_path();
81		let this = Self {
82			build_cmd,
83			exe_path,
84			build_args: build_args.clone(),
85		};
86		Ok(this)
87	}
88
89	/// execute `wasm-bindgen` with inferred locations. The wasm_exe_path
90	/// should be the path to the output of `cargo build`
91	fn wasm_bindgen(&self) -> Result<()> {
92		Command::new("wasm-bindgen")
93			.arg("--out-dir")
94			.arg(self.build_args.html_dir.join("wasm"))
95			.arg("--out-name")
96			.arg("bindgen")
97			.arg("--target")
98			.arg("web")
99			// alternatively es modules target: experimental-nodejs-module
100			.arg("--no-typescript")
101			.arg(&self.exe_path)
102			.status()?
103			.exit_ok()?
104			.xok()
105	}
106
107	// TODO wasm opt
108	fn wasm_opt(&self) -> Result<()> {
109		println!("🌱 Optimizing wasm binary");
110		let out_file = self
111			.build_args
112			.html_dir
113			.join("wasm")
114			.join("bindgen_bg.wasm");
115
116		let size_before = std::fs::metadata(&out_file)?.len();
117
118		Command::new("wasm-opt")
119			.arg("-Oz")
120			.arg("--output")
121			.arg(&out_file)
122			.arg(&out_file)
123			.status()?
124			.exit_ok()?;
125
126		let size_after = std::fs::metadata(&out_file)?.len();
127		println!(
128			"🌱 Reduced wasm binary from {} to {}",
129			format!("{} KB", size_before as usize / 1024),
130			format!("{} KB", size_after as usize / 1024)
131		);
132
133		Ok(())
134	}
135}
136
137impl BuildStep for BuildWasm {
138	fn run(&self) -> Result<()> {
139		println!("🌱 Compiling wasm binary");
140		self.build_cmd.spawn()?;
141		self.wasm_bindgen()?;
142		if self.build_cmd.release {
143			self.wasm_opt()?;
144		}
145		Ok(())
146	}
147}
148
149
150pub struct RunServer {
151	exe_path: PathBuf,
152	build_args: BuildArgs,
153	child_process: GracefulChild,
154}
155
156impl RunServer {
157	pub fn new(build_args: &BuildArgs, exe_path: &Path) -> Self {
158		Self {
159			build_args: build_args.clone(),
160			exe_path: exe_path.to_path_buf(),
161			child_process: GracefulChild::default().as_only_ctrlc_handler(),
162		}
163	}
164}
165
166impl BuildStep for RunServer {
167	/// run the built binary with the `--static` flag, instructing
168	/// it to not spin up a server, and instead just build the static files
169	fn run(&self) -> Result<()> {
170		if self.build_args.as_static {
171			return Ok(());
172		}
173
174		self.child_process.kill();
175
176		let child = Command::new(&self.exe_path)
177			.arg("--html-dir")
178			.arg(&self.build_args.html_dir)
179			// kill child when parent is killed
180			.process_group(0)
181			.spawn()?;
182		self.child_process.set(child);
183		Ok(())
184	}
185}