Rafael Tonholo
01/14/2025, 11:16 PM/{lang}/article/{article_id}
, which works fine until 0.20.0
, but I couldn't update further. I could reproduce the issue on both 0.20.1
and 0.20.2
.
Looking into the dev tools, I see the following exception:
IllegalStateException {
"cause": undefined,
"message": "User attempted to register a dynamic route that conflicts with one or more routes already set up. \"{lang}\" is being registered but [\"\", \"about\", \"articles\", \"project\", \"resume\"] route(s) already exist.",
"name": "IllegalStateException",
"stack": "IllegalStateException: User attempted to register a dynamic route that conflicts with one or more routes already set up. \"{lang}\" is being registered but [\"\", \"about\", \"articles\", \"project\", \"resume\"] route(s) already exist.\n at RootNode.createChild_922k2c_k$ (webpack-internal:///./kotlin/kobweb-common-client-server-internal.mjs:258:118)\n at RouteTree.register_q504rs_k$ (webpack-internal:///./kotlin/kobweb-common-client-server-internal.mjs:514:22)\n at Router.register_vkebx7_k$ (webpack-internal:///./kotlin/kobweb-frontend-kobweb-core.mjs:1528:25)\n at main$lambda (webpack-internal:///./kotlin/portfolio.mjs:421:30)\n at initKobweb (webpack-internal:///./kotlin/kobweb-frontend-kobweb-core.mjs:564:3)\n at main (webpack-internal:///./kotlin/portfolio.mjs:138:92)\n at mainWrapper (webpack-internal:///./kotlin/portfolio.mjs:593:3)\n at eval (webpack-internal:///./kotlin/portfolio.mjs:19302:1)\n at ./kotlin/portfolio.mjs (<http://localhost:8080/portfolio.js:486:1>)\n at __webpack_require__ (<http://localhost:8080/portfolio.js:520:41>)"
}
It looks like the code that is throwing the issue is this: https://github.com/varabyte/kobweb/blob/8f104e3bed69bf05fead154d57d4d66ec3adadc2/c[…]c/commonMain/kotlin/com/varabyte/kobweb/navigation/RouteTree.kt
I would like to ask if there was a change in how we define the page routes that I might need to create a migration to support the /{lang}/article/{article_id}
route, as it was supported before 0.20.1
. I saw the issue related to the tryRoutingTo
, but I believe it isn't related since the exception also happens on 0.20.2
.
Also, if that is a real issue, I can create a ticket in GitHub, I just want to double-check if I'm not missing anything.David Herman
01/14/2025, 11:18 PMDavid Herman
01/14/2025, 11:19 PMRafael Tonholo
01/14/2025, 11:21 PMDavid Herman
01/14/2025, 11:21 PMDavid Herman
01/14/2025, 11:23 PMDavid Herman
01/14/2025, 11:23 PMDavid Herman
01/14/2025, 11:24 PMDavid Herman
01/14/2025, 11:24 PMDavid Herman
01/14/2025, 11:29 PMDavid Herman
01/14/2025, 11:50 PMRafael Tonholo
01/14/2025, 11:50 PM"/a"
"/b"
"/{else}/x"
where visiting "/a" would go to the first, "/b" would go to the second, and "/c/x" would go to the third?Yes, that is the expected behaviour.
Thinking about it, I can definitely support the case where I allow static pages and dynamic pages at the same level, as long as you'd be OK with the static pages taking precedence over the dynamic ones, if presentYeah, I think that, too, the static routes must get precedence over the dynamics. The only case I would think the dynamic should get precedence over the static is if the dynamic parameter was mapped to some value, and the value matched.
David Herman
01/14/2025, 11:51 PMDavid Herman
01/14/2025, 11:51 PMDavid Herman
01/14/2025, 11:51 PMDavid Herman
01/14/2025, 11:52 PMRafael Tonholo
01/14/2025, 11:52 PM/a
• /b
• /{param}/x
, where param
is c.
So, when you navigate to /c/x
it redirects to the page, and /d/x
redirects to 404. However I don't expected that to be supportedDavid Herman
01/14/2025, 11:52 PMRafael Tonholo
01/14/2025, 11:53 PMThis may have worked before just by chance 🙂That was indeed working before, I have it running on my website, using
0.20.0
hahaDavid Herman
01/14/2025, 11:53 PM{x}
• {else}/x
• {else}/y
Rafael Tonholo
01/14/2025, 11:54 PMDavid Herman
01/14/2025, 11:55 PM'else
, {a}/x`, {b}/y
, {c}/z
, {k}/{j}
....Rafael Tonholo
01/14/2025, 11:55 PM{user_id}
• {user_id}/profile
• {user_id}/messages
David Herman
01/14/2025, 11:55 PMDavid Herman
01/14/2025, 11:56 PMRafael Tonholo
01/14/2025, 11:56 PM{message_id}
• {user_id}/profile
• {user_id}/messages
Rafael Tonholo
01/15/2025, 12:00 AM/abc
should open: /{message_id}
or /{user_id}
?David Herman
01/15/2025, 12:01 AMRafael Tonholo
01/15/2025, 12:01 AM/{user_id}
• /{user_id}/profile
• /{user_id}/messages
is OK, however, the following:
• /{message_id}
• /{user_id}
• /{user_id}/profile
• /{user_id}/messages
isn't.David Herman
01/15/2025, 12:02 AMDavid Herman
01/15/2025, 12:02 AMDavid Herman
01/15/2025, 12:02 AMRafael Tonholo
01/15/2025, 12:03 AMDavid Herman
01/15/2025, 12:57 AMDavid Herman
01/15/2025, 5:12 AMDavid Herman
01/15/2025, 5:14 AMDavid Herman
01/15/2025, 5:16 AMDavid Herman
01/15/2025, 5:17 AMDavid Herman
01/15/2025, 5:24 AMDavid Herman
01/15/2025, 7:13 AMDavid Herman
01/15/2025, 8:30 AMkqr
01/15/2025, 9:26 AMkqr
01/15/2025, 9:27 AMRafael Tonholo
01/15/2025, 3:02 PM/x/y/z
just by using /x
by default if I haven't mapped /x
to be redirected to /x/y/z
.
So, to me, the correct would be /x
to access /{else}
instead of redirecting to /x/y/z
automatically.
> One final weird case, just going to write it down before crashing for the night:
>
> You register:
> • /a/{b}
> • /{a}/b
>
> User visits /a/b. Which page should handle it?
I guess in that scenario, the user should access the first page. As the first part of the url matches with a static first path of a route, it should navigate to it.David Herman
01/15/2025, 5:03 PM/{a}/b
, and then someone else goes ahead and creates a page /a/{b}
without realizing the unexpected havoc they've just created.
In practice, maybe this will be a very rare issue. However, I'm always concerned about cases in codebases where you pull a lever OVER HERE and get a bug that happens OVER THERE as a result due to unexpected coupling.
In short, allowing static AND dynamic route nodes to both live side by side increases flexibility but opens up this really nuanced potential for introducing breakage. Not allowing them and failing fast prevents some site designs but can always be reasoned about cleanly.David Herman
01/15/2025, 5:05 PM/about
• /projects
• /resume
• /lang/{lang}
Rafael Tonholo
01/15/2025, 5:12 PM/lang
as a path cause it doesn't make sense, but I can move the parameter one leve without much trouble. I guess the following declaration works: /path/{lang}/{id}
, right?David Herman
01/15/2025, 5:14 PMRafael Tonholo
01/15/2025, 5:16 PMDavid Herman
01/15/2025, 5:16 PMDavid Herman
01/15/2025, 5:47 PMDavid Herman
01/15/2025, 5:58 PMDavid Herman
01/15/2025, 6:00 PMDavid Herman
01/15/2025, 9:17 PM0.20.3-SNAPSHOT
which now supports a more flexible routing algorithm.
• /x/y
and /{else}
now work as expected: /x/y
-> /x/y
, /x
-> /{else}
• /{a}/{b}
and /{a}/b
and /a/{b}
can all be registered at the same time. /a/b
will match /a/{b}
(whichever route has the earliest static route match in it)
• /{user_id}
, /{user_id}/profile
, and /{user_id}/messages
can all be registered.
Best of all, this should be completely backwards compatible with all existing Kobweb sites. (Always easier to go from stricter to less strict than the other way around...)
@Rafael Tonholo I would love it if you could give this a shot and confirm if it's working on your end or not, if it is not too late (and you haven't already migrated away from your old site organization).Rafael Tonholo
01/15/2025, 9:45 PM"Key [object Object] is missing in the map."
NoSuchElementException: Key [object Object] is missing in the map.
at getOrImplicitDefault (webpack-internal:///./kotlin/kotlin-kotlin-stdlib.mjs:19176:13)
at getValue (webpack-internal:///./kotlin/kotlin-kotlin-stdlib.mjs:19276:10)
at _toModifier (webpack-internal:///./kotlin/kobweb-frontend-silk-foundation.mjs:1936:93)
at toModifier (webpack-internal:///./kotlin/kobweb-frontend-silk-foundation.mjs:1929:14)
at Scaffold (webpack-internal:///./kotlin/portfolio-core.mjs:4191:108)
at HomeContent (webpack-internal:///./kotlin/portfolio.mjs:14261:80)
at HomePage (webpack-internal:///./kotlin/portfolio.mjs:18594:5)
at ComposableSingletons$MainKt$lambda_1$lambda_sdpc0d (webpack-internal:///./kotlin/portfolio.mjs:156:5)
at ComposableLambdaImpl.invoke_z8di7s_k$ (webpack-internal:///./kotlin/compose-multiplatform-core-compose-runtime-runtime.mjs:38737:162)
at eval (webpack-internal:///./kotlin/portfolio.mjs:150:23)
But it is unrelated with the route issue, so I would say the registration worked fineDavid Herman
01/15/2025, 9:47 PMDavid Herman
01/15/2025, 9:47 PMRafael Tonholo
01/15/2025, 9:48 PM