Gunslingor
08/10/2020, 2:00 PMtarget {
browser {
webpackTask {
outputFileName = "MyProjectName.js"
}
runTask {
dependsOn("build")
devServer = devServer?.copy(
port = 8088,
proxy = mapOf("/api" to "<http://localhost:8080>")
)
}
}
}
Casey Brooks
08/10/2020, 2:41 PMbrowserProductionWebpack
task to generate a static .js
file, bundle that with your server’s resources, and serve it as a static file from Ktor itself. There’s probably a better way to do it, but here’s how I have this set up for my site: https://github.com/cjbrooks12/caseyjbrooks/blob/master/lib/build.gradle.kts#L79-L81 adds /browser.js
to the jar resources, so I can serve the following in my ktor router
routing {
static {
resource("/favicon.ico")
resource("/browser.js")
resource("/browser.js.map")
}
}
Gunslingor
08/10/2020, 2:49 PMCasey Brooks
08/10/2020, 3:02 PMbrowserProductionRun
, the page load time was very long compared to serving the static bundle directly, and I prefer to just recompile everything on changes. But yeah, i don’t think there’s any automatic integration of Ktor with MPP right now to serve the JS bundles through/with Ktor; it’s all manualRobert Jaros
08/10/2020, 3:04 PMbrowserDevelopmentRun
task and the other with run
or jvmRun
(not sure what the name is) to run Ktor backend.Gunslingor
08/10/2020, 3:06 PMRobert Jaros
08/10/2020, 3:07 PMGunslingor
08/10/2020, 3:08 PMtasks {
register<Copy>("prepCopyJsBundleToKtor") {
group = "app"
dependsOn("srcFrontend:build", "srcBackend:build")
mustRunAfter("srcFrontend:build", "srcBackend:build")
from("$buildDir/frontend/distributions/")
include("**/*.*")
into("$buildDir/backend/resources/main/web")
}
register("pipelineFatJarBuild"){
group = "app"
dependsOn("prepCopyJsBundleToKtor", "srcBackend:fatJarBuild")
mustRunAfter("prepCopyJsBundleToKtor", "srcBackend:fatJarBuild")
}
register<JavaExec>("pipelineFatJarRunLocal") {
group = "app"
dependsOn("pipelineFatJarBuild")
mustRunAfter("pipelineFatJarBuild")
classpath = getByPath("srcBackend:fatJarBuild").outputs.files
}
}
Current custom tasks for all (sub)projectsRobert Jaros
08/10/2020, 3:11 PMGunslingor
08/10/2020, 3:12 PMregister<JavaExec>("pipelineDevRunLocal") {
group = "app"
dependsOn("jvmRun", "browserDevelopmentRun")
}
Robert Jaros
08/10/2020, 3:14 PMapplication.conf
I have:
ktor {
deployment {
port = 8080
watch = [build/classes/kotlin/backend/main]
}
}
Gunslingor
08/10/2020, 3:14 PMRobert Jaros
08/10/2020, 3:16 PMGunslingor
08/10/2020, 3:16 PMRobert Jaros
08/10/2020, 3:18 PMGunslingor
08/10/2020, 3:19 PMRobert Jaros
08/10/2020, 3:20 PMGunslingor
08/10/2020, 3:20 PMRobert Jaros
08/10/2020, 5:07 PMGunslingor
08/10/2020, 5:08 PMRobert Jaros
08/10/2020, 5:09 PMGunslingor
08/10/2020, 5:09 PMclass Table {
val table = document.create.div("grid w-100 w-100 h-100") { }
private fun sectionAdd(child: HTMLElement){
val toolbarRow = document.create.div("row").apply {
val toolbarRowCell = document.create.div("cell-12").apply {
appendChild(child)
}
appendChild(toolbarRowCell)
}
table.appendChild(toolbarRow)
}
init {
sectionAdd(TableToolbar().toolbar())
sectionAdd(TableView().view)
sectionAdd(TableToolbar().paginator())
}
}
Robert Jaros
08/10/2020, 5:10 PMCasey Brooks
08/10/2020, 5:10 PMdocument.appendChild { }
Robert Jaros
08/10/2020, 5:10 PMGunslingor
08/10/2020, 5:11 PMimport kotlinx.html.dom.create
import kotlinx.html.js.div
import org.w3c.dom.HTMLElement
import kotlin.browser.document
import kotlin.dom.appendElement
class TableToolbar {
fun toolbar(): HTMLElement {
return document.create.div("grid") {
div("row") {
div("cell-md-8 table-search-wrapper")
div("cell-md-4 table-rows-wrapper")
}
}
}
fun paginator(): HTMLElement {
return document.create.div("grid") {
div("row") {
p("cell-md-12 table-info-wrapper ")
}
div("row") {
div("cell-md-12 table-pagination-wrapper")
}
}
}
}
Robert Jaros
08/10/2020, 5:12 PMGunslingor
08/10/2020, 5:12 PMRobert Jaros
08/10/2020, 5:12 PMGunslingor
08/10/2020, 5:12 PMRobert Jaros
08/10/2020, 5:14 PMkotlinx.html
so I wont tell you :-)Gunslingor
08/10/2020, 5:14 PMRobert Jaros
08/10/2020, 5:14 PMGunslingor
08/10/2020, 5:15 PMRobert Jaros
08/10/2020, 5:18 PMCasey Brooks
08/10/2020, 5:18 PMTagConsumer<*>
as the receiver, and then you can call your custom functions inside each other
fun render() {
document.append {
div("main") {
parent {
child()
child()
child()
child()
}
}
}
}
inline fun TagConsumer<*>.parent(crossinline block: ()->Unit) {
div("parent") {
block()
}
}
fun TagConsumer<*>.child() {
div("child"){}
}
Gunslingor
08/10/2020, 5:22 PMCasey Brooks
08/10/2020, 5:55 PMTagConsumer
is the base interface that kotlinx.html DSL functions are based on. When it is the receiver, it allows you to call any kotlinx.html functions you want, instead of having to dump everything into a single huge function or use selectors for each smaller chunk. Here’s some documentation on it (though it’s not great) https://github.com/Kotlin/kotlinx.html/wiki/Micro-templating-and-DSL-customizingGunslingor
08/10/2020, 6:11 PMfun DIV.paginator(block : DIV.() -> Unit)
Casey Brooks
08/10/2020, 7:17 PMblock
lambda, but for, say, a layout function, you’d accept a block and call it in the proper nested place of that layout. The block
lambda itself should have a receiver of the tag type where it is called, but it’s usually easier to define the function as inline
so the receiver is more-or-less implicitGunslingor
08/10/2020, 7:26 PMCasey Brooks
08/10/2020, 7:29 PMGunslingor
08/10/2020, 7:32 PMCasey Brooks
08/10/2020, 7:34 PMbrowserProductionWebpack
building and serving a static file, bundles are actually quite small. Not tiny, by any means, but definitely small enough to have reasonable load times nowGunslingor
08/10/2020, 7:39 PMCasey Brooks
08/10/2020, 7:47 PMGunslingor
08/10/2020, 8:24 PMRobert Jaros
08/10/2020, 8:38 PMGunslingor
08/10/2020, 8:40 PMfun DIV.projectionControlsStyles() {
CSSBuilder().apply {
".toolbar-absolute" {
position = Position.absolute
margin = "10px 20px 10px 20px"
padding = "10px 10px 10px 10px"
border = "1px solid rgba(0, 0, 0, 0.1)"
width = LinearDimension.maxContent
}
}
}
Casey Brooks
08/10/2020, 9:49 PMGunslingor
08/10/2020, 10:01 PMclass Projection {
val projection = document.create.div("w-100 h-100 p-0") {
projectionControlsView()
}
init {
val projectionView = ProjectionView()
projection.appendChild(projectionView.renderer.domElement)
projection.appendChild(projectionControlsViewStyles)
ProjectionController(projectionView)
}
//TODO: Bug - 3d canvas seems to disappear when window is tool small (F12)
}
Works, clean enough...