Skip to content

Releases: varabyte/kobweb

v0.20.3

03 Feb 17:50
Compare
Choose a tag to compare

This release includes several miscellaneous bug fixes and features.

This release also updates the Kotlin target to 2.1.10.

kotlin = "2.1.10"

Perhaps the feature most people will be interested in is official support for sibling static and dynamic routes.

There was also a bug fix for the backend for an NPE that should not have been thrown. This was caused by any codebase calling ClassLoader.findResource(...) looking for an optional resource when it does not exist. Your own codebase might not do it, but a library you call might! For example, a user trying to use the SQL library jOOQ experienced this.

Important

Planning to upgrade? Review instructions in the README.

Changes

Frontend

  • Support static routes and dynamic routes living side-by-side.
    • v0.20.0 and before, this was supported unintentionally, and as such, was fragile (and depending on the order that routes got registered).
    • In v0.20.1, I noticed this mistake and forced this setup to fail only to learn users were actually depending on it.
    • So in this version, we now support it correctly, with many tests added to validate the feature is hardened.
  • When navigating to a new page, the page will now snap instantly, instead of smooth scroll from whatever arbitrary position it happened to be on the previous page.
  • Breakpoints can now be combined with pseudo selectors.
    • e.g. in a CssStyle: ((SM..MD) + hover) { ... }.
  • Fix bug with tryRoutingTo that could in a rare case open up infinite tabs in production mode.
  • Added a new utility method for rendering raw HTML, i.e. RawHtml("<div>Example</div>")
    • This method is marked unsafe and you must opt-in to use it.

Backend

  • Fixed bug where calling ClassLoader.findResource(...) on a non-existant resource would crash.

Full Changelog: v0.20.2...v0.20.3

v0.20.2

10 Jan 21:35
Compare
Choose a tag to compare

This release is the same as v0.20.1 but with an emergency fix for code related to routing.

Specifically, the bug would hit users who called tryRoutingTo in their codebase while passing in a URL with query parameters and/or fragments as part of it (and would only show up in an exported production build). See this issue for more details.

Important

Planning to upgrade? Review instructions in the README.

Full Changelog: v0.20.1...v0.20.2

v0.20.1

09 Jan 23:02
Compare
Choose a tag to compare

This is a fairly meaty release with a handful of miscellaneous features addressing different requests made by various users, so it is hard to summarize easily! Please find details in the changes below.

Caution

This release introduced a bug that would hit users who called tryRoutingTo in their codebase passing in a URL with query parameters and/or fragments as part of it (and would only show up in an exported production build). See this issue for more details. Even though this should only affect a minority of users, we recommend using 0.20.2 instead, which is just this release with that bug fixed.

Also, starting with this version, Kobweb will start releasing its artifacts on Maven Central and the Gradle Plugin Portal. More information about this in the Notes section below, but in general, this should open up Kobweb development to people working at companies that might restrict access to random maven repository URLs, which is nice.

Finally, this version of Kobweb updates Compose to 1.7.3 and Ktor to 3.0.3.

Important

Planning to upgrade? Review instructions in the README.

Changes

Frontend

  • Catch-all dynamic routes (README link)
    • e.g. @Page("/a/b/c/...slug") would capture the value "d/e/f" in the URL "/a/b/c/d/e/f"
  • Add modifier support for transition-behavior
  • Add modifier support for color-scheme
  • Add support for passing in the redirect parameter into all the Kobweb HTTP APIs (e.g. window.http.get(redirect = MANUAL))

Silk

  • Add CanvasGl2 which lets you create a Canvas that wraps a WebGL2 context
  • Add ColorMode.systemPreference
    • e.g. in an @InitSilk block: ctx.theme.initialColorMode = ColorMode.systemPreference
  • Add ColorMode.saveToLocalStorage / ColorMode.loadFromLocalStorage convenience methods, which Kobweb sites commonly do to store a user's color mode preferences across multiple browser sessions.
    • Run kobweb create app for an example project that uses these methods.
  • ⚠️ Renamed ColorScheme class to ColorPalette due to naming conflict with the CSS color-scheme property, which could be confusing.
    • Old code should still compile but this may generate deprecation warnings. See the Notes section for more details.

