Bolero brings Blazor to F# developers with an easy to use Model-View-Update architecture, HTML combinators, hot reloaded templates, type-safe endpoints, advanced routing and remoting capabilities, and more.
APACHE-2.0 License
Bot releases are hidden (Show)
Published by Tarmil about 4 years ago
#56: Update to Elmish 3.0. Also update the Cmd
module to match Elmish 3's API, adding submodules Cmd.OfAuthorized
and Cmd.OfJS
.
#163 Rework the HTML element reference API and add Blazor component reference:
ElementRefBinder
renamed to HtmlRef
(old name still available but obsolete)attr.bindRef
renamed to attr.ref
(old name still available but obsolete)attr.ref
taking a function removedref.Ref
renamed to ref.Value
let theDiv = HtmlRef() // Used to be: let theDiv = ElementRefBinder()
div [
attr.ref theDiv // Used to be: attr.bindRef theDiv
on.click (fun _ -> doSomethingWith theDiv.Value) // Used to be: doSomethingWith theDiv.Ref
] []
Ref<'Component>
which provides the same capability for Blazor components, using the same attr.ref
:let theComp = Ref<MyComponent>()
comp<MyComponent> [
attr.ref theComp
on.click (fun _ -> doSomethingWith theComp.Value)
] []
#168: Move the module Bolero.Html
to a separate assembly and make all of its functions inline, in order to reduce the downloaded binary size.
#144: When a router is enabled and the user clicks a link that points to a URI not handled by the router, do navigate to this URI.
#166: Ensure that Elmish subscriptions and init commands are not run during server-side prerender.
#174: Change ShouldRender to invoke override instead of base implementation (thanks @dougquidd!)
#175: Do not render Ref until after Child Content (thanks @dougquidd!)
Published by Tarmil over 4 years ago
#135 Inferred router performs URL encoding/decoding on string
-typed parameters.
#151 Accept either a relative or absolute path in custom router's getRoute
.
#155 Add function fragment
to create a Bolero Node
from a Blazor RenderFragment
.
#159 Breaking change: Remove the module Bolero.Json
, and use System.Text.Json together with FSharp.SystemTextJson instead for remoting.
Remoting serialization can be customized by passing an additional argument configureSerialization: JsonSerializerOptions -> unit
to services.AddRemoting()
in both the server-side and client-side startup functions.
Published by Tarmil over 4 years ago
This release upgrades the minimal required version of .NET Core SDK to 3.1.300.
Update dependencies to Blazor 3.2.0.
Add Elmish commands for JavaScript interop:
Cmd.ofJS : IJSRuntime -> string -> obj[] -> ('res -> 'msg) -> (exn -> 'msg) -> Cmd<'msg>
Cmd.performJS : IJSRuntime -> string -> obj[] -> ('res -> 'msg) -> Cmd<'msg>
#127 Add lazyComp*By
family functions based on a key function (as opposed to lazyComp*With
's equality function):
lazyCompBy
: ('model -> 'key)
-> ('model -> Node)
-> 'model -> Node
when 'key : equality
lazyComp2By
: ('model -> 'key)
-> ('model -> Dispatch<'msg> -> Node)
-> 'model -> Dispatch<'msg> -> Node
when 'key : equality
lazyComp3By
: ('model1 * 'model2 -> 'key)
-> ('model1 -> 'model2 -> Dispatch<'msg> -> Node)
-> 'model1 -> 'model2 -> Dispatch<'msg> -> Node
when 'key : equality
#142 Add functions to create Blazor component attributes of certain types for which =>
is not sufficient:
EventCallback<'T>
:
attr.callback : string -> ('T -> unit) -> Attr
attr.async.callback : string -> ('T -> Async<unit>) -> Attr
attr.task.callback : string -> ('T -> Task) -> Attr
RenderFragment
:
attr.fragment : string -> Node -> Attr
RenderFragment<'T>
:
attr.fragmentWith : string -> ('T -> Node) -> Attr
#141 Add injectable Bolero.Server.RazorHost.IBoleroHostConfig
to provide configuration for the server-side Razor host. This is used within the Razor page by calling the extension methods on IHtmlHelper
:
member RenderComponentAsync<'T when 'T :> IComponent> : IBoleroHostConfig -> Task<IHtmlContent>
member RenderBoleroScript : IBoleroHostConfig -> IHtmlContent
and injected using the extension method on IServiceCollection
:
member AddBoleroHost : ?server: bool * ?prerendered: bool * ?devToggle: bool -> IServiceCollection
Published by Tarmil over 4 years ago
bind.*
Published by Tarmil almost 5 years ago
This release upgrades the minimal required version of .NET Core to 3.1.
#95 Add on.async.*
and on.task.*
event handlers that use callbacks returning Async<unit>
and Task
, respectively.
#86 Add attr.aria
to create ARIA accessibility attributes.
#97 Add on.preventDefault
and on.stopPropagation
to prevent the default behavior of an event and to stop its propagation to parent elements, respectively.
#102 BREAKING CHANGE: The API for binders have been changed. The bind
module now contains submodules bind.input
and bind.change
which in turn contain functions for the type of value being bound: string
, int
, int64
, float
, float32
, decimal
, dateTime
and dateTimeOffset
. Additionally, a module bind.withCulture
contains the same submodules with functions taking an additional CultureInfo
as argument to specify the culture to use to parse the value.
#103: Optimization: use Async.StartImmediateAsTask
rather than Async.StartAsTask
internally.
#105: New functions lazyComp
, lazyCompWith
, lazyComp2
, lazyComp2With
, lazyComp3
and lazyComp3With
allow creating components whose view is only updated when the model is actually changed. For users familiar with Fable, they are close equivalents to its lazyView
family of functions.
#106: ProgramComponent.Dispatch
is now public, and can be used for scenarios where Program.withSubscription
is insufficient.
Published by Tarmil almost 5 years ago
#82 Calls to attr.classes
and attr.``class``
are now combined into a single class
attribute.
div [attr.classes ["a"; "b"]; attr.``class`` "c"; attr.classes ["d"]] []
becomes:
<div class="a b c d"></div>
#87 ecomp
now takes an additional list of attributes as first argument.
#89 ProgramComponent
now has the same method ShouldRender : 'model * 'model -> bool
that ElmishComponent
has. The full program is not re-rendered if this returns false after an update. Thanks @laenas!
A new type alias Program<'model, 'msg>
represents the exact type of Elmish programs used by Bolero. It corresponds to Program<ProgramComponent<'model, 'msg>, 'model, 'msg, Node>
.
Published by Tarmil about 5 years ago
#78, #79: Add PageModels. PageModels allow adding a model specific to a page. The new APIs are:
namespace Bolero
type PageModel<'T> = { Model : 'T }
module Router =
val inferWithModel
: makeMessage: ('page -> 'msg)
-> getEndPoint: ('model -> 'page)
-> defaultPageModel: ('page -> unit)
-> Router<'page, 'model, 'msg>
val noModel : PageModel<'T>
val definePageModel : PageModel<'T> -> 'T -> unit
Published by Tarmil about 5 years ago
#73 Removed the server-side module Bolero.Remoting.Server.Remote
with its functions withHttpContext
, authorize
and authorizeWith
.
Instead, a new type IRemoteContext
is provided via dependency injection:
type IRemoteContext =
inherit IHttpContextAccessor // member HttpContext : HttpContext with get, set
member Authorize : ('req -> Async<'resp>) -> ('req -> Async<'resp>)
member AuthorizeWith : seq<IAuthorizeData> -> ('req -> Async<'resp>) -> ('req -> Async<'resp>)
There are also new overloads on IServiceCollection.AddRemoting
that take IRemoteContext -> 'Handler
as argument, so that remote handlers that use authorization don't need to switch to using DI.
#61 Add attr.key
to uniquely identify elements in a list to help the renderer. See the corresponding @key attribute in the Blazor documentation.
#70 Correctly provide the HttpContext
to remote functions when running in server mode.
#71 Add new exception RemoteException of HttpResponseMessage
, which is thrown on the client side when the response code is neither 200 OK (which succeeds) nor 401 Unauthorized (which throws RemoteUnauthorizedException
).
Published by Tarmil over 5 years ago
Published by Tarmil over 5 years ago
NuGet package reorganization:
Bolero.HotReload.Server
is obsolete.Bolero.Server
contains the assemblies Bolero.HotReload.Server.dll
, moved from package Bolero.HotReload.Server
, and Bolero.Server.dll
, moved from package Bolero
.#22 Move the server-side and client-side AddRemoting
extension methods to namespaces Bolero.Remoting.Server
and Bolero.Remoting.Client
, respectively.
#24 Add remoting authentication.
Add F#-friendly extension methods on HttpContext
for authentication:
member AsyncSignIn : name: string
* ?persistsFor: TimeSpan * ?claims: seq<Claim>
* ?properties: AuthenticationProperties * ?authenticationType: string
-> Async<unit>
member AsyncSignOut : ?properties: AuthenticationProperties -> Async<unit>
member TryUsername : unit -> option<string>
member TryIdentity : unit -> option<Identity>
Add module Bolero.Remoting.Server.Remote
with remote function wrappers to get access to the HttpContext
and mark a function as requiring authorization:
module Remote =
val withContext : (HttpContext -> 'req -> Async<'resp>)
-> ('req -> Async<'resp>)
val authorize : (HttpContext -> 'req -> Async<'resp>)
-> ('req -> Async<'resp>)
val authorizeWith : seq<IAuthorizeData>
-> (HttpContext -> 'req -> Async<'resp>)
-> ('req -> Async<'resp>)
#28 Templating: Holes that fill an HTML attribute's value (eg: some-attr="${SomeHole}"
) now have type obj
rather than string
.
Published by Tarmil over 5 years ago
Published by Tarmil over 5 years ago
#13: Add DOM element reference functions.
attr.ref : (ElementRef -> unit) -> Attr
calls the given function with a reference to the element when it is inserted.
attr.bindRef : ElementRefBinder -> Attr
binds the element when it is inserted. The ElementRefBinder
is typically created as a component field using ElementRefBinder()
and used in event handlers through its .ref
property, of type ElementRef
.
type View() =
inherit ElmishComponent<Model, Message>()
let buttonRef = ElementRefBinder()
override this.View model dispatch =
button [
attr.bindRef buttonRef
on.click (fun _ -> someJsCallback(buttonRef.ref))
] [text "Click me!"]
Published by Tarmil over 5 years ago
#10: Router: add full path specification. Documentation
Routers can now use EndPointAttribute
to specify the full shape of the path for a given union case, rather than just a single prefix fragment. These paths can freely mix constant and parameter fragments, and several cases can share a common prefix of one or multiple fragments.
type Page =
| [<EndPoint "/article/{id}">]
Article of id: int
| [<EndPoint "/list/{page}/{*tags}">]
ArticleList of page: int * tags: list<string>
| [<EndPoint "/user/{username}/favorites">]
UserFavorites of username: string
| [<EndPoint "/user/{username}/comments">]
UserComments of username: string
Specifying a single prefix fragment is still supported in a fully compatible way.