Interactive render modes
We are happy to announce the release of Bolero version 0.24. Bolero is a library that enables writing full-stack appications in F#, whose interactivity runs in WebAssembly or on the server side using Blazor.
The main highlights of this release are:
Install the latest project template with:
dotnet new -i Bolero.Templates::0.24.38
Bolero now supports the Interactive render modes which were introduced in Blazor 8.
This is a new way of deciding whether dynamic content should be rendered on the server side or in WebAssembly, incompatible with the existing IBoleroHostConfig
-based method.
The Bolero project template now uses InteractiveWebAssembly mode by default. You can toggle it with the --render
argument:
dotnet new bolero-app --render=InteractiveAuto
dotnet new bolero-app --render=InteractiveServer
dotnet new bolero-app --render=InteractiveWebAssembly
dotnet new bolero-app --render=LegacyServer # "classic" server-side mode
dotnet new bolero-app --render=LegacyWebAssembly # "classic" WebAssembly mode
To switch an existing project to the new mode:
Make sure you are using Bolero HTML for your static content.
Wrap your index
page definition in a component:
[<Route "/{*path}">]
type Page() =
inherit Bolero.Component()
override _.Render() = index
In the server-side dependency injection: replace AddBoleroHost()
with AddBoleroComponents()
.
In the server-side endpoints configuration, replace this:
endpoints.MapDefaultToBolero(index) |> ignore
with:
endpoints.MapRazorComponents<Page>()
// If you use Server or Auto render mode:
.AddInteractiveServerRenderMode()
// If you use WebAssembly or Auto render mode:
.AddInteractiveWebAssemblyRenderMode()
// List here your client assemblies:
.AddAdditionalAssemblies(typeof<MyApp>.Assembly)
|> ignore
On your root dynamic component(s), use one of the following to decide its render mode:
BoleroRenderMode
on the component itself:
// Note: prerender is true if not specified.
[<BoleroRenderMode(BoleroRenderMode.Auto, prerender = false)>]
type MyApp() =
// ...
OR
attr.renderMode
when creating an instance of the component:
open Microsoft.AspNetCore.Components.Web
let index = doctypeHtml {
head { (* ... *) }
body {
// Default (ie with prerender=true):
comp<MyApp> { attr.renderMode RenderMode.InteractiveAuto }
// Custom (here with prerender=false):
comp<MyApp> { attr.renderMode (InteractiveAutoRenderMode(prerender = false)) }
boleroScript
}
}
If neither of these are used, then the render mode will be Static Server (ie no interactive content).
Bolero now supports streaming rendering in two different ways:
Streaming rendering in the Elmish program, using Program.mkStreamRendering
or Program.mkSimpleStreamRendering
:
type Model = { text: string }
[<StreamRendering true>]
type MyApp() =
inherit ProgramComponent<Model, Message>()
override this.Program =
let initModel = { text = "Loading..." }
let load initialModel = task {
let! loadedText = myRemoteApi.getText ()
return { initialModel with text = $"Loaded {loadedText}!" }, Cmd.none
}
Program.mkStreamRendering initModel load update view
Streaming rendering on a (non-Elmish) component by inheriting from StreamRenderingComponent<'model>
:
type Model = { text: string }
type MyStreamedComponent() =
inherit StreamRenderingComponent<Model>()
override _.InitialModel = { text = "Loading..." }
override _.LoadModel(initialModel) = task {
let! loadedText = myRemoteApi.getText ()
return { initialModel with text = $"Loaded {loadedText}!" }, Cmd.none
}
This is not part of Bolero 0.24, but since .NET 9 and F# 9 were recently released, we would like to highlight some improvements that are relevant to Bolero:
Tooling performance has been greatly improved around large and nested computation expressions. This should make the experience of editing HTML-heavy source files much more pleasant.
It is now possible to create empty computation expressions. For example, to create an empty div
element, instead of:
div { attr.empty() }
You can now simply write:
div {}
(On Blazor 9 only) Dependency injection can now be done using constructor arguments, rather than properties with the Inject
attribute.
// Blazor 8:
type MyOldComponent() =
inherit Component()
[<Inject>]
member val JS = Unchecked.defaultof<IJSRuntime> with get, set
override this.Render() =
this.JS.InvokeAsync("console.log", "Hello world!") |> ignore
div { attr.empty() }
// Blazor 9:
type MyNewComponent(js: IJSRuntime) =
inherit Component()
override this.Render() =
js.InvokeAsync("console.log", "Hello world!") |> ignore
div {}
Bolero 0.24 will be the last version of Bolero supporting .NET 6 and .NET 7 (which are already out of support by Microsoft). Starting with Bolero 0.25, .NET 8 will be the minimum supported version.
Happy coding!