From 7f7d3bdcc58410d0627081763dcc35ff5b673440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Wed, 3 Jan 2024 12:58:20 +0100 Subject: [PATCH 01/11] Set version to '0.24-beta' --- version.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.json b/version.json index 6cfe45ba..98010ede 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { - "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.24-alpha", + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", + "version": "0.24-beta", "gitCommitIdShortAutoMinimum": 7, "nuGetPackageVersion": { "semVer": 2.0 From cf61cd8ec2d349703a840100424f6eb99c3b7c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Wed, 3 Jan 2024 14:11:40 +0100 Subject: [PATCH 02/11] Update changelog --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 888127da..8727afa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.24 + +* [#347](https://github.com/fsbolero/Bolero/issues/347) Add Blazor Interactive Render Modes. + + * `IServiceCollection.AddBoleroComponents()` to be called instead of `IServiceCollection.AddBoleroHost()` to use interactive render modes. + When that is used, `boleroScript` will include `blazor.web.js` instead of `blazor.server.js` or `blazor.webassembly.js`. + + * `BoleroRenderModeAttribute` can be used to indicate the render mode of the component it is applied to. + + * Alternately, `Bolero.Server.Html.attr.renderMode` can be used to indicate the render mode of the component it is applied to. + +* [#279](https://github.com/fsbolero/Bolero/issues/279) Re-enable the generation of reference assemblies. + ## 0.23 * [#308](https://github.com/fsbolero/Bolero/issues/308) Add router functions to decide what to do when the URL is invalid. From 9c6579473140de3a2dff24a90ef11610286da289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Wed, 3 Jan 2024 14:28:17 +0100 Subject: [PATCH 03/11] Publish to github nuget on releases too --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c8931a42..3056bc02 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,7 +68,7 @@ jobs: prerelease: runs-on: ubuntu-latest needs: build - if: ${{ github.ref == 'refs/heads/master' }} + if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'releases') }} steps: - name: Setup dotnet uses: actions/setup-dotnet@v1 From 14dec574ff037f988bd1ee521b9182554f113342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Tue, 9 Jan 2024 23:47:29 +0100 Subject: [PATCH 04/11] Remove workaround for Unsafe.AsRef bug in SDK 8.0.100 --- .github/workflows/build.yml | 6 +++--- .github/workflows/publish.yml | 2 +- global.json | 2 +- src/Bolero/Router.fs | 7 ------- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3056bc02..33a62dcd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: '8.0.100' + dotnet-version: '8.0.101' - name: NuGet cache uses: actions/cache@v1 @@ -73,7 +73,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: '8.0.100' + dotnet-version: '8.0.101' - name: Download nupkg uses: actions/download-artifact@v1 @@ -97,7 +97,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: '8.0.100' + dotnet-version: '8.0.101' - name: Prepare run: | diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a3b19c17..2affdb2e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,7 +11,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: '8.0.100' + dotnet-version: '8.0.101' - name: Download nupkg uses: dawidd6/action-download-artifact@v2 diff --git a/global.json b/global.json index 35a65772..c9c781a8 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.100", + "version": "8.0.101", "rollForward": "feature", "allowPrerelease": true } diff --git a/src/Bolero/Router.fs b/src/Bolero/Router.fs index 81ab576b..f7cbcaea 100644 --- a/src/Bolero/Router.fs +++ b/src/Bolero/Router.fs @@ -190,15 +190,8 @@ exception InvalidRouter of kind: InvalidRouterKind with type PageModel<'T> = { Model: 'T } -#if NET8_0 - static let prop = typeof>.GetProperty("Model") - - member internal this.SetModel(value) = - prop.SetValue(this, value) -#else member internal this.SetModel(value) = Unsafe.AsRef<'T>(&this.Model) <- value -#endif [] module private RouterImpl = From a2e27b4908eb26fc31c3b0dd1e7b10f03dcdcd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Thu, 23 May 2024 02:47:51 +0200 Subject: [PATCH 05/11] feat: Program functions for StreamRendering --- src/Bolero/Components.fs | 18 +++++++++++++++--- src/Bolero/Program.fs | 40 ++++++++++++++++++++++++++++++++++++++++ src/Bolero/ProgramRun.fs | 11 ++++++++++- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/Bolero/Components.fs b/src/Bolero/Components.fs index 483fbcc0..9f262063 100644 --- a/src/Bolero/Components.fs +++ b/src/Bolero/Components.fs @@ -194,8 +194,7 @@ and [] with _ -> () // fails if run in prerender ) - override this.OnInitialized() = - base.OnInitialized() + override this.OnInitializedAsync() = let setDispatch d = dispatch <- d program <- @@ -207,12 +206,25 @@ and [] id id (fun _ model dispatch -> setState model dispatch) id id - runProgramLoop <- Program'.runFirstRender this program + + let updateInitState, initModel, loop = Program'.runFirstRender this program + runProgramLoop <- loop setState <- fun model dispatch -> match oldModel with | Some oldModel when this.ShouldRender(oldModel, model) -> this.ForceSetState(model, dispatch) | _ -> () + match this.StreamingInit with + | None -> + Task.CompletedTask + | Some init -> + task { + let! model, cmd = init initModel + updateInitState model cmd + } + + member val internal StreamingInit : ('model -> Task<'model * Cmd<'msg>>) option = None with get, set + member internal this.InitRouter ( r: IRouter<'model, 'msg>, diff --git a/src/Bolero/Program.fs b/src/Bolero/Program.fs index 8c832433..eb4570b7 100644 --- a/src/Bolero/Program.fs +++ b/src/Bolero/Program.fs @@ -23,8 +23,48 @@ module Bolero.Program open System.Reflection +open System.Threading.Tasks open Elmish +/// +/// Create a simple program for a component that uses StreamRendering. +/// +/// The model that is shown initially. +/// Load the model to be stream-rendered. +/// The Elmish update function. +/// The Elmish view function. +let mkSimpleStreamRendering + (initialModel: 'model) + (load: 'model -> Task<'model>) + (update: 'msg -> 'model -> 'model) + (view: 'model -> Dispatch<'msg> -> Node) + : Program<'model, 'msg> = + Program.mkSimple (fun (comp: ProgramComponent<'model, 'msg>) -> + comp.StreamingInit <- Some (fun x -> task { + let! model = load x + return model, Cmd.none + }) + initialModel) + update view + +/// +/// Create a program for a component that uses StreamRendering. +/// +/// The model that is shown initially. +/// Load the model to be stream-rendered. +/// The Elmish update function. +/// The Elmish view function. +let mkStreamRendering + (initialModel: 'model) + (load: 'model -> Task<'model * Cmd<'msg>>) + (update: 'msg -> 'model -> 'model * Cmd<'msg>) + (view: 'model -> Dispatch<'msg> -> Node) + : Program<'model, 'msg> = + Program.mkProgram (fun (comp: ProgramComponent<'model, 'msg>) -> + comp.StreamingInit <- Some load + initialModel, []) + update view + /// /// Attach `router` to `program` when it is run as the `Program` of a `ProgramComponent`. /// diff --git a/src/Bolero/ProgramRun.fs b/src/Bolero/ProgramRun.fs index cc2c40b0..a84ad7a2 100644 --- a/src/Bolero/ProgramRun.fs +++ b/src/Bolero/ProgramRun.fs @@ -105,8 +105,17 @@ module internal Program' = reentered <- true setState model dispatch - fun () -> + let mutable cmd = cmd + + let updateInitState m cmd' = + setState m dispatch + state <- m + cmd <- cmd @ cmd' + + let run () = cmd |> Cmd.exec (fun ex -> onError ("Error intitializing:", ex)) dispatch activeSubs <- Subs.diff activeSubs sub |> Subs.Fx.change onError dispatch processMsgs () reentered <- false + + updateInitState, model, run From c1163734b642cf2418b47ef49dbf1b5456536438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Thu, 23 May 2024 20:41:22 +0200 Subject: [PATCH 06/11] feat: StreamRenderingComponent for stream rendering SSR --- src/Bolero.Server/Components.fs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Bolero.Server/Components.fs b/src/Bolero.Server/Components.fs index b3f955a4..879208d9 100644 --- a/src/Bolero.Server/Components.fs +++ b/src/Bolero.Server/Components.fs @@ -59,6 +59,30 @@ type BoleroScript() = override this.BuildRenderTree(builder) = builder.AddMarkupContent(0, BoleroHostConfig.Body(this.Config)) +#if NET8_0_OR_GREATER +[] +type StreamRenderingComponent<'model>() = + inherit Component<'model>() + + let mutable model = Unchecked.defaultof<'model> + + abstract InitialModel : 'model + + abstract LoadModel : 'model -> Task<'model> + + abstract Render : 'model -> Node + + override this.OnInitializedAsync() = + model <- this.InitialModel + task { + let! newModel = this.LoadModel(model) + model <- newModel + } + + override this.Render() = + this.Render(model) +#endif + module Rendering = let private emptyContent = Task.FromResult { new IHtmlContent with member _.WriteTo(_, _) = () } From dd82d663d6a6cdc33a1197dde9eb16adb5ac5158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Sun, 4 Aug 2024 11:01:55 +0200 Subject: [PATCH 07/11] test: StreamRendering program and component --- tests/Remoting.Client/Main.fs | 19 ++++++++++++++----- tests/Remoting.Server/Startup.fs | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/tests/Remoting.Client/Main.fs b/tests/Remoting.Client/Main.fs index feb56a23..ad5b8b33 100644 --- a/tests/Remoting.Client/Main.fs +++ b/tests/Remoting.Client/Main.fs @@ -20,13 +20,17 @@ module Bolero.Tests.Remoting.Client +open System open System.Collections.Generic +open System.Threading.Tasks +open Microsoft.AspNetCore.Components open Microsoft.AspNetCore.Components.Authorization open Bolero open Bolero.Html open Bolero.Remoting open Bolero.Remoting.Client open Elmish +open Microsoft.Extensions.Logging type MyApi = { @@ -220,22 +224,27 @@ let Display model dispatch = } } +[] //; BoleroRenderMode(BoleroRenderMode.Server, prerender = false)>] type MyApp() = inherit ProgramComponent() - override this.Program = - let myApi = this.Remote() - Program.mkProgram (fun _ -> InitModel, Cmd.batch [ + let load model = task { + do! Task.Delay 2000 + return { model with currentKey = 42 }, Cmd.batch [ Cmd.ofMsg RefreshItems Cmd.ofMsg GetLogin - ]) (Update myApi) Display + ] + } + + override this.Program = + let myApi = this.Remote() + Program.mkStreamRendering InitModel load (Update myApi) Display |> Program.withRouter router open Microsoft.AspNetCore.Components.WebAssembly.Hosting open Microsoft.Extensions.DependencyInjection open System.Security.Claims -open System.Threading.Tasks type DummyAuthProvider() = inherit AuthenticationStateProvider() diff --git a/tests/Remoting.Server/Startup.fs b/tests/Remoting.Server/Startup.fs index bf5c77c4..ab553cbc 100644 --- a/tests/Remoting.Server/Startup.fs +++ b/tests/Remoting.Server/Startup.fs @@ -22,6 +22,7 @@ namespace Bolero.Tests.Remoting open System open System.Text.Json.Serialization +open System.Threading.Tasks open Bolero.Tests.Remoting.Client open Microsoft.AspNetCore open Microsoft.AspNetCore.Authentication.Cookies @@ -40,6 +41,18 @@ module Page = open Bolero.Html open Bolero.Server.Html + type MyStreamedComponent() = + inherit Components.StreamRenderingComponent() + + override _.InitialModel = "loading..." + + override _.LoadModel(_initialModel) = task { + do! Task.Delay (TimeSpan.FromSeconds 2) + return "loaded!" + } + + override _.Render(model) = div { $"Static stream content {model}" } + let index = doctypeHtml { head { title { "Bolero (remoting)" } @@ -47,7 +60,8 @@ module Page = ``base`` { attr.href "/" } } body { - div { attr.id "main"; comp { attr.renderMode RenderMode.InteractiveAuto } } + div { attr.id "main"; comp { attr.renderMode (InteractiveWebAssemblyRenderMode(prerender = false)) } } + comp script { attr.src "_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js" } boleroScript } From 3ea9dcfc0c712f945a7c2f3f5b52f4e7557b30af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Sun, 17 Nov 2024 10:35:57 +0100 Subject: [PATCH 08/11] fix(ScopedCss): Include generated file even when unchanged --- src/Bolero.Build/Bolero.Build.targets | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Bolero.Build/Bolero.Build.targets b/src/Bolero.Build/Bolero.Build.targets index 2c109ee6..56908d6c 100644 --- a/src/Bolero.Build/Bolero.Build.targets +++ b/src/Bolero.Build/Bolero.Build.targets @@ -15,6 +15,10 @@ <_BoleroApplyCssScopesBeforeTargets>ResolveScopedCssOutputs;CoreCompile + + + + From 3fd4707884ae597213879ff7d7f41b8ecf6bb133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Sun, 17 Nov 2024 11:01:17 +0100 Subject: [PATCH 09/11] fix(ScopedCss): Always run _BoleroComputeCssScope --- src/Bolero.Build/Bolero.Build.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bolero.Build/Bolero.Build.targets b/src/Bolero.Build/Bolero.Build.targets index 56908d6c..72e91704 100644 --- a/src/Bolero.Build/Bolero.Build.targets +++ b/src/Bolero.Build/Bolero.Build.targets @@ -29,7 +29,7 @@ - + From 8235d804862af3a64b1db64c1521299c42042a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Sun, 17 Nov 2024 15:16:07 +0100 Subject: [PATCH 10/11] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8727afa4..9eaab3ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,14 @@ * Alternately, `Bolero.Server.Html.attr.renderMode` can be used to indicate the render mode of the component it is applied to. +* Add `Program.mkStreamRendering` and `Program.mkSimpleStreamRendering` functions. + +* Add `StreamRenderingComponent` base class with members `InitialModel: 'model` and `LoadModel: 'model -> Task<'model>`. + * [#279](https://github.com/fsbolero/Bolero/issues/279) Re-enable the generation of reference assemblies. +* [#355](https://github.com/fsbolero/Bolero/issues/355) Fix CSS isolation on rebuild. + ## 0.23 * [#308](https://github.com/fsbolero/Bolero/issues/308) Add router functions to decide what to do when the URL is invalid. From da0d86ffb442a47f6f70517c7357a583e8437e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Denuzi=C3=A8re?= Date: Sun, 17 Nov 2024 15:45:00 +0100 Subject: [PATCH 11/11] Release v0.24 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 98010ede..6ce6d7ce 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.24-beta", + "version": "0.24", "gitCommitIdShortAutoMinimum": 7, "nuGetPackageVersion": { "semVer": 2.0