Automatically open a browser window when Dev Server starts (#117)
* Automatically open dev server in system browser * Allow opting out of automatically opening in browser * Update readme with new behavior
This commit is contained in:
parent
a34ffd4249
commit
0731ccb36f
|
@ -49,8 +49,7 @@ new [Tokamak](https://tokamak.dev/) project, while `carton init --template basic
|
|||
currently).
|
||||
|
||||
The `carton dev` command builds your project with the SwiftWasm toolchain and starts an HTTP server
|
||||
that hosts your WebAssembly executable and a corresponding JavaScript entrypoint that loads it. Open
|
||||
[http://127.0.0.1:8080/](http://127.0.0.1:8080/) in your browser to see the app running. You can
|
||||
that hosts your WebAssembly executable and a corresponding JavaScript entrypoint that loads it. The app, reachable at [http://127.0.0.1:8080/](http://127.0.0.1:8080/), will automatically open in your default web browser. You can
|
||||
edit the app source code in your favorite editor and save it, `carton` will immediately rebuild the
|
||||
app and reload all browser tabs that have the app open. You can also pass a `--verbose` flag to
|
||||
keep the build process output available, otherwise stale output is cleaned up from your terminal
|
||||
|
|
|
@ -47,6 +47,9 @@ struct Dev: ParsableCommand {
|
|||
@Option(name: .shortAndLong, help: "Set the HTTP port the app will run on.")
|
||||
var port = 8080
|
||||
|
||||
@Flag(name: .long, help: "Skip automatically opening app in system browser.")
|
||||
var skipAutoOpen = false
|
||||
|
||||
static let configuration = CommandConfiguration(
|
||||
abstract: "Watch the current directory, host the app, rebuild on change."
|
||||
)
|
||||
|
@ -84,6 +87,7 @@ struct Dev: ParsableCommand {
|
|||
// swiftlint:disable:next force_try
|
||||
package: try! toolchain.package.get(),
|
||||
verbose: verbose,
|
||||
skipAutoOpen: skipAutoOpen,
|
||||
terminal,
|
||||
port: port
|
||||
).run()
|
||||
|
|
|
@ -39,6 +39,8 @@ final class Server {
|
|||
private let watcher: Watcher
|
||||
private var builder: ProcessRunner?
|
||||
private let app: Application
|
||||
private let localURL: String
|
||||
private let skipAutoOpen: Bool
|
||||
|
||||
init(
|
||||
builderArguments: [String],
|
||||
|
@ -47,12 +49,16 @@ final class Server {
|
|||
customIndexContent: String?,
|
||||
package: SwiftToolchain.Package,
|
||||
verbose: Bool,
|
||||
skipAutoOpen: Bool,
|
||||
_ terminal: InteractiveWriter,
|
||||
port: Int
|
||||
) throws {
|
||||
watcher = try Watcher(pathsToWatch)
|
||||
|
||||
var env = Environment(name: verbose ? "development" : "production", arguments: ["vapor"])
|
||||
localURL = "http://127.0.0.1:\(port)/"
|
||||
self.skipAutoOpen = skipAutoOpen
|
||||
|
||||
try LoggingSystem.bootstrap(from: &env)
|
||||
app = Application(env)
|
||||
app.configure(
|
||||
|
@ -67,6 +73,8 @@ final class Server {
|
|||
self?.connections.remove($0)
|
||||
}
|
||||
)
|
||||
// Listen to Vapor App lifecycle events
|
||||
app.lifecycle.use(self)
|
||||
|
||||
watcher.publisher
|
||||
.flatMap(maxPublishers: .max(1)) { changes -> AnyPublisher<String, Never> in
|
||||
|
@ -80,11 +88,11 @@ final class Server {
|
|||
return ProcessRunner(builderArguments, terminal)
|
||||
.publisher
|
||||
.handleEvents(receiveCompletion: { [weak self] in
|
||||
guard case .finished = $0 else { return }
|
||||
guard case .finished = $0, let self = self else { return }
|
||||
|
||||
terminal.write("\nBuild completed successfully\n", inColor: .green, bold: false)
|
||||
terminal.logLookup("The app is currently hosted at ", "http://127.0.0.1:\(port)/")
|
||||
self?.connections.forEach { $0.send("reload") }
|
||||
terminal.logLookup("The app is currently hosted at ", self.localURL)
|
||||
self.connections.forEach { $0.send("reload") }
|
||||
})
|
||||
.catch { _ in Empty().eraseToAnyPublisher() }
|
||||
.eraseToAnyPublisher()
|
||||
|
@ -102,3 +110,35 @@ final class Server {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Server: LifecycleHandler {
|
||||
public func didBoot(_ application: Application) throws {
|
||||
guard !skipAutoOpen else { return }
|
||||
openInSystemBrowser(url: localURL)
|
||||
}
|
||||
|
||||
/// Attempts to open the specified URL string in system browser on macOS and Linux.
|
||||
/// - Returns: true if launching command returns successfully.
|
||||
@discardableResult
|
||||
private func openInSystemBrowser(url: String) -> Bool {
|
||||
#if os(macOS)
|
||||
let openCommand = "open"
|
||||
#elseif os(Linux)
|
||||
let openCommand = "xdg-open"
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
let process = Process(
|
||||
arguments: [openCommand, url],
|
||||
outputRedirection: .none,
|
||||
verbose: false,
|
||||
startNewProcessGroup: true
|
||||
)
|
||||
do {
|
||||
try process.launch()
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue