You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/Oxpecker.ViewEngine/README.md
+51-1Lines changed: 51 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -44,6 +44,7 @@ let mainView (model: Person) =
44
44
-[Attributes](#attributes)
45
45
-[Event handlers](#event-handlers)
46
46
-[Html escaping](#html-escaping)
47
+
-[Prerendering](#prerendering)
47
48
-[Rendering](#rendering)
48
49
-[ARIA](#aria)
49
50
-[Fragments](#fragments)
@@ -63,7 +64,7 @@ let mainView (model: Person) =
63
64
abstract member AddChild: HtmlElement -> unit
64
65
...
65
66
```
66
-
There are 5 types of HTML elements available: `RegularNode`, `VoidNode` (only attributes), `FragmentNode` (only children), `RegularTextNode`(escaped text), `RawTextNode`(unescaped text).
67
+
There are 7 types of HTML elements available: `RegularNode`, `VoidNode` (only attributes), `FragmentNode` (only children), `RegularTextNode`(escaped text), `RawTextNode`(unescaped text), `IntNode`(integer), `PrerenderedNode`(prerendered markup around children).
67
68
68
69
All HTML tags inherit from `RegularNode` or `VoidNode` and you can easily create your own tag:
69
70
@@ -140,6 +141,55 @@ div(){
140
141
}
141
142
```
142
143
144
+
### Prerendering
145
+
146
+
Views are object trees that are walked (and their text and attributes escaped) on every render. When a part of your view is static, `prerender` lets you pay that cost once: it renders an element **together with all its children** into a snapshot that is appended as a plain string on every subsequent render.
147
+
148
+
```fsharp
149
+
// rendered once, when the module is initialized
150
+
let pageHeader =
151
+
prerender(
152
+
header() {
153
+
h1() { "My site" }
154
+
nav() { a(href = "/") { "Home" } }
155
+
}
156
+
)
157
+
158
+
let page (model: Model) =
159
+
html() {
160
+
body() {
161
+
pageHeader // appended as a plain string on every request
162
+
main() { model.Content }
163
+
}
164
+
}
165
+
```
166
+
167
+
`prerender` returns a `RawTextNode` holding already-escaped HTML, so the snapshot is not escaped again when embedded.
168
+
169
+
Note that the snapshot is taken **eagerly**, at the moment of the call: children or attributes added to the original element afterwards won't be reflected in the returned node.
170
+
171
+
When only a small part of the markup changes between renders, `prerenderAround` lets you prerender everything around it. It takes a function that places the provided _hole_ inside your markup, renders the static part once, and gives you back a factory that is used like any other tag:
172
+
173
+
```fsharp
174
+
let layout =
175
+
prerenderAround(fun content ->
176
+
html() {
177
+
body() {
178
+
header() { h1() { "My site" } }
179
+
main() { content }
180
+
footer() { "(c) 2026" }
181
+
}
182
+
})
183
+
184
+
let page (model: Model) =
185
+
layout() {
186
+
h2() { model.Title }
187
+
p() { model.Text }
188
+
}
189
+
```
190
+
191
+
Everything outside the hole is rendered once, so every `page` call only appends two prerendered strings around its own children. The hole has to be used exactly once, otherwise `prerenderAround` raises an `ArgumentException`.
192
+
143
193
### Rendering
144
194
145
195
There are several functions to render `HtmlElement` (after opening Oxpecker.ViewEngine namespace):
0 commit comments