Backend

  • You can now disable backend logging either to file and/or stdout/stderr destinations via the enableFileLogging and enableConsoleLogging properties in the Kobweb server configs
  • API interceptors (README link)
    • Intercept all incoming network requests / outgoing responses, allowing you to mutate / redirect requests and responses.
    • A useful place to set global logic that should run before multiple API routes, redirect legacy APIs to new ones, and add authentication logic for protected routes, for example.
  • Fixed a bug where if you had a resource and folder with the same name, attempting to access the resource would 404
    • e.g. if you registered both "store/product" and "store/product/item", then a Kobweb server would error if you tried to visit "store/product" directly.

Markdown

  • Fixed a markdown cast exception that could occur in a markdown blockquote.

Gradle

  • The Application plugin attempts to configure the Compose Compiler plugin in ways that may improve the site performance / size
    • ⚠️ See the Notes section for more details.
  • New helper utility importCss method.
    • Before: unsafe { raw("@import url(\"somestyle.css\" layer(somestyle)") }
    • After: importCss("somestyle.css", layerName = "sometime")
  • Preparations for publishing Kobweb artifacts to the Gradle Plugin Portal and Maven Central.

Notes

Maven central and the Gradle Portal Plugin

Starting in 0.20.1, Kobweb artifacts are now published to maven central and the Gradle Plugin Portal.

This means, essentially, that you can delete all maven repos from your build scripts that point to "https://us-central1-maven.pkg.dev/varabyte-repos/public" if you'd like.

// root settings.gradle.kts
pluginManagement {
    repositories {
        gradlePluginPortal()
-       maven("https://us-central1-maven.pkg.dev/varabyte-repos/public")
    }
}

// root build.gradle.kts
subprojects {
    repositories {
        mavenCentral()
        google()
-       maven("https://us-central1-maven.pkg.dev/varabyte-repos/public")
    }
}

Snapshots

Occasionally, when people report issues with Kobweb, we may ask them to try using a snapshot version, which will have our latest code. Snapshots, which so far have only lived on the varabyte repository, are now published to an official snapshot maven repository as well ("https://s01.oss.sonatype.org/content/repositories/snapshots/"). If you remove the varabyte repo declarations as recommended earlier, you may wish to drop this code somewhere into your settings.gradle.kts file which will add references to the snapshot repository in their place:

// root settings.gradle.kts

// The following block registers dependencies to enable Kobweb snapshot support. It is safe to delete or comment out
// this block if you never plan to use them.
gradle.settingsEvaluated {
    fun RepositoryHandler.kobwebSnapshots() {
        maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
            mavenContent { 
                includeGroupByRegex("com\\.varabyte\\.kobweb.*")
                mavenContent { snapshotsOnly() }
            }
        }
    }
    pluginManagement.repositories { kobwebSnapshots() }
    dependencyResolutionManagement.repositories { kobwebSnapshots() }
}

Compose Compiler warning

After upgrading to 0.20.1, you may get this warning:

The Kobweb plugin failed to configure the compose compiler plugin. This prevents it from applying settings which may improve the size / performance of your site. To fix this, ensure that the plugin org.jetbrains.kotlin.plugin.compose is loaded at the same level as the Kobweb plugin. For example, if you load the Kobweb plugin in the project root with alias(libs.plugins.kobweb.application) apply false, you should also load the compose plugin there (e.g. with alias(libs.plugins.compose.compiler) apply false). To disable Kobweb's configuration of the compose compiler plugin, add kobweb.configureComposeCompiler=false to your project's gradle.properties file.

This warning may look complex, but in general, it just means you should make sure to always apply the compose compiler plugin at the same time you apply the Kobweb plugin. Most projects probably do this already, but yours may not if you declare your kobweb dependency in the root build script but only declare the compose compiler dependency in the site build script.

