Skip to content

Releases: varabyte/kobweb

v0.17.0

29 Feb 17:59
Compare
Choose a tag to compare

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.


⚠️ ⚠️ ⚠️ If you see the 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

29 Feb 16:25
Compare
Choose a tag to compare

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)
  • Breakpoint types refactored to be more sensible

    • so you can now do e.g. Modifier.setWidth(Breakpoints.MD)
  • 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
    • These were values you could query JS's window.location property for, but they fit nicely inside PageContext as well for easy access.

Full Changelog: v0.16.2...v0.16.3

v0.16.2

11 Feb 22:05
Compare
Choose a tag to compare

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

09 Feb 17:02
Compare
Choose a tag to compare

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

07 Feb 19:05
Compare
Choose a tag to compare

This release changes the way Kobweb generates multi-word parts of routes (e.g. example-page instead of examplepage).

⚠️ This provides much more standard, cleaner URLs (that are additionally more SEO friendly). This may end up being a little bit of work to some users, but a lot of care went in to make sure old sites will not break. This felt like a significant enough change that we decided to bump up the "major" version number. You can read more about legacy routes here.

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.
  • 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 the configAsKobwebApplication("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

13 Jan 20:02
Compare
Choose a tag to compare

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 using IntersectionObserver. 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(...) }
    • 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
    • More methods for configuring color and style added to the top-level border Modifier
  • 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.

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.compose.example.stuff to com.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

12 Dec 22:34
Compare
Choose a tag to compare

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 from kobweb.export to kobweb.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 example timeout.set(1.minute).
    • The default timeout is 30 seconds.

Backend

  • The ApiContext and InitApiContext 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), and maxSize(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.

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

27 Nov 22:50
Compare
Choose a tag to compare

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

20 Nov 18:26
Compare
Choose a tag to compare

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

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....)

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.
  • 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's build.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

03 Nov 17:05
Compare
Choose a tag to compare

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.