Unaisul Hadi
Unaisul Hadi

Reputation: 678

How to enable development mode in embedded server to use auto reload in Ktor?

I'm using Ktor for my back end, I am planning to use auto reload and when I used engine main I've configured development mode in application.conf file. How to do the same in embedded server?

fun main() {
    embeddedServer(Netty, port = 8080 ,watchPaths = listOf("classes","resources")) {
        module()
    }.start(wait = true)
}

Upvotes: 9

Views: 5379

Answers (4)

AlexO
AlexO

Reputation: 1444

If you want to auto-reload the backend classes/resources, you can launch Ktor from your IDE like this:

fun main() {
    System.setProperty("io.ktor.development", "true")

    embeddedServer(
        Netty,
        port = 8080,
        host = "127.0.0.1",
        watchPaths = listOf(
            "classes",
            "resources"
        )
    ) {
        // ...
    }.start(wait = true)
}

Then from the command line you can run ./gradlew -t :<backend-module>:classes.

However, if you want to auto-reload the frontend in a full stack application, your main methods can be:

fun main() {
    System.setProperty("io.ktor.development", "true")

    val jsFile = Path.of(".").resolve("<frontend-module/build/distributions/frontend-module.js>").toFile()

    embeddedServer(
        Netty,
        port = 8080,
        host = "127.0.0.1"
    ) {
        routing {
            get("/static/frontend-module.js") {
                call.respondFile(jsFile)
            }
        }

        // ...
    }.start(wait = true)
}

Then add the following in the frontend module build.gradle.kts:

val devMode = properties.containsKey("jsWatch")
kotlin {
    js {
        useCommonJs()
        binaries.executable()
        browser {
            val webpackMode =
                if (devMode) { Mode.DEVELOPMENT }
                else { Mode.PRODUCTION }
            commonWebpackConfig {
                mode = webpackMode
            }
        }
    }
}

Then add a file inside the <frontend-module>/webpack.config.d folder, for example called watch.js:

const productionMode = config.mode === "production";
config.watch = ! productionMode;

Then after running the above frontend auto-reload main function from the IDE, you can run the following from the command line: ./gradlew -t :sample-ktor-react-js:build -x test -PjsWatch

Here's a working example: https://github.com/alexoooo/sample-ktor-react

Upvotes: 4

Omkar T
Omkar T

Reputation: 883

For me it worked with this code in application.conf

ktor {
    development = true
    deployment {
        port = 8080
        port = ${?PORT}
    }
    application {
        modules = [ com.myapp.ApplicationKt.module ]
    }
}
jwt {
    domain = "https://jwt-provider-domain/"
    audience = "jwt-audience"
    realm = "ktor sample app"
}

and this is how i checked it

fun Application.module() {
    println("developmentMode: " +this.environment.developmentMode)
   ...

Upvotes: 1

Koch
Koch

Reputation: 594

In intellijIdea, go to Run COnfiguration, add this to VM Options -Dio.ktor.development=false

Upvotes: 1

DustWing
DustWing

Reputation: 11

fun main() {
    embeddedServer(
        Netty, port = 80, host = "0.0.0.0", developmentMode = true, watchPaths = listOf("main")
    ) {
        configureRouting()
        configureSerialization()
    }.start(wait = true)
}

@OptIn(DelicateCoroutinesApi::class)
fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration> embeddedServer(
    factory: ApplicationEngineFactory<TEngine, TConfiguration>,
    port: Int = 80,
    host: String = "0.0.0.0",
    developmentMode: Boolean = false,
    watchPaths: List<String> = listOf(File(".").canonicalPath),
    configure: TConfiguration.() -> Unit = {},
    module: Application.() -> Unit
): TEngine = GlobalScope.embeddedServer(
    factory, port, host, developmentMode, watchPaths, EmptyCoroutineContext, configure, module
)


fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration> CoroutineScope.embeddedServer(
    factory: ApplicationEngineFactory<TEngine, TConfiguration>,
    port: Int = 80,
    host: String = "0.0.0.0",
    developmentMode: Boolean = false,
    watchPaths: List<String> = listOf(File(".").canonicalPath),
    parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
    configure: TConfiguration.() -> Unit = {},
    module: Application.() -> Unit
): TEngine {

    val connectors: Array<EngineConnectorConfig> = arrayOf(EngineConnectorBuilder().apply {
        this.port = port
        this.host = host
    })
    val environment = applicationEngineEnvironment {
        this.parentCoroutineContext = coroutineContext + parentCoroutineContext
        this.log = KtorSimpleLogger("ktor.application")
        this.watchPaths = watchPaths
        this.module(module)
        this.connectors.addAll(connectors)
        this.developmentMode = developmentMode
    }

    return embeddedServer(factory, environment, configure)
}

What I tried and worked is created my own functions to created an embededServer. basically I copied EmbeddedServer.kt logic and exposed developmentMode. If you are using Intellij you need to press the Build button to work, or enable auto build. However i dont think is a good idea because you need a way to update this value for other environments. Thus it should be done by application.conf or from applicationDefaultJvmArgs in gradle.

Edit: Went back and tried latest version for ktor. You can use something like this. Also make sure you have enable auto build or you will have to build each time while server is running.

fun main() {

    embeddedServer(
        Netty,
        environment = applicationEngineEnvironment {
            log = LoggerFactory.getLogger("ktor.application")
            config = HoconApplicationConfig(ConfigFactory.load())
            developmentMode = true
            watchPaths = listOf("class")

            connector {
                port = 8080
                host = "localhost"
            }

            module {
                defaultModule()
            }
        }

    ).start(wait = true)
}

Upvotes: 1

Related Questions