Here's an example fix (taken from the kobweb create examples/chat template, which gave us this warning when we upgraded it to 0.20.1):

// root build.gradle.kts
plugins {
   alias(libs.plugins.kotlin.multiplatform) apply false
+  alias(libs.plugins.compose.compiler) apply false
   alias(libs.plugins.kobweb.application) apply false
   alias(libs.plugins.kobweb.library) apply false
   alias(libs.plugins.kobwebx.markdown) apply false
}

ColorScheme to ColorPalette migration

You may get some compile warnings when upgrading to 0.20.1. Fixing them is trivial!

Here's an example of how to migrate such code:

val ctx = rememberPageContext()
   Button(
      onClick = { /* ... */ }, 
-     colorScheme = ColorSchemes.Blue
+     colorPalette = ColorPalettes.Blue
   ) {
      Text("Click me!")
   }

Thanks!

We had lots of new interest in Kobweb over the Christmas break. We appreciate folks choosing to spend some of their vacation time to experiment with our software! If you ever create a live website using Kobweb, be sure to inform us via one of the channels mentioned in the README's Connecting With Us section, and we'd love to boost its signal.


Full Changelog: v0.20.0...v0.20.1

v0.20.0

29 Nov 16:52
Compare
Choose a tag to compare

This release is nearly identical to 0.19.3 (with minor changes discussed below) but enables support for Kotlin 2.1.0.

kobweb = "0.20.0"
kotlin = "2.1.0"

Important

Planning to upgrade? Review instructions in the README.


Changes

  • Refactored code behind the scenes resulting in a Compose optimization that reduces site output size by a modest 2-3%
  • Canvas widgets now detect if their lambda block changes upon subsequent recompositions.
    • See notes.

Notes

Canvas lambdas

When I first wrote the canvas widget, I basically expected the render callback passed into it itself to never change over time.

For example, refer to this clock rendering demo. Obviously, each time the render call happens, you'll get a new result (as it is based on the current time), but the callback logic itself is unchanging and self contained.

However, if you wrote a lambda that, for example, captured some values, then that lambda will be recreated each time the method is recomposed. Here, this lambda will be regenerated for each time a new cursor position is passed into the parent function:

fun CanvasWithCursor(cursorX: Int, cursorY: Int) {
   val cursor: CanvasImageSource = remember { initializeCursor() }

   Canvas2d(/*... params ...*/) {
      // canvas lambda captures cursorX and cursorY
      ctx.drawImage(cursor, cursorX.toDouble(), cursorY.toDouble())
   }
}

Previously, the Canvas2d internally remembered the first lambda that was passed in and ignored all subsequent changes.

This is not an issue that perhaps 99.9% of Kobweb users would ever run into -- especially given that this bug has been present for almost three years at this point and was just recently reported -- but I didn't know how else to explain this feature without describing it in this much detail!


Thanks

Thanks to @DennisTsar for doing the early legwork on investigating 2.1.0, including a way to get past a roadblock that would have otherwise significantly delayed the release, as well as for identifying the refactoring that would cut our site size down.


Full Changelog: v0.19.3...v0.20.0

v0.19.3

15 Nov 23:56
Compare
Choose a tag to compare

Some fun miscellaneous items in this one, including breakpoint ranges, Kotlinx serialization support for HTTP verbs, and support for small/large/dynamic viewport units.

Important

Planning to upgrade? Review instructions in the README.

Changes

