Releases: varabyte/kobweb
v0.17.0
This release is identical to v0.16.3 but has migrated its dependencies to target Compose 1.6.0.
Important
Planning to upgrade? Review instructions in the README.
androidx.collections
error
If after upgrading, you start getting this build error:
> Could not find androidx.collection:collection:1.4.0.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/androidx/collection/collection/1.4.0/collection-1.4.0.pom
- https://maven.pkg.jetbrains.space/public/p/compose/dev/androidx/collection/collection/1.4.0/collection-1.4.0.pom
Required by:
project :site > org.jetbrains.compose.runtime:runtime:1.6.0 > org.jetbrains.compose.runtime:runtime-desktop:1.6.0 > org.jetbrains.compose.collection-internal:collection:1.6.0
make sure you have the google
repository added to your list of project repositories. This requirement changed in 1.6.0!
Before
// build.gradle.kts
repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
maven("https://us-central1-maven.pkg.dev/varabyte-repos/public")
}
After
// build.gradle.kts
repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
// ↓↓↓↓↓
google() // Add me!!!
// ↑↑↑↑↑
maven("https://us-central1-maven.pkg.dev/varabyte-repos/public")
}
Full Changelog: v0.16.3...v0.17.0
v0.16.3
This is a small release with some minor fixes. However, we're cutting it early in preparation for a follow-up release that will be compatible with a newer Compose version.
Important
Planning to upgrade? Review instructions in the README.
-
Fixed an issue with Markdown code generating incorrect output when links contained inline code formatting
- For example, this used to break:
[see `ExampleClass` docs for more information](https://mysite.com/docs/exampleclass)
- For example, this used to break:
-
Breakpoint types refactored to be more sensible
- so you can now do e.g.
Modifier.setWidth(Breakpoints.MD)
- so you can now do e.g.
-
Added new
PageContext
parameters for convenience.- For a URL
https://mysite.com/a/b/c?id=123#fragment
- ctx.origin:
https://mysite.com
- ctx.pathQueryAndFragment:
/a/b/c?id=123#fragment
- ctx.origin:
- These were values you could query JS's
window.location
property for, but they fit nicely insidePageContext
as well for easy access.
- For a URL
Full Changelog: v0.16.2...v0.16.3
v0.16.2
This micro release contains a fix for a critical bug introduced in the v0.16.0 route generation algorithm that may apply to a small subset of users.
You will know if this is you if Kobweb v0.16.0 generates a site that won't start up, with the dev console complaining about an invalid path that doesn't start with a slash.
Important
Planning to upgrade? Review instructions in the README.
Due to the Compose / Kotlin target increase in v0.16.1, if you upgrade from v0.16.0 to this one, ensure that you also update to Compose v1.5.12 and Kotlin v1.9.22.
Who is affected? Specifically, if you use camel casing in your project's package, e.g. com.example.mySite
, then v0.16.0 will break on your site.
// site/build.gradle.kts
plugins { /* ... */ }
group = "com.example.mySite" // <-- Camel casing here breaks in v0.16.0, fixed in v0.16.2+
// ...
Our new route generation algorithm should have only been constrained to the part of the package under the pages
package, e.g. com.example.mySite.pages.exampleRoute
should only have transformed exampleRoute
and not mySite
. Once we transformed the earlier part, however, we ended up generating a weird route that broke logic further down the line. Unfortunately, we missed this in our testing, and apologize for any inconvenience.
Thanks to @TheDome0 for their quick bug report, letting us turn around on this issue quickly.
If you were not affected by this issue, updating is not required but it otherwise harmless.
Full Changelog: v0.16.1...v0.16.2
v0.16.1
This release is identical to v0.16.0 but has migrated its dependencies to target Compose 1.5.12 and Kotlin 1.9.22.
Important
Planning to upgrade? Review instructions in the README.
v0.16.0
This release changes the way Kobweb generates multi-word parts of routes (e.g. example-page
instead of examplepage
).
This release also includes a handful of quality-of-life features and under-the-hood improvements.
Important
Planning to upgrade? Review instructions in the README.
Markdown
- Introduced the new
kobweb.markdown.process
callback which you can set to iterate over all markdown files in your project.- This feature is very useful, for example, if you want to create a listing file that enumerates all your other markdown posts.
- Please see the added README section for more information.
Backend
- You can now add custom headers into your response.
Frontend
- 🚨 Camel-case packages and filenames now generate hyphenated routes!
- This is recommended for SEO, and many users have been using route overrides to do this. Hopefully the defaults are a lot more sensible now.
- You can review Page and Package docs for the latest information.
- Kobweb will still work with old sites, as for now it will intercept links to legacy style routes and handle them automatically. However....
- You should still consider auditing your site and disabling these legacy route redirects. The README provides a simple list of steps to follow to do this.
- We now support declaring Kobweb Server Plugin dependencies in a more Gradle-idiomatic way, using the
dependencies
block.- The README has been updated with a new section
- Added support for the
user-valid
psuedo-class - Updated the kotlinx.html dependency to its recently released 0.11.0 version
Gradle
- Tons of cleanup and tweaking which should make the Kobweb Gradle Plugins play more friendly with things like the Gradle configuration cache. Hopefully this will slightly improve compile times.
KSP
- Fixed our KSP logic so it now properly implements multi-round processing.
- This could matter to you if are writing your own KSP processors that generate Kobweb code.
Worker
- Changed the way to specify a worker name in a Kobweb worker, which is now more consistent with Kobweb applications.
configAsKobwebWorker("workername")
, which is symmetrical to theconfigAsKobwebApplication("appname")
method we all know and love
- If a worker fails to serialize / deserialize its input / output arguments, the dev console now prints out a useful warning message instead of swallowing it quietly.
Thanks to our contributors!! 🎉 🎉 🎉
- @kjeller took on the markdown feature discussed in these release notes. They also helped clean up some badly indented formatting in generated font code.
- @Remblej provided the feedback and the initial code draft for custom headers in backend responses.
We are always grateful to community support. Thanks so much for your help!
Full Changelog: v0.15.4...v0.16.0
v0.15.4
This release introduces Kobweb Workers, a wrapper around the standard web workers technology.
Note
Web workers are a way to create an isolated script that your website can run and communicate with. Web workers run on their own thread, so it's a useful place to put computationally expensive background logic (i.e. stuff that calculates things or manages complicated state and doesn't need to interact with the UI), to avoid affecting the responsiveness and performance of your main site.
Planning to upgrade? Review instructions in the README.
Getting web workers working in vanilla Kotlin/JS can be a bit of a pain (example project here), but if you are writing a Kobweb site, it couldn't be much easier.
You just create a module that applies the Kobweb Worker Gradle plugin and then implement a single interface which provides your worker logic, and Kobweb takes care of the rest. As a bonus, you can also specify rich types for your input and output messages, which we recommend using Kotlinx Serialization to help with:
@Serializable
class CalculatePiInput(val numDigits: Int)
@Serializable
class CalculatePiOutput(val digits: List<Int>)
private fun calculatePi(numDigits: Int): List<Int> { /* ... */ }
internal class CalculatePiWorkerFactory
: WorkerFactory<CalculatePiInput, CalculatePiOutput> {
override fun createStrategy(postOutput: (CalculatePiOutput) -> Unit) =
WorkerStrategy<CalculatePiInput> { input ->
postOutput(calculatePi(input.numDigits))
}
override fun createIOSerializer() = Json.createIOSerializer()
}
and after writing that, a CalculatePiWorker
class will be automatically generated, easy to use in your Kobweb site:
val worker = rememberWorker {
CalculatePiWorker { output -> println("Pi is 3.${output.digits.joinToString("")}") }
}
// Later, say in response to some input being entered or a button being pressed
worker.postInput(31415)
Please check out the official documentation for more details.
Frontend
- Kobweb Worker support 🎉 🎉 🎉
- Refactor non-Compose utility methods and classes out of
compose-html-ext
⚠️ This could cause a bunch of compile warnings in your project. See notes section for more information.⚠️ This might cause an error if you are usingIntersectionObserver.
See notes section for more information.
- Removed "And" from some parameter names for consistency and simplicity.
⚠️ Renamed parameters might cause an error in your project. See notes section for more information.
- A bunch of Modifier additions and improvements
- New
accent-color
Modifier - New
appearance
Modifier - New
caption-side
Modifier - New
clear
Modifier - New
column-rule
Modifier - New top-level
font
Modifier- Font modifiers have existed for a long time, but now you can do this:
Modifier.font { style(...); size(...) }
- Font modifiers have existed for a long time, but now you can do this:
- New top-level
borderRadius
Modifier- Makes it easy to set just the corners you need, e.g.
Modifier.borderRadius { topLeft(5.px) }
- Additional support to make it easy to set elliptical border radii
- Makes it easy to set just the corners you need, e.g.
- More methods for configuring color and style added to the top-level
border
Modifier
- New
- Removed the requirement for the
cssRule
API to start with a space for Descendant selectors- In other words, before:
cssRule(" h1")
, after:cssRule("h1")
- You can leave the space in if you'd like, e.g. for symmetry with
cssRule(">h1")
, but in my opinion, the code reads fine without it.
- In other words, before:
Backend
ApiContext
(the context value passed into@Api
methods) improvements- Now includes all headers sent with the request.
- Added a bunch of connection details to the request (so you can know where the request came from, for example)
Gradle
- Fixed an issue with my logic that could sometimes cause Gradle to issue you a spurious demand to add an explicit dependency on ":kobwebGenSiteIndexTask"
Notes
compose-html-ext
non-Compose bits refactored into browser-ext
We deprecated quite a bit of code as part of a code migration in this release. You may see a warning with this latest version of Kobweb, something that looks like:
We are migrating non-Compose utilities to a new artifact. Please change your imports to use `com.varabyte.kobweb.browser.example.stuff` instead (that is, `compose` → `browser`).
Unfortunately, the sort of migration we're doing here is not one that we could easily provide instructions to the IDE so it could automatically replace old code with new. You'd end up with code like:
import com.varabyte.kobweb.browser.example.stuff
import com.varabyte.kobweb.compose.example.stuff
which replaces your easy to understand deprecation warning with an opaque "ambiguity" warning.
If you run into this, the best recommendation I can give you is to manually change the import statement, changing the "compose" part to "browser". For example, com.varabyte.kobweb.
to compose.example.stuffcom.varabyte.kobweb.browser.example.stuff
.
Rationale for this migration
When we first started working on Kobweb, we needed a place to put utility methods and classes that didn't exist in Compose HTML but wish they did. So we created an artifact that even users who did not use Kobweb could pull into their Compose HTML projects and benefit from.
But we recently realized we could have gone further -- some of these utilities don't depend on Compose! But apply to Kotlin/JS browser projects more generally.
Especially with the introduction of workers (which are modules that don't depend on Compose), we decided to do the migration now.
topAndBottom
to topBottom
, etc.
As we get closer to 1.0, we're reviewing some of our old code and trying to come up with consistent rules. We made the decision that "and" should not be included when it's obvious from context.
So we decided that some of our original naming was a mistake. This can cause compile errors in projects which reference parameter names like topAndBottom
or leftAndRight
directly. If that happens, please rename them.
IntersectionObserver API changes
As part of the browser-ext
migration discussed above, a minor scar was that the IntersectionObserver
class obviously belonged in the non-Compose part, but the API provided by compose-html-ext
did use a nice, rich CSSMargin
type that ultimately requires Compose HTML.
Therefore, we moved the class into browser-ext
but added a new extension constructor in compose-html-ext
. If you happened to be using this constructor, you'll get a compile error. You can fix this by importing the extension constructor (which is implemented as an invoke
operator on the Option
class).
import com.varabyte.kobweb.browser.dom.observers.IntersectionObserver
import com.varabyte.kobweb.compose.dom.observers.invoke // !!! Add this!
// Later
IntersectionObserver(
IntersectionObserver.Options(
rootMargin = margin(leftRight = 10.px) // to allow using `margin`
)
)
You could of course consider doing the following, which sidesteps importing "invoke":
import com.varabyte.kobweb.browser.dom.observers.IntersectionObserver
// Later
IntersectionObserver(
IntersectionObserver.Options(
rootMargin = margin(leftRight = 10.px).toString()
)
)
Thanks!
We had some new contributors in this release.
- @ellet0 helped us fill out some of the CSS gaps in our APIs (most of the new modifiers in this release)! They also improved site process by adding a new PR testing workflow. I really appreciate their interest in Kobweb -- it's clear they have a lot of ideas for improvements.
- @dieter115 suggested APIs for improving our file loading utilities, allowing loading multiple files at once.
Thanks so much for taking your time to help Kobweb be a better project!!
And perhaps more than usual, thanks to @DennisTsar for helping me navigate myself out of countless dead ends for poor approaches I took with the Worker feature.
Full Changelog: v0.15.3...v0.15.4
v0.15.3
This release brings some extra functionality to Kobweb's export feature.
Planning to upgrade? Review instructions in the README.
Export
- The
export
block has moved fromkobweb.export
tokobweb.app.export
, a long overdue migration. - You can now use
kobweb.app.export.filter
to filter some routes out of being exported, which can save a lot of time in case you have some routes that don't need to be cached for SEO purposes. - You can now use
kobweb.app.export.enableTraces
to collect snapshots of your pages' progress which you can use to visualize what was happening when they were being visited at export time. - You can configure the timeout used when exporting by setting the
kobweb.app.export.timeout
property, for exampletimeout.set(1.minute)
.- The default timeout is 30 seconds.
Backend
- The
ApiContext
andInitApiContext
classes now expose a property which tells you if your server is running in dev or prod mode; for example,ctx.env.isDev
.- You can use this information to decide if you should create development versions of services, like a database populated with fake data.
Frontend
- Added convenience
size(width, height)
,minSize(width, height)
, andmaxSize(width, height)
modifiers. - Added new
CSS*NumericValue
types for all relevant CSS units.- Compose HTML provides non-Numeric versions, e.g.
CSSLengthValue
,CSSPercentageValue
, etc.. Kobweb now provides numeric versions, e.g.CSSLengthNumericValue
,CSSPercentageNumericValue
, etc. - Updated all Kobweb APIs to use these new types.
- Read more about this change in the README.
- Compose HTML provides non-Numeric versions, e.g.
Notes
The export
block has moved
The export feature is about as old as features in this framework get. As a result, it's no surprise that the export
block location is outdated!
The new location lives under the app
block (since only application modules should be influencing it):
// site/build.gradle.kts
// Old location
kobweb {
export {
includeSourceMap.set(false)
}
}
// New location
kobweb {
app {
export {
includeSourceMap.set(false)
}
}
}
It's trivial to move, but Gradle / IntelliJ unfortunately doesn't surface deprecation warnings directly (i.e. it would have been nice if the export
name was crossed out in the IDE if in the old location), so instead you will get a warning at export time.
Filtering routes
Here's a quick example where we filter out exporting all admin pages from our site, since those will always require auth anyway and shouldn't be cached for SEO purposes. The filter
scope includes a route
property you can use to test the current route being exported:
// site/build.gradle.kts
kobweb {
app {
export {
filter { !route.startsWith("/admin/") }
}
}
}
Enabling export traces
Let's say you have a page on your site that is taking 10 seconds to export, when all your other pages only take 1. What is happening?
Thanks to a feature provided by Playwright (the framework by Microsoft we use for taking browser snapshots), enabling traces is easy:
// site/build.gradle.kts
kobweb {
app {
export {
enableTraces()
}
}
}
You can look at the docs for enableTraces
to see how to configure it, but by default, when traces are enabled, Kobweb will drop trace.zip
files under your .kobweb/export-traces
folder, one per page exported.
You can then drag and drop those files into the page at https://playwright.dev/docs/trace-viewer to investigate its details.
Between trace snapshots and server logs, you should be able to diagnose what's going on.
Full Changelog: v0.15.2...v0.15.3
v0.15.2
This release is identical to v0.15.1 but has migrated its dependencies to support Compose 1.5.11 and Kotlin 1.9.21.
Planning to upgrade? Review instructions in the README.
v0.15.1
This is a minor release that addresses some technical issues and features which, while important to do, probably won't apply to most users.
Planning to upgrade? Review instructions in the README.
Frontend
- Added support for CSS subgrids
Backend
- Updated class loading logic to better separate dependencies used by the user's code from dependencies used by the backend. This makes the Kobweb backend code a lot more robust and future proof.
- A concrete example can help here. The Kobweb backend uses kotlinx serialization, but as a user, you might also use it in your own site, and perhaps you're using a slightly different version of it. Before, the Kobweb server would just find and use its own copy of the serialization library which it would hand to the user code, which almost always works fine but could potentially result in confusing crashes if any API call you were using was different between the two. Now, the user code will always get to use its own copy of the library.
Markdown
- Fixed an issue with absolute paths in markdown breaking on Windows.
- If your markdown file had a line like
link to [some markdown](https://some.example.site.com/path/to/some/markdown.md)
, that would crash when running on Windows. ("Cross platform" path APIs are fun....)
- If your markdown file had a line like
Gradle
-
The library plugin now generates a
module.json
file for all of its artifacts. This allows the application plugin to detect that an artifact was build by the Kobweb library plugin as well as which version it was built by, in case that matters in the future.- Before, the application plugin would copy over any resources found under a
resources/public
folder in any library into your final site's public resources. That logic has been updated to only copy files from libraries we are sure were built with Kobweb.
- Before, the application plugin would copy over any resources found under a
-
If you are a library author who wants to write code that requires the user add script includes into their site's
<head>
block, you can now specify them yourself in the library'sbuild.gradle.kts
file and they will be included in the user's site automatically.- The user will be notified of this and given a chance to opt-out of auto-including head elements on a per dependency basis.
- See the notes section below for an example.
Notes
Specifying head elements from the library plugin
A concrete example will help here. In v0.0.6 of the Kotlin Bootstrap library, the user is asked to add some code into their build script in order for the library to work.
The author of that library can now do this in their own build script:
kobweb {
library { // <-------------- Note "library" here, instead of "app"
index {
head.add {
script {
src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
}
link {
rel = "stylesheet"
href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
}
link {
rel = "stylesheet"
href = "https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css"
}
}
}
}
}
and with that, they can publish their library, and anyone using Kobweb v0.15.1 or newer will have those head tags automatically added for them.
If a user wanted to opt out of adding these dependencies automatically, they would add the following into their own application build script:
kobweb {
app {
index {
// The name "bootstrap" was reported by the Kobweb application plugin when
// it detected that head elements were being added in the Kotlin Bootstrap artifact.
excludeTagsForDependency("bootstrap")
}
}
}
Full Changelog: v0.15.0...v0.15.1
v0.15.0
This release is identical to v0.14.3 but has migrated its dependencies to support Compose 1.5.10 and Kotlin 1.9.20.
Planning to upgrade? Review instructions in the README.