Skip to content

Commit

Permalink
feat(cli): added inbuilt server for exported apps
Browse files Browse the repository at this point in the history
No more `serve`!
  • Loading branch information
arctic-hen7 committed Dec 30, 2021
1 parent dccd25e commit 8274678
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 11 deletions.
2 changes: 2 additions & 0 deletions packages/perseus-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ serde = "1"
serde_json = "1"
clap = { version = "=3.0.0-beta.5", features = ["color"] }
fs_extra = "1"
tokio = { version = "1", features = [ "macros", "rt-multi-thread" ] }
warp = "0.3"

[lib]
name = "perseus_cli"
Expand Down
24 changes: 17 additions & 7 deletions packages/perseus-cli/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,28 @@ use perseus_cli::parse::SnoopSubcommand;
use perseus_cli::{
build, check_env, delete_artifacts, delete_bad_dir, deploy, eject, export, has_ejected,
parse::{Opts, Subcommand},
prepare, serve, tinker,
prepare, serve, serve_exported, tinker,
};
use perseus_cli::{errors::*, snoop_build, snoop_server, snoop_wasm_build};
use std::env;
use std::io::Write;
use std::path::PathBuf;

// All this does is run the program and terminate with the acquired exit code
fn main() {
#[tokio::main]
async fn main() {
// In development, we'll test in the `basic` example
if cfg!(debug_assertions) {
let example_to_test =
env::var("TEST_EXAMPLE").unwrap_or_else(|_| "../../examples/basic".to_string());
env::set_current_dir(example_to_test).unwrap();
}
let exit_code = real_main();
let exit_code = real_main().await;
std::process::exit(exit_code)
}

// This manages error handling and returns a definite exit code to terminate with
fn real_main() -> i32 {
async fn real_main() -> i32 {
// Get the working directory
let dir = env::current_dir();
let dir = match dir {
Expand All @@ -37,7 +38,7 @@ fn real_main() -> i32 {
return 1;
}
};
let res = core(dir.clone());
let res = core(dir.clone()).await;
match res {
// If it worked, we pass the executed command's exit code through
Ok(exit_code) => exit_code,
Expand All @@ -60,7 +61,7 @@ fn real_main() -> i32 {
// This returns the exit code of the executed command, which we should return from the process itself
// This prints warnings using the `writeln!` macro, which allows the parsing of `stdout` in production or a vector in testing
// If at any point a warning can't be printed, the program will panic
fn core(dir: PathBuf) -> Result<i32, Error> {
async fn core(dir: PathBuf) -> Result<i32, Error> {
// Get `stdout` so we can write warnings appropriately
let stdout = &mut std::io::stdout();

Expand Down Expand Up @@ -88,7 +89,16 @@ fn core(dir: PathBuf) -> Result<i32, Error> {
// Delete old build/exportation artifacts
delete_artifacts(dir.clone(), "static")?;
delete_artifacts(dir.clone(), "exported")?;
export(dir, export_opts)?
let exit_code = export(dir.clone(), export_opts.clone())?;
if exit_code != 0 {
return Ok(exit_code);
}
// Start a server for those files if requested
if export_opts.serve {
serve_exported(dir, export_opts.host, export_opts.port).await;
}

0
}
Subcommand::Serve(serve_opts) => {
// Delete old build artifacts if `--no-build` wasn't specified
Expand Down
10 changes: 9 additions & 1 deletion packages/perseus-cli/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,15 @@ fn deploy_full(dir: PathBuf, output: String, integration: Integration) -> Result
/// subcommands.
fn deploy_export(dir: PathBuf, output: String) -> Result<i32, Error> {
// Export the app to `.perseus/exported`, using release mode
let export_exit_code = export(dir.clone(), ExportOpts { release: true })?;
let export_exit_code = export(
dir.clone(),
ExportOpts {
release: true,
serve: false,
host: String::new(),
port: 0,
},
)?;
if export_exit_code != 0 {
return Ok(export_exit_code);
}
Expand Down
7 changes: 5 additions & 2 deletions packages/perseus-cli/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ pub fn export_internal(
vec![&format!(
"{} build --target web {}",
env::var("PERSEUS_WASM_PACK_PATH").unwrap_or_else(|_| "wasm-pack".to_string()),
if is_release { "--release" } else { "" }
if is_release { "--release" } else { "--dev" }
)],
&wb_target,
&wb_spinner,
Expand All @@ -197,8 +197,11 @@ pub fn export_internal(
/// Builds the subcrates to get a directory that we can serve. Returns an exit code.
pub fn export(dir: PathBuf, opts: ExportOpts) -> Result<i32, ExportError> {
let spinners = MultiProgress::new();
// We'll add another not-quite-spinner if we're serving
let num_spinners = if opts.serve { 3 } else { 2 };

let (ep_thread, wb_thread) = export_internal(dir.clone(), &spinners, 2, opts.release)?;
let (ep_thread, wb_thread) =
export_internal(dir.clone(), &spinners, num_spinners, opts.release)?;
let ep_res = ep_thread
.join()
.map_err(|_| ExecutionError::ThreadWaitFailed)??;
Expand Down
2 changes: 2 additions & 0 deletions packages/perseus-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod export;
pub mod parse;
mod prepare;
mod serve;
mod serve_exported;
mod snoop;
mod thread;
mod tinker;
Expand All @@ -55,6 +56,7 @@ pub use eject::{eject, has_ejected};
pub use export::export;
pub use prepare::{check_env, prepare};
pub use serve::serve;
pub use serve_exported::serve_exported;
pub use snoop::{snoop_build, snoop_server, snoop_wasm_build};
pub use tinker::tinker;

Expand Down
9 changes: 8 additions & 1 deletion packages/perseus-cli/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,18 @@ pub struct BuildOpts {
pub release: bool,
}
/// Exports your app to purely static files
#[derive(Parser)]
#[derive(Parser, Clone)]
pub struct ExportOpts {
/// Export for production
#[clap(long)]
pub release: bool,
/// Serve the generated static files locally
#[clap(short, long)]
pub serve: bool,
#[clap(long, default_value = "127.0.0.1")]
pub host: String,
#[clap(long, default_value = "8080")]
pub port: u16,
}
/// Serves your app (set the `$HOST` and `$PORT` environment variables to change the location it's served at)
#[derive(Parser)]
Expand Down
30 changes: 30 additions & 0 deletions packages/perseus-cli/src/serve_exported.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use console::Emoji;
use std::net::SocketAddr;
use std::path::PathBuf;
use warp::Filter;

static SERVING: Emoji<'_, '_> = Emoji("🛰️ ", "");

/// Serves an exported app, assuming it's already been exported.
pub async fn serve_exported(dir: PathBuf, host: String, port: u16) {
let dir = dir.join(".perseus/dist/exported");
// We actually don't have to worry about HTML file extensions at all
let files = warp::any().and(warp::fs::dir(dir));
// Parse `localhost` into `127.0.0.1` (picky Rust `std`)
let host = if host == "localhost" {
"127.0.0.1".to_string()
} else {
host
};
// Parse the host and port into an address
let addr: SocketAddr = format!("{}:{}", host, port).parse().unwrap();
// Notify the user that we're serving their files
println!(
" [3/3] {} Your exported app is now live at <http://{host}:{port}>!",
SERVING,
host = host,
port = port
);

warp::serve(files).run(addr).await
}

0 comments on commit 8274678

Please sign in to comment.