Frontend

  • Fixed development live reload behavior, which now works even if the tab is not visible when the site is finished rebuilding.
  • HTTP fetch methods now support serialization.
    • See "HTTP verb serialization" notes section for more details.
  • You can now specify breakpoint ranges in CSS styles.
    • For example: (Breakpoint.SM until Breakpoint.LG) { ... } targets tablet and desktop screens (but no wider).
    • The README breakpoints section has been updated with more examples.
  • New Modifier.attr and Modifier.dataAttr attribute modifiers.
    • Modifier.attr("key", "value") is a slightly simpler substittute for Modifier.attrsModifier { attr("key", "value") }
    • Modifier.dataAttr("key", "value") is short for Modifier.attrsModifier { attr("data-key", "value") }
  • Added support for repainting canvases manually.
    • See "Repainting canvases manually" notes section for more details.
  • New CSS units for small / large / dynamic viewport sizes
    • These modern (and relatively recent) units let designers create sites that respond better to mobile devices that have UI elements that hide / show regularly.
    • See this article for examples.
  • Fixed a reported issue where attempting to query AppGlobals in InitSilk and InitKobweb methods would crash.
  • ⚠️ routePrefix has been renamed to basePath
    • You will be warned to update this value in your conf.yaml file.
    • This name is more consistent with what other web frameworks use.
  • Simplified a bunch of APIs that used to take autoPrefix parameters.
    • It is not expected that any user outside of the Kobweb library internally actually used this parameter, but they have been removed. At this point, if you set a basePath value in your conf.yaml file, you should just expect that Kobweb will automatically add it every time.

Backend

  • Updated ktor to v3.0.0
    • And migrated / cleaned up code related to SSE (server-sent events), which is used for live reloading.
  • Fixed an issue with spaces in paths in our start.bat server script.
  • Server start scripts now include the server layout
    • In other words, kobweb export --layout fullstack and kobweb export --layout static generate slightly different scripts.

Build

  • Jetbrains Compose dependency updated to 1.7.1
  • Disable compose trace markers for kobweb modules.
    • This was extra compose code that had no effect for Compose HTML sites, so disabling it should result in some JS file size savings.

Notes

HTTP verb + serialization

The HTTP standard provides a core set of verbs (GET, POST, PUT, etc.) which Kobweb provides Kotlin bindings for. For example:

// `get` returns a ByteArray, which we convert into a string. It is up to us to interpret that further,
// perhaps by parsing it
val unparsedData = window.api.get("/user/123").decodeToString()

With this latest release, if your site depends on kotlinx serialization (setup instructions here) and a kobweb serialization artifact (discussed shortly), you can leverage it to get a fully parsed type.

First, you should add a dependency on the artifact that provides the utility methods:

# libs.versions.toml
[libraries]
kobwebx-serialization-kotlinx = { module = "com.varabyte.kobwebx:kobwebx-serialization-kotlinx", version.ref = "kobweb" }
// site/build.gradle.ktx

// apply kotlinx serialization plugin

jsMain.dependencies {
  // ...
  // add kotlinx serialization dependency
  implementation(libs.kobwebx.serialization.kotlinx)
}

And that point, your project should have access to kotlinx-serialization-aware methods:

@Serializable
class UserDataResponse(val id: String, val name: String, val age: Int)

val userData = window.api.get<UserDataResponse>("/user/123")
check(userData.id == "123")

You can also pass in rich types for the body parameter, if you have one:

@Serializable
class ChangeUserNameRequest(val id: String, val name: String)

@Serializable
class ChangeUserNameResponse(val error: String?)

val response = window.api.put<ChangeUserNameRequest, ChangeUserNameResponse>(
   "/user/change-name", body = ChangeUserNameRequest("123", "Kobweb")
)
if (response.error != null) { /* ... */ }

Repainting canvases manually

Canvases (specifically, Canvas2d and CanvasGl widgets) were designed to repaint continuously, which was honestly inspired by my background in gamedev. However, it is absolutely valid to have a canvas that only paints once and then stops until the user interacts with the canvas, or at least, whose repaint is infrequent and controlled by the developer.

To this end, we introduced the new CanvasRepainter class, which you can optionally pass into a canvas and use it to control when that canvas rerenders:

// Before: Continuously rendering canvas
Canvas2d(width, height, minDeltaMs = ONE_FRAME_MS_60_FPS) {
   /* rendered about every 15ms */
}

