- F# 97.5%
- CSS 2%
- Shell 0.4%
|
All checks were successful
Publish dev package / publish (push) Successful in 1m45s
- ./build: NUGET_XMLDOC_MODE=none so first-time restores keep shipped XML (689c). - IsPackable=false on Docs.Server/Docs.Wasm/Benchmark/CSharpComponents; removed 5 upstream GitHub Actions workflows (9400). - Trimmed build.fsx to local-dev orchestration (dev/docs/bindings/ benchmark + version-stamp); dropped the broken `test` + ./build-owned `packages` pipelines (697b). No shipped library code changed. Closes Tasks 019e79ff-689c, 019e7aae-9400, 019e7aae-697b. |
||
|---|---|---|
| .claude | ||
| .config | ||
| .forgejo/workflows | ||
| .vscode | ||
| Benchmark | ||
| Bindings | ||
| data/html-spec | ||
| Docs | ||
| e2e | ||
| Fun.Blazor | ||
| Fun.Blazor.Cli | ||
| Fun.Blazor.CustomElements | ||
| Fun.Blazor.Docs.Server | ||
| Fun.Blazor.Docs.Wasm | ||
| Fun.Blazor.Elmish | ||
| Fun.Blazor.Generator | ||
| Fun.Blazor.HotReload | ||
| Fun.Blazor.HtmlTemplate | ||
| Fun.Blazor.Reactive | ||
| Fun.Blazor.Server | ||
| Fun.Blazor.Tests | ||
| Fun.Blazor.Wasm | ||
| Fun.Htmx | ||
| scripts | ||
| .build-image | ||
| .editorconfig | ||
| .gitignore | ||
| AGENTS.md | ||
| AGENTS.source.md | ||
| build | ||
| build.fsx | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| crawler.fsx | ||
| Directory.Build.props | ||
| docs.fsx | ||
| Fun.Blazor.sln | ||
| global.json | ||
| LICENSE | ||
| nuget.config | ||
| README.md | ||
| THIRD-PARTY-NOTICES.md | ||
| WORK-PLAN.md | ||
Fun.Blazor 
Patched build of slaveOftime/Fun.Blazor distributed via Forgejo. Tracks upstream master with overlay-fork fixes pending upstream merge.
Upstream sources (click through to view on GitHub):
- github.com/slaveOftime/Fun.Blazor — the original library this fork tracks
- github.com/slaveOftime/Fun.Css — the typed CSS library Fun.Blazor depends on
See CHANGELOG.md for the patches included on top of upstream.
This is a project to make F# developer to write blazor easier.
- Use F# ❤️😊 for blazor
- Computation expression (CE) style DSL for internal and third party blazor libraries
- Dependency injection (html.inject)
- Adaptive model (adaptiview/AdaptivieForm) (recommend), elmish model (html.elmish)
- Giraffe style routing (html.route/blazor official style)
- Type safe css style (Fun.Css)
- Convert html to CE style by Fun.Dev.Tools
Check the WASM Docs for more 🚀
Donation
If you find my projects helpful and would like to support my work, consider making a donation via PayPal. Your support is greatly appreciated!
Start to use
dotnet new install Fun.Blazor.Templates::4.1.1
dotnet new fun-blazor -o FunBlazorDemo1
The template is upgraded to dotnet 9, but you can downgrade it according to your needs.
Code samples
// Functional style
let count = cval 0
let counter (str: string) = section {
h2 { "Counter: "; str }
adapt {
let! count, setCount = count.WithSetter()
button {
onclick (fun _ -> setCount (count + 1))
"Increase "; count
}
}
}
// Class style
type CountPage() =
inherit FunComponent()
let mutable count = 0
override _.Render() = main {
h1 { "Counter Page" }
p { "hi here" }
button {
onclick (fun _ -> count <- count + 1)
"Increase "; count
}
counter "functional style"
}
Inline styles: open Fun.Css required
When authoring inline styles via style { ... } or ruleset { ... }, add
open Fun.Css alongside open Fun.Blazor. Many CSS CustomOperations —
color, width, height, backgroundColor, fontSize, borderRadius,
cursorPointer, and similar — live in an [<AutoOpen>] module CssBuilderGenerated inside Fun.Css.dll. F#'s computation-expression
machinery only discovers those extensions when the Fun.Css namespace is
in scope at the consumer site.
open Fun.Blazor
open Fun.Css
let view =
div {
style { color "red"; backgroundColor "ivory"; padding 8 }
"Hello"
}
Without open Fun.Css, F# emits errors like
FS3095: '<op>' is not used correctly. This is a custom operation in this query or computation expression.
or FS0039: The value or constructor '<op>' is not defined.
This is a consequence of the IvanTheGeek Fun.Css fork's generator-based
packaging. Cross-assembly [<assembly: AutoOpen("Fun.Css")>] on Fun.Blazor
was investigated and is non-functional for this purpose — F#'s CE
CustomOperation resolution does not honor type extensions reached only via
cross-assembly auto-open, so consumers must open Fun.Css explicitly.
Local development
You can run dotnet fsi build.fsx -- -h to check what is available to help you get started.
Benchmark
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3) 12th Gen Intel Core i7-12700H, 1 CPU, 20 logical and 14 physical cores .NET SDK 9.0.100 [Host] : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX2 DEBUG DefaultJob : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---|---|---|---|---|---|---|---|---|
| RenderWithRazorCSharp | 247.7 ns | 3.80 ns | 3.37 ns | 1.00 | 0.02 | 0.0291 | 368 B | 1.00 |
| RenderWithFunBlazorInlineCE | 374.1 ns | 5.53 ns | 4.91 ns | 1.51 | 0.03 | 0.0439 | 552 B | 1.50 |
| RenderWithFunBlazorSSRTemplate | 475.6 ns | 5.78 ns | 5.40 ns | 1.92 | 0.03 | 0.0420 | 528 B | 1.43 |
| RenderWithBolero | 497.9 ns | 8.46 ns | 10.07 ns | 2.01 | 0.05 | 0.1192 | 1496 B | 4.07 |
| RenderWithFunBlazorArray | 525.2 ns | 10.44 ns | 11.17 ns | 2.12 | 0.05 | 0.1144 | 1440 B | 3.91 |
| RenderWithFunBlazorTemplate | 785.9 ns | 7.95 ns | 7.44 ns | 3.17 | 0.05 | 0.1240 | 1560 B | 4.24 |
