kobweb
kobweb copied to clipboard
Use ksp when it supports js(IR)
See also: https://github.com/google/ksp/issues/33
For now, maybe just hack things by parsing "manually" with like a regex or something?
Here's some code that can used as a starting point. Thanks @DVDAndroid for the initial work!
https://github.com/DVDAndroid/kobweb/tree/dvd/ksp
So I finally got a chance to look into this, nearly one year later :)
With the way Kobweb has evolved, it's possible that KSP may not be the approach we want to use after all. Let me document my thoughts here for now and I'll sleep on them.
Background
Currently, codegen works through a Gradle plugin which, when applied, adds a bunch of tasks, including kobwebGenSiteSource (main.kt for frontend), kobwebGenApi (ApisFactoryImpl.kt for backend), kobwebGenSiteIndex (index.html), kobwebExport, and kobwebStart.
The project parsing is handled by the kotlin-compiler-embeddable artifact.
There's also a markdown plugin which adds kobwebxMarkdownConvert, which needs to run before kobwebGenSiteSource, as it may generate files that feed into it as inputs. Currently, this is easy to do because with Gradle, you just register one task as a dependency of another.
If we transition to KSP, the Kobweb application plugin doesn't go away! You still need kobwebStart, etc.
The only tasks that might go away are kobwebGenSiteSource and kobwebGenApi. So now we'd have this weird complicated thing where a Kobweb project needs to both specify a KSP processor AND a gradle plugin, which both need the other active to be effective.
Another wrinkle -- with kobwebGenSiteSource, we output different source based on whether we're targeting debug or release. I don't see a way to control that behavior with KSP very easily. Even if there is a way, we have to make sure we keep the Gradle and KSP logic in sync (since currently Gradle parses a property from the command line and turns that into a build release value).
And finally, we have markdown -> Kotlin (from the markdown plugin), which definitely isn't related to KSP (KSP doesn't care about markdown). So now we'd have some gen source tasks handled by KSP and some by Gradle.
All in all, I'm starting to think that KSP isn't the way forward here. I think it makes a Kobweb project...
- more complicated to understand (what KSP does and what Gradle does may be hard to follow)
- less flexible due to lack of debug / release config control
- more fragile because someone might go into their build.gradle file, remove a KSP dependency they don't understand, and blammo, things just silently stop working.
The only reason I can think that we'd want to use KSP over Gradle is performance. But I'm not sure that the Kotlin parsing we're currently doing is that slow. Maybe I need to time stuff, but unless we're talking about 5-10s slimming down to sub-second, I'm not sure it's worth the complexity!
I'm going to close this for now. I think having the Gradle plugin continue to do the parsing is the easiest path forward.
Otherwise, I'd need to ask users to both apply a Gradle plugin (e.g. com.varabyte.kobweb.library) and a ksp plugin + ksp("com.varabyte.kobweb:processor") dependency.
In the future, if we find out that compile time additions from the Kobweb plugin are prohibitive, then we can revisit this decision.
As an aside, thanks to my notes from the above comment, I did significantly refactor my Gradle code, so that the code parsing / processing step is simultaneously cleaner and it also caches intermediate outputs which means that 1) subsequent task runs which do expensive parsing might not need to happen and 2) doing an export will only run the parsing step once (before, it was running it twice in a row from different tasks. whoops!)
One thing that might make this worth revisiting is KSP probably has better support for resolving values?
Like, if I have
val SomeVariant = SomeStyle.addVariant("...")
and I want to know the fully qualified path of SomeStyle, I believe KSP lets me resolve that (even though it's generally discouraged as an expensive operation)
With the embedded kotlin compiler artifiact, I'm not 100% sure I can do that. So I end up with some checks I can't do at compile time...