feat: add --open to deno serve to open server in browser (#25340)

Change:
Supported --open flag with deno serve -> (deno serve --open
somescript.ts/js).
The action that takes place is openning the browser on the address that
the server is running on.

Signed-off-by: HasanAlrimawi <141642411+HasanAlrimawi@users.noreply.github.com>
This commit is contained in:
HasanAlrimawi 2025-04-29 00:14:44 +03:00 committed by GitHub
parent ad0ebb57ee
commit e028e26b9c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 53 additions and 0 deletions

View file

@ -356,6 +356,7 @@ pub struct ServeFlags {
pub port: u16, pub port: u16,
pub host: String, pub host: String,
pub worker_count: Option<usize>, pub worker_count: Option<usize>,
pub open_site: bool,
} }
impl ServeFlags { impl ServeFlags {
@ -367,6 +368,7 @@ impl ServeFlags {
port, port,
host: host.to_owned(), host: host.to_owned(),
worker_count: None, worker_count: None,
open_site: false,
} }
} }
} }
@ -3086,6 +3088,11 @@ Start a server defined in server.ts, watching for changes and running on port 50
.long("host") .long("host")
.help("The TCP address to serve on, defaulting to 0.0.0.0 (all interfaces)") .help("The TCP address to serve on, defaulting to 0.0.0.0 (all interfaces)")
.value_parser(serve_host_validator), .value_parser(serve_host_validator),
).arg(
Arg::new("open")
.long("open")
.help("Open the browser on the address that the server is running on.")
.action(ArgAction::SetTrue)
) )
.arg( .arg(
parallel_arg("multiple server workers") parallel_arg("multiple server workers")
@ -5285,6 +5292,7 @@ fn serve_parse(
let host = matches let host = matches
.remove_one::<String>("host") .remove_one::<String>("host")
.unwrap_or_else(|| "0.0.0.0".to_owned()); .unwrap_or_else(|| "0.0.0.0".to_owned());
let open_site = matches.remove_one::<bool>("open").unwrap_or(false);
let worker_count = parallel_arg_parse(matches).map(|v| v.get()); let worker_count = parallel_arg_parse(matches).map(|v| v.get());
@ -5331,6 +5339,7 @@ fn serve_parse(
port, port,
host, host,
worker_count, worker_count,
open_site,
}); });
Ok(()) Ok(())

View file

@ -1,5 +1,6 @@
// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2018-2025 the Deno authors. MIT license.
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use deno_core::error::AnyError; use deno_core::error::AnyError;
@ -46,6 +47,12 @@ pub async fn serve(
let worker_factory = let worker_factory =
Arc::new(factory.create_cli_main_worker_factory().await?); Arc::new(factory.create_cli_main_worker_factory().await?);
if serve_flags.open_site {
let url = resolve_serve_url(serve_flags.host, serve_flags.port);
let _ = open::that_detached(url);
}
let hmr = serve_flags let hmr = serve_flags
.watch .watch
.map(|watch_flags| watch_flags.hmr) .map(|watch_flags| watch_flags.hmr)
@ -180,3 +187,40 @@ async fn serve_with_watch(
.await?; .await?;
Ok(0) Ok(0)
} }
fn resolve_serve_url(host: String, port: u16) -> String {
let host = if matches!(host.as_str(), "0.0.0.0" | "::") {
"127.0.0.1".to_string()
} else if std::net::Ipv6Addr::from_str(&host).is_ok() {
format!("[{}]", host)
} else {
host
};
if port == 80 {
format!("http://{host}/")
} else {
format!("http://{host}:{port}/")
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_resolve_serve_url() {
assert_eq!(
resolve_serve_url("localhost".to_string(), 80),
"http://localhost/"
);
assert_eq!(
resolve_serve_url("0.0.0.0".to_string(), 80),
"http://127.0.0.1/"
);
assert_eq!(resolve_serve_url("::".to_string(), 80), "http://127.0.0.1/");
assert_eq!(
resolve_serve_url("::".to_string(), 90),
"http://127.0.0.1:90/"
);
}
}