// New: Repaint on click
val repainter = remember { CanvasRepainter() }
Canvas2d(width, height, Modifier.onClick { repainter.repaint() }, repainter = repainter) {
   /* rerendered every time the user clicks on this canvas */
}

Here is an example which refills the canvas with a random color every click:

const val WIDTH = 320
const val HEIGHT = 240

// Later...

val repainter = remember { CanvasRepainter() }
Canvas2d(
    WIDTH, HEIGHT,
    Modifier.onClick { repainter.repaint() },
    repainter = repainter
) {
    ctx.fillStyle = Color.rgb(Random.nextInt(255), Random.nextInt(255), Random.nextInt(255))
    ctx.fillRect(0.0, 0.0, WIDTH.toDouble(), HEIGHT.toDouble())
}

If you don't care about repainting at all and just want a canvas that renders something unique once and then never again, you can pass in the REPAINT_CANVAS_MANUALLY value to the minDeltaMs parameter and then just never request a repaint:

Canvas2d(width, height, minDeltaMs = REPAINT_CANVAS_MANUALLY) {
   /* renders exactly once */
}

A note on tryRoutingTo / navigateTo and base paths

If you have RoutePrefix.prepend code anywhere in your project (which is probably very few of you all):

ctx.router.tryRoutingTo(RoutePrefix.prepend("/"))

it is no longer necessary to auto-prepend anything yourself. In this release, tryRoutingTo and navigateTo have been updated to prepend these values for you automatically.

In other words, you can find those calls and simplify your code to:

ctx.router.tryRoutingTo("/")

and it will just work.

Old code will continue to work for now, but if you look at your dev console output, you'll find warnings asking the developer to search your code and fix this issue.

If you have code where you still need to keep the RoutePrefix.prepend call in (because, say, you're interacting with a Compose HTML widget that is not aware of Kobweb base paths), the name has been deprecated and you should change it to BasePath.prepend instead.

Thanks!

  • Thanks to new contributor @ChrisGNZ for reporting and helping us fix the issue with our start.bat script (which broke if the user's Java path had at least one space in it...)

  • Thanks to @dead8309 for their spooky Hacktoberfest contribution, fixing #602 and giving us serialization APIs for HTTP verbs.

  • Thanks to @TheDome0 for their help extending CSS units.

  • And to @DennisTsar for so much of his work, as usual, but with a special callout for the ktor 3.0.0 migration, removing unnecessary trace markers (resulting in smaller sites for everyone), and some work he has done in preparation for Kotlin 2.1.0 (to be supported in a future release)


Full Changelog: v0.19.2...v0.19.3

v0.19.2

19 Sep 23:47
Compare
Choose a tag to compare

This release is nearly identical to v0.19.1 but contains a fix for a logic error introduced there that affected scrolling to fragments on the same page.

For example, if your project had code like this:

Link("#conclusion", "Click here to jump to the conclusion")

clicking on that link would have no effect.

If you are using v0.19.1, you should consider upgrading to v0.19.2 at your earliest convenience.

Important

Planning to upgrade? Review instructions in the README.


⚠️ Smooth scrolling behavior has changed ⚠️

In addition to our fix, we also removed some opinionated smooth scrolling behavior we used when navigating to fragments that we probably shouldn't have added in the first place.

What this means is, after upgrading to 0.19.2, if you have any pages in your site with internal links, navigation to them will now be instant, snapping immediately to the target element when you click a link. This is the browser's (and many sites') default behavior.

(For example, try clicking around on the section links in the sidebar of this Wikipedia page to see instant navigation in action.)

If you'd like to go back to re-enabling smooth scrolling in your site, we recommend adding this somewhere in your site, for example in your AppEntry.kt file:

@InitSilk
fun enableSiteWideSmoothScrolling(ctx: InitSilkContext) = ctx.stylesheet.apply {
    registerStyle("html") {
        cssRule(CSSMediaQuery.MediaFeature("prefers-reduced-motion", StylePropertyValue("no-preference"))) {
            Modifier.scrollBehavior(ScrollBehavior.Smooth)
        }
    }
}

What the above code does is set the site's scroll behavior to "smooth" unless some accessibility setting has been set on that user's machine indicating they don't want it. This approach is an encouraged best practice for enabling smooth scrolling.


Full Changelog: v0.19.1...v0.19.2

v0.19.1

09 Sep 21:33
Compare
Choose a tag to compare

Warning

This release added a logic bug around navigating to link fragments which was resolved in v0.19.2 (which you are encouraged to update to instead).


This release adds a few miscellaneous features and bumps up the Kotlin target to 2.0.20.

Important

Planning to upgrade? Review instructions in the README.

The biggest feature introduced in this release is callouts.

Note

GitHub also has callouts (they call them Alerts) and this is an example of one them: a note! GitHub also has alerts for tips, cautionary points, warnings, and important messages.

Kobweb includes all the alerts that GitHub exposes plus a few others.

I updated the handful of articles in my blog site to use callouts. If you'd like to see them in action, you can find a few examples of them in this post about fullstack Kobweb for example.

This release also adds markdown support for Callouts. They're as easy to create in Kobweb Markdown as they are in GitHub Markdown.

More information about Callouts and their markdown support can be found in the README.


Changes

Frontend

  • Fixed an issue where working with Modifier.displayIfAtLeast(Breakpoint) and that family of methods would still result in elements flickering when a page first loaded.
  • Tweaked a handful of composable names to be more consistent with the official API Guidelines for Jetpack Compose.
    • For example, deferRender -> Deferred, and a few others.
    • It's not expected that the average user will even notice, but this may result in some deprecation notices for some users.
  • Removed a timer-related hack which was used to scroll to page fragments.
    • At the very least, the code is clean now; at best, there may have been the occasional case where the scroll operation wouldn't work and it should be a lot more robust now.

Silk

Markdown

  • Added support for creating callouts

Gradle

  • Fix a handful of cases in lesser used tasks that were still not configuration cache compatible.

Thanks!

In this release, we'd like to extend our appreciation to @okarmazin, who has been nothing but kind to the project in the Kotlin slack and has been going through the new user experience, filing bugs, and helping us by cleaning up mistakes and gaps in our README. Thank you very much for the support!


Full Changelog: v0.19.0...v0.19.1

v0.19.0

09 Aug 14:53
Compare
Choose a tag to compare

This release is identical to 0.18.3 but enables K2 support for Kobweb. 🎉

Please review the Kobweb K2 migration docs to learn how to migrate any existing projects over.

Important

Planning to upgrade? Review instructions in the README.


For the first time in several releases, we are seeing a decrease in the size of exported binaries. This may even be a more significant drop for projects that can use the new "ES2015" compiler target (see the migration docs for more details).

Note

For my own site, pre-0.19.0, the exported size was 1.12MB. In 0.19.0, it dropped to 1.00MB. And with ES2015, it dropped further to 941K. In total, a 16% drop without any changes to my code. That's pretty nice!

Also with this release, both Kobweb and all Kotlin Gradle plugins from JetBrains are configuration-cache compatible. If enabled for your project, you can experience significant compilation time speed-ups. This is highly encouraged given Kobweb's live-reloading experience.

Thanks!

This change exists thanks to @DennisTsar's efforts.

  • He regularly tested Kobweb against pre-release versions of K2
  • He identified and reported an incremental compilation issue with 2.0.0 (before things went out to our users!)
  • He wrote the migration Gradle task and migration documentation
  • He ensured that Kobweb was configuration-cache compatible by the time K2 came out

For my part, I mostly stayed out of his way, and I poked JB occasionally about the status of our filed bug.

This is a really incredible release, one that will result in memory and performance improvements for almost (or even every?) Kobweb user, and that many people were waiting for. And all the legwork for it happened while I was distracted by other tasks. I am truly grateful.

Of course, thanks as well to the Kotlin team. K2 is shaping up to be quite an excellent iteration on the language.


Full Changelog: v0.18.3...v0.19.0

v0.18.3

06 Aug 20:47
Compare
Choose a tag to compare

This release is a collection of miscellaneous features and bug fixes. Enjoy!

Important

Planning to upgrade? Review instructions in the README.

Changes

Frontend

  • Modifier support for the border-image CSS property.
  • Added additional margin and padding-related CSS logical properties (like more overrides for scrollPadding, marginInline, etc.)
  • Fixed a bug where Modifier.background(color) without any other parameters would ignore the color value.
  • You can now programmatically query all routes in your site using the PageContext
    • e.g. ctx.router.routes.forEach { r -> console.log(r.path) }
  • Add new type-safe API for working with local storage and session storage (Documentation)
  • ⚠️ Legacy route support has been removed.
    • See the Notes section for more information.
  • Fixed some edge cases where underscores really confused route generation logic.
    • ⚠️ Example_Route.kt used to generate example_route and now will generate example-route.

Markdown

  • Fixed issue where putting triple quotes in code blocks would generate code that wouldn't compile.

Backend

  • API endpoints now support dynamic routes
    • e.g. @Api("articles/{article}")
    • Access the value of article in the above case using ctx.params["article"]

Gradle

  • Kobweb should now be compatible with the Gradle configuration cache.
    • Note that the Kotlin plugin itself is not until v2.0. Kobweb should have support for this version soon.

Notes

Legacy Route support removed

If you don't care that much about a bit of Kobweb history, then don't read the rest of this section. Just go into your build.gradle.kts and remove the line:

kobweb {
  app {
    // ↓↓↓↓↓↓↓
    legacyRouteRedirectStrategy.set(DISALLOW) // DELETE ME!
    // ↑↑↑↑↑↑↑
  }
}

Caution

If you have this set to WARN or ALLOW, please read here.

However, if you'd like to learn more about this, read on!

Legacy route history

In the beginning, I wrote some logic to convert a Kotlin @Page filename (Example.kt) into a URL route (/example). My initial algorithm simply lowercased everything, and while I did not realize it at the time, this made the default behavior generate names that did not conform to Google's SEO recommendations, which is to use hyphens to separate words.

In 0.16.0, we updated this! So ExampleRoute.kt would now generate /example-route and not /exampleroute.

This long overdue change which, unfortunately, could break old sites if released directly.

Therefore, we did a bunch of work to intercept routes and handle legacy formats and new formats at the same time. In other words, a site with legacy route support would work if you visited either /examperoute OR /example-route.

However, it was always the plan to remove it sooner than later. It was a lot of ugly code we had to maintain, and the issue wasn't likely to affect that many users. Therefore, we gave users 6 months to migrate any offending cases over.

And that brings us to today! Legacy routes are finally out.

In order to not break compilation, we are leaving the legacyRouteRedirectStrategy property in Gradle for now, but it doesn't do anything anymore (except print out a warning if you've set it). You have 6 months to delete this one-liner from your project...

Thanks!

We had a first time contribution from @FromWau who noticed some misformatted documentation and fixed it. These kinds of cleanups are truly appreciated! Thanks for helping keep Kobweb tidy.

And a serious shoutout to @DennisTsar who did all the hard work to fix my crappy Gradle code in order to make it configuration cache friendly.


Full Changelog: v0.18.2...v0.18.3

v0.18.2

26 Jun 17:42
Compare
Choose a tag to compare

This is a minor release mostly to fix an accidental API ambiguity error we introduced for some users in v0.18.1. We also picked up a few misc. additions along the way.

If v0.18.1 is working fine for you, there is no urgency to upgrade.

Important

Planning to upgrade? Review instructions in the README.

Changes

Frontend

  • Fixed ambiguity error for people calling Modifier.background(color) without any other parameters.
  • Fixed an exception that would get fired if you used a design breakpoint inside a ctx.stylesheet.registerStyle block.
  • Added mixBlendMode modifier

Gradle

  • Refactored our Gradle code more compatible with configuration caching.

Full Changelog: v0.18.1...v0.18.2