Я пытаюсь настроить шаблон для Kotlin Мультиплатформенного проекта, выполняющего ktor
на бэкэнде и react
на веб-интерфейсе с Kotlin типобезопасной оболочкой от команды jetbrains. Для совместного использования кода между внешним и внутренним интерфейсом мне нужно использовать gradle
build.gradle.kts
:
val kotlin_version: String by project
val ktor_version: String by project
val logback_version: String by project
val annotations_version: String by project
val kotlin_react_version: String by project
val kotlin_react_dom_version: String by project
val kotlin_extensions_version: String by project
val kotlin_css_version: String by project
val kotlin_css_js_version: String by project
val kotlin_styled_version: String by project
val kotlinx_serialization_version: String by project
val kotlinx_html_version: String by project
plugins {
kotlin("multiplatform") version "1.3.61"
kotlin("kapt") version "1.3.61"
kotlin("plugin.serialization") version "1.3.61"
}
apply {
plugin("kotlin-dce-js")
}
group = "com.jaro2gw"
version = "0.0.1"
repositories {
mavenCentral()
mavenLocal()
maven(url = "https://kotlin.bintray.com/kotlin-eap")
maven(url = "https://kotlin.bintray.com/js-externals")
maven(url = "https://kotlin.bintray.com/kotlin-js-wrappers")
maven(url = "https://dl.bintray.com/kotlinx/kotlinx")
jcenter()
}
kotlin {
js("frontend") {
useCommonJs()
nodejs()
browser {
compilations.all {
kotlinOptions {
metaInfo = true
sourceMap = true
sourceMapEmbedSources = "always"
moduleKind = "commonjs"
main = "call"
}
}
}
}
jvm("backend")
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
}
}
val frontendMain by getting {
dependsOn(commonMain)
dependencies {
implementation(kotlin("stdlib-js", kotlin_version))
implementation(kotlinDependency("react", kotlin_react_version))
implementation(kotlinDependency("react-dom", kotlin_react_dom_version))
implementation(kotlinDependency("extensions", kotlin_extensions_version))
implementation(kotlinDependency("css", kotlin_css_version))
implementation(kotlinDependency("css-js", kotlin_css_js_version))
implementation(kotlinDependency("styled", kotlin_styled_version))
implementation(kotlinxDependency("html-js", kotlinx_html_version))
implementation(kotlinxDependency("serialization-runtime-js", kotlinx_serialization_version))
implementation("org.jetbrains:annotations:$annotations_version")
implementation(npm("webpack"))
implementation(npm("webpack-cli"))
implementation(npm("webpack-dev-server"))
implementation(npm("react"))
implementation(npm("react-dom"))
implementation(npm("react-draggable"))
implementation(npm("react-list"))
implementation(npm("react-is"))
implementation(npm("inline-style-prefixer"))
implementation(npm("core-js"))
implementation(npm("styled-components"))
implementation(npm("jquery"))
}
}
val backendMain by getting {
dependsOn(commonMain)
dependencies {
implementation(kotlin("stdlib-jdk8", kotlin_version))
implementation(ktorDependency("server-netty"))
implementation(ktorDependency("server-core"))
implementation(ktorDependency("locations"))
implementation(ktorDependency("server-sessions"))
implementation(ktorDependency("websockets"))
implementation(ktorDependency("gson"))
implementation("ch.qos.logback:logback-classic:$logback_version")
}
}
}
}
fun ktorDependency(name: String, version: String = ktor_version) = "io.ktor:ktor-$name:$version"
fun kotlinDependency(name: String, version: String) = "org.jetbrains:kotlin-$name:$version"
fun kotlinxDependency(name: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$name:$version"
gradle.properties
:
kotlin.code.style=official
kotlin_version=1.3.61
ktor_version=1.3.0
logback_version=1.2.1
kotlin_react_version=16.9.0-pre.90-kotlin-1.3.61
kotlin_react_dom_version=16.9.0-pre.90-kotlin-1.3.61
kotlin_extensions_version=1.0.1-pre.90-kotlin-1.3.61
kotlin_css_version=1.0.0-pre.90-kotlin-1.3.61
kotlin_css_js_version=1.0.0-pre.90-kotlin-1.3.61
kotlin_styled_version=1.0.0-pre.90-kotlin-1.3.61
annotations_version=16.0.2
kotlinx_serialization_version=0.11.1
kotlinx_html_version=0.6.12
Внешний вид структуры проекта как это:
/src
/backendMain (ktor kotlin code)
/commonMain
/kotlin
/model
>User.kt
/frontendMain
/kotlin
>index.kt
/resources
/public
>index.html
/webpack.config.d
>webpack.config.js
User.kt
package model
data class User(val ID: Long, val name: String)
index.kt
import kotlinext.js.require
import kotlinext.js.requireAll
import react.dom.render
import kotlin.browser.document
import model.User
fun main() {
requireAll(require.context("kotlin", true, js("/\\.css$/")))
val user = User(1, "ReactUser")
render(document.getElementById("root")) {
+"Hello, $user!"
}
}
index.html
<!doctype html>
<html lang="en">
<head>
<!-- some meta information, shortcut icon and title -->
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div>Hello</div>
<div id="root"></div>
</body>
</html>
webpack.config.js
:
path = require("path")
config = config || {};
config.devServer = config.devServer || {};
config.devServer = {
"hot": true,
"open": false,
"port": 3000,
contentBase: [
path.resolve(__dirname, "..\\..\\..\\processedResources\\frontend\\main\\public")
]
}
config.devServer.proxy = config.devServer.proxy || {};
config.devServer.proxy = {
"/api": "https://localhost:8080"
}
config.devServer.watchOptions = config.devServer.watchOptions || {};
config.devServer.watchOptions = {
"aggregateTimeout": 5000,
"poll": 1000
};
module.exports = {
entry: {
main: path.resolve(__dirname, "kotlin\\kotlin-fullstack-mpp-frontend.js")
}
}
Бэкэнд работает гладко, однако веб-интерфейсу не удается загрузить сгенерированный файл. js (я думаю?).
Ожидаемая страница html при доступе к localhost:3000
должна выглядеть примерно так:
Hello
Hello, (ID=1, name="ReactUser")!
, но я получаю только первые Hello
I думаю, что проблема с автоматически сгенерированным webpack.config.js
. Я немного искал inte rnet и обнаружил, что вы можете включить свой собственный файл webpack.config.js
в проект. Мне удалось установить contentBase
, proxy
и другие параметры, но, похоже, не удалось правильно настроить параметр entry.main
? Я думаю, что структура проекта также может играть здесь роль. Структура папок build
выглядит следующим образом:
/build
/js
/node_modules (project dependencies)
/packages
/kotlin-fullstack-mpp-frontend
/kotlin
/kotlin-fullstack-mpp-frontend (compiled common code)
>kotlin-fullstack-mpp-frontend.js (compiled frontend code)
/node-modules (not sure what is here)
>package.json
>webpack.config.js
/packages_imported (kotlin wrapper for react)
>package.json
>yarn.lock
/processedResources
/frontend
/main
/public
>index.html
/reports
/webpack
/kotlin-fullstack-mpp-frontend
>webpack.config.evaluated.js
Для создания и запуска приложения реагирования я использую gradlew frontendBrowserRun -t
Весь проект доступен здесь: https://github.com/jaro2gw/kotlin-fullstack-mpp