egil / Htmxor

Supercharges Blazor static server side rendering (SSR) by seamlessly integrating the Htmx.org frontend library.
MIT License
124 stars 13 forks source link

feat: Add HtmxorComponentResult and HtmxorHtmlRenderer #41

Open tanczosm opened 5 months ago

tanczosm commented 5 months ago

This is just a first effort so far, untested but I figured I would draft PR this before getting too deep.

tanczosm commented 5 months ago

HtmlRenderer uses HtmlRootComponent, which is public. I added HtmxorHtmlRenderer and it renders components based on HtmxorRootComponent so I had to change the visibility to public as well.

It now throws the "warning CA1815: HtmxorRootComponent should override Equals" when compiling and the checks all fail, treating that as an error.

egil commented 5 months ago

HtmlRenderer uses HtmlRootComponent, which is public. I added HtmxorHtmlRenderer and it renders components based on HtmxorRootComponent so I had to change the visibility to public as well.

Why is HtmxorHtmlRenderer needed?

tanczosm commented 4 months ago

@egil I believe I can encapsulate most of the functionality of the htmxor renderer with the exception of rendering the App root component markup, which a call to a component renderer would not have awareness of. Since the root component typically wraps a Router component the HtmxorComponentResult has to go another way.

To get closer I think the ideal approach would require passing a root Layout and DefaultLayout to the component result renderer. This would require duplicating the markup inside App.razor though unless App.razor uses a layout itself.

The layout approach where the App root component uses a Layout that can be shared with the HtmxorComponentResult may be the cleanest approach.

app.MapGet("/greeting", () => new HtmxorComponentResult<GreetingComponent>() {
        RootLayout = typeof(AppLayout),  // optional root layout
        DefaultLayout = typeof(MainLayout)  // optional default layout if component doesn't specify a layout via Htmx attributes or @layout
    }
);
egil commented 4 months ago

Isn't supporting the "full page" render path irrelevant in this scenario? Just as with HtmlComponentResult, you use it because you want to render a specific component outside of the normal rendering flow afforded to you by Blazor or Htmxor.

tanczosm commented 4 months ago

Isn't supporting the "full page" render path irrelevant in this scenario? Just as with HtmlComponentResult, you use it because you want to render a specific component outside of the normal rendering flow afforded to you by Blazor or Htmxor.

Most likely so. I'll stick with matching the RazorComponentResult approach.