Hi there, I've been working on building libraries ...
# gradle
m
Hi there, I've been working on building libraries and getting to providing/using them via implementation() calls; however in this final case the "dependency" is a Kotlin/JS project and I want to serve it using Ktor (Kotlin/Jvm; i.e. this dependency belongs in resources kinda?) Not sure how to use it as that instead of "code" (the library doesn't even show up in the build/ directory so I can't manually copy it even?)
b
You cannot "serve" kjs dependency as it's just a compile-time entity. You'd need to gave a js module that compiles and exports the dependency as a js file
petuska.dev/kamp sounds like a good example if I understand your use-case correctly
The website (client) is also a kjs app and is embedded and served via ktor server
To recap, kjs dependency is not the same as web jar
m
Sorry I'm not that advanced in a sense that I've used web jars before. I'm really coming from PHP - 10 years gap - Some Minecraft - At the moment I'm setting up a TeamCity server (among other things I've not used nor had before); and I am attempting to assemble a docker container to serve my ktor server (serving static files built by another teamcity build) behind nginx. I can really assemble this any-which-way I suppose but I was looking for a clean solution that was maybe directly in the gradle build scripts for pulling the files from an ivy repository (teamcity server); in there I can serve the .klib, the .jar, the .js, etc files; and sticking those directly into the resources (for serving with /static) I'll study that project in a moment I'm a bit adhd in which there's a thousand moving parts I'm attempting to roll forward here simultaneously ^^
b
Have a look at kamp I've linked. It's fully managed by gradle and just running build command produces a fully self-contained server with embedded web client
m
b
Yep
jsMain is client, jvmMain is server
m
Oh I see you put them together in one repository? Another solution I suppose.
Didn't think of the simplicity of a git subproject actually perhaps.
My main issue stems from I'm not as advanced at gradle so I couldn't get a final multiplatform project to build correctly with all my subprojects (of which some built correctly fine as a multiplatform library). I additionally wanted the common code I share between 'jsMain' and 'jvmMain' to be in its own libraries to be importable into other projects anyway (I have multiple frontends and backends) so I decided to go with my naivety and split the projects up since that also seemed easier anyway.
b
Nothing stops you from doing that in monorepo
m
Also clicking build on such a final multiplatform project is like ~4 minutes for me oof.
(for hello world)
b
Same project, but modular structure for client/server https://github.com/mpetuska/kamp
Also clicking build on such a final multiplatform project is like ~4 minutes for me oof. Don't click build then, use proper gradle commands for the modules that you actually want to build
i.e. instead of doing "gradlew build" to build all modules, do "gradlew clientbuild" to only build the "client" module
Gradle module dependencies are treated almost the same as external maven dependencies in a multi-module project (except that they're built on demand)
m
I suppose. ^^. Again I prefer systems to work with 'defaults' wherever possible. I'm just looking for the best possible way to get there as I don't want to have to convey this information to the next engineer. I appreciate all the options and even if it's not what I want to use it always helps to hear them out (I might use them anyway).
b
Using module dependencies is the "default" approach in the ecosystem tbh. No hassle required to publish unnecessary artefacts. But to each its own.
m
I feel we may have a conflict in terminology or understanding. I may use this solution as it does have its advantages but right now I don't have any common code shared between client a & server a that isn't also shared between client b & server b ... i mean perhaps client b and server b could grab client a/server a's library directly? it just seems weird when they're lopping off the actual front end and back end
b
No issues with that too, you can choose to have all servers in the same monorepo or have only the server that serves your client together with the client code. Common code can then be either ingested as gradle module dependency and also published for other repos or be in it's own repo and published.
m
ultimately i may be pulling from all solutions because it appears industry standards don't work here; this product is entirely unique; down to the physics engine and email distribution 😛
b
Key point here is to have common code module to declare all targets you plan on consuming it from
Your go-to should be to have as much stuff in a gradle multimodule project and only selectively publish some modules for remote repos where you cannot avoid it.
IMHO*
m
I guess this is what you mean by monorepo?
b
Monorepo is a git repo that has multiple projects inside. Gradle multimodule project is more specific version of that specifically focussed on gradle tooling to manage it.
m
Ah ignore monorepo I guess; see I don't want to do that (the multimodule project) for the bulk of my development. I want everything to be broken up as much as possible in small targeted projects which I publish on my repo. So like basically I'm following your advice but flip one word. I selectively publish to remote repos but only for other people. I cannot avoid publishing code in private repositories anymore to make sure I distribute code securely and since I'm doing this all 'privately' and don't want to hit limits of teamcity, dockerhub, etc, anyway... Well it's become a writer's block to also not be able to endlessly publish miniature modules that can then be selectively included across projects... So with the private servers I've opted to publish as much to repositories but I guess that's because I don't view them as remote...
idk if I can expose much of /why/ everything must be in micromodules to the point where 2 products are built from a thousand modules ... that's where I'm nda
b
In that case you can still have your kjs client in a separate repo, but build it into js and publish that as a webjar
Then you can simply add it to your server dependencies and load/serve your kjs app from resources
Simmilar strategy to kamp with an extra step of packaging and publishing js output as a jar
m
I mean like ... with the way my cdn caching is I could just literally link to it from the ivy repository ... like not even in the gradle script just the index {} I serve from ktor would be an actual https:// link.
b
FYI: webjar is just a jar that has only resources (usually js, html and css)
With cdn it would result in redirection. Some might not want that.
m
It's actually all possible behind the same domain with my setup
b
But in general, most people just host kjs apps on cdn as standalone
You don't win much by having your server serve the app anyways since you're not doing ssr/ssg
kamp is actually hosted in both modes kamp.azurewebsites.net is served by ktor, whereas kamp.petuska.dev is hosted as a standalone webapp
I have it served by the ktor server as a fallback in case cdn fails
A bit redundant, i know... 😀
m
um -- well yeah the ktor setup is more just extra steps I could concise this all and just use webpack in the kotlin/js build... but I do plan to do ssg eventually... and even without ssg, ktor is useful since there's lots of apis I plan to build here?
b
I'm not arguing that ktor is not useful. We're discussing how to serve your client here to which I recommend standalone cdn hosting
m
Although for a proper API I plan to have a standalone ktor for that that doesn't even deal with static resources maybe
b
Also you can only build SPAs with kotlin.js for now. If you plan to do ssg, use ktor plus kotlinx.html
m
For now I -- guess I could just make the ktor setup all about the API no serving of content directly
For the content I'll just do nginx rewrites onto the teamcity literally ... since the 'production' build step is to actually do cloudflare pages (this is the dev setup we're talking about; but it needs to be semi-production-like so containers/etc)
well i don't think you directly solved my problem but thanks for talking it solved my problem 🙂
b
Either way you got it resolved 😀
m
you said 'we're just talking about serving your content here' and it refocused me a bit I was like yeah ... ktor isn't going to serve my content period it's cloudflare pages ... why am I making ktor serve it for development purposes?
b
Ah yes, we all get "boxed" in your inital ideas sometimes. Always good to get a second opinion to talk it through even if the other party is spitting out nonsense.
Although we certainly took a long way around the problem now that I read through this 😂
m
still would like to figure out how to copy(..., resources) in gradle ... i mean I think I know it's literally that simple I just want to use gradle's dependency-resolution logic to convert the implementation-style-uri
Copy code
io.ktor:ktor-server-core-jvm:$ktor_version
to actual url to copy from (maybe with a /blah.js to refer specifically to the js file I want; or I've seen other syntax like
Copy code
io.ktor:ktor-server-core-jvm:$ktor_version/ktor-server-core-jvm-$ktor_version.jar!/META-INF/MANIFEST.MF
b
I might be wrong on this, but webjars would be your best option
m
I'll read into them for sure. It's just something about my 'early 2000s enterprise' logic that's making me go web ... jar ... ew who uses those?
b
That or just having a custom gradle task to download the files you need and shove them into resources folder
m
But I'm like Kotlin Ktor Jar Web ... Duh
b
You can even register a second resources folder and put downloaded files there. Then .gitignore it to avoid comitting
Sorry if it's a bit too basic or obvious, just trying to avoid assuming your gradle expertise
m
Just the one-line implementation() so juicy. Maybe there needs to be a gradle plugin lol? I mean maybe I'm underrating my gradle knowledge after generating well over 1000 of the projects just never doing something as mystical as you have with the build.gradle(.kts) so like maybe I'll just go code that randomly here in the next few years out of needing it
We're all unicorns.
b
A plugin to pack a webjar from kjs project sounds very useful!
m
I told Kotlin team about idk a bug... and "remote kotlin development" and got very confused looks in KotlinConf
Now I'm paying for the feature of remote kotlin development and very happy lmao
I've like subtly submitted bug reports on all languages and so far Kotlin has made me feel the most valuable ^.~
I feel it's something of a language barrier I have with the team but it shows they care a ton when they actually fix what I ask them to is what I'm saying. ❤️