hilla
hilla copied to clipboard
Allow non-centralized route configuration for client side views
On the server side, you can create your view and define the routing info and related metadata for the view on the view itself as
@Route("some/route")
@PageTitle("my fine page");
There is no need to maintain a separate, global routing configuration.
There should be a similar way for client side routes so you could, instead of defining an explicit router configuration like
const routes = [
{
path: '',
component: 'main-view',
action: async () => { await import ('./views/main/main-view'); },
children: [
{
path: 'master-detail',
component: 'master-detail-view',
action: async () => { await import ('./views/masterdetail/master-detail-view'); }
},
you could do e.g.
@customElement('main-view')
export class MainEndpoint extends LitElement {
@Route("some/route")
@RouteLayout("main-view")
@PageTitle("my fine page");
@customElement('master-detail-view')
export class MasterDetailViewElement extends LitElement {
This would require being able to read annotations at build time to generate the same router configuration as above and make code splitting work. Also the runtime @customElement annotation needs to be read at build time
Potentially related to https://github.com/microsoft/TypeScript/issues/30723
There are at leats to challenges to overcome unless TypeScript would get built-in support for something resembling Java annotations.
- Finding the annotated files. As it stands today with webpack, it only processes files that are reachable through imports from the entry point(s) that is given to it. This means that we would either need to have an explicit reference to
MasterDetailsViewElementand then only pick up its configuration from the decorators, or then we would have a separate filesystem scanning step that generates an entry point for webpack. - While not used in that way in the given example, there isn't anything that prevents you from writing decorators with values that cannot be resolved at compile time. There is for instance nothing that technically prevents you from typing
@PageTitle(window.prompt("What's you title?")). What this means is that our compile-time parser would have to reject definitions that an IDE happily lets you write.
There's also an additional difference between TS decorators and Java annotations that isn't evident from this example but that might require some changes in the design. This is the support for named parameters, i.e. @Route(value="some/route", registerAtStartup = false) as expressed in Java. There are of course ways around this, but it means that the syntax cannot be identical to what we currently have for configuring routes in Java.
I think it is fine that we cannot use the same syntax as in Java as long as you are able to express the same things. It does not really have to be annotations either but doing something like
// route(something, something) // Yeah this is really code even though it is a comment
does not sound right.
For this to make sense, you would not want any references to any of the elements that define @route, the point would be that they can be developed and configured independently of the rest of the application. Thus you would need to scan for the annotations like we scan for Java annotations.