Repository: ktorio/ktor
File: ktor-server/ktor-server-core/jsAndWasmShared/src/io/ktor/server/engine/EmbeddedServer.jsAndWasmShared.kt (Kotlin)

Code before:
            for (module in modules) {
                application.module()
            }
            monitor.raise(ApplicationModulesLoaded, application)
            monitor.raise(ApplicationStarted, application)
        } catch (cause: Throwable) {
            environment.log.error("Failed to start application.", cause)
            serverScope.launch { destroy(application) }
            throw cause
        }

        CoroutineScope(application.coroutineContext).launch {
            engine.resolvedConnectors().forEach {
                val host = escapeHostname(it.host)
                environment.log.info(
                    "Responding at ${it.type.name.lowercase()}://$host:${it.port}"
                )
            }
        }
    }

    public actual fun start(wait: Boolean): EmbeddedServer<TEngine, TConfiguration> {
        addShutdownHook { stop() }
        serverScope.launch { prepareToStart() }
        engine.start(wait)
        return this
    }

    @OptIn(DelicateCoroutinesApi::class)
    public actual suspend fun startSuspend(wait: Boolean): EmbeddedServer<TEngine, TConfiguration> {
        addShutdownHook { serverScope.launch { stopSuspend() } }
        prepareToStart()
        engine.startSuspend(wait)
        return this
    }

    @OptIn(DelicateCoroutinesApi::class)
    public actual fun stop(gracePeriodMillis: Long, timeoutMillis: Long) {
        engine.stop(gracePeriodMillis, timeoutMillis)
        serverScope.launch { destroy(application) }
    }

    public actual suspend fun stopSuspend(gracePeriodMillis: Long, timeoutMillis: Long) {
        engine.stopSuspend(gracePeriodMillis, timeoutMillis)
        destroy(application)
    }

    @OptIn(InternalAPI::class)
    private suspend fun destroy(application: Application) {
        safeRaiseEvent(ApplicationStopping, application)
        try {

Review comment (suggestion):
This is a bit of a problem, because we can't block in JS-land the engine can start before the modules are loaded.  It might make sense to deprecate start for JS in favour of startAsync.

Code after:
            for (module in modules) {
                application.module()
            }
            monitor.raise(ApplicationModulesLoaded, application)
            monitor.raise(ApplicationStarted, application)
        } catch (cause: Throwable) {
            environment.log.error("Failed to start application.", cause)
            serverScope.launch { destroy(application) }
            throw cause
        }

        CoroutineScope(application.coroutineContext).launch {
            engine.resolvedConnectors().forEach {
                val host = escapeHostname(it.host)
                environment.log.info(
                    "Responding at ${it.type.name.lowercase()}://$host:${it.port}"
                )
            }
        }
    }

    @Deprecated(
        "Some platforms may not support blocking. Use startSuspend() instead.",
        replaceWith = ReplaceWith("startSuspend(wait)"),
        level = DeprecationLevel.WARNING
    )
    public actual fun start(wait: Boolean): EmbeddedServer<TEngine, TConfiguration> {
        error("Blocking start() is not available on this platform; use startSuspend() instead")
    }

    @OptIn(DelicateCoroutinesApi::class)
    public actual suspend fun startSuspend(wait: Boolean): EmbeddedServer<TEngine, TConfiguration> {
        addShutdownHook { serverScope.launch { stopSuspend() } }
        prepareToStart()
        engine.startSuspend(wait)
        return this
    }

    @OptIn(DelicateCoroutinesApi::class)
    public actual fun stop(gracePeriodMillis: Long, timeoutMillis: Long) {
        engine.stop(gracePeriodMillis, timeoutMillis)
        serverScope.launch { destroy(application) }
    }

    public actual suspend fun stopSuspend(gracePeriodMillis: Long, timeoutMillis: Long) {
        engine.stopSuspend(gracePeriodMillis, timeoutMillis)
        destroy(application)
    }

    @OptIn(InternalAPI::class)
    private suspend fun destroy(application: Application) {