• x Use ws-* instead of data-* for special attribute names. data-* attributes are standard HTML5 and people might want to use them in their application.

  • x Use a proper HTML parser, rather than System.Xml.Linq which is too restrictive (eg refuses <input> without final /, finnicky with entities, etc).

  • x Pass arguments using a chained method per argument rather than one method with N arguments. This provides better completion, and allows us to take advantage of overloading (eg: attributes can be either Attr or seq<Attr>, same with docs).

  • x Use ${name} for plain text holes and View holes (possible thanks to the aforementioned overloading).

  • Allow the client to load the template from the DOM, rather than have it inlined in JavaScript. This allows the developer to touch the HTML file and see the results with a simple refresh without recompiling.

  • Allow the client to download the template. Same as above but for templates that are in a separate file from the main document.

  • Allow the server to reload the template from the file system. Same as above but when using from the server side. The model here is WebSharper.Html's templating:

    1
    
    type LoadFrequency = Once | PerRequest | WhenChanged

The last three pose new challenges regarding nested templates. For example let's say my index.html is as follows:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
  <head><title>Test</title><meta ws-replace="meta"><link ws-replace="styles"></head>
  <body>
    <div ws-hole="clientContent">
      <div ws-template="clientTpl">The client says: ${text}</div>
    </div>
    <script ws-replace="scripts"></script>
  </body>
</html>

And it is used as follows:

1
2
3
4
5
6
7
8
9
10
11
type Template = Template<"index.html", clientLoad = ClientLoad.FromDocument>

[<JavaScript>]
let ClientFun() = Template.clientTpl().text("Hi!").Doc()

[<Website>]
let App = Application.SinglePage(fun ctx ->
  Content.Page(
    Template().clientContent(client <@ ClientFun() @>).Doc()
  )
)

ClientFun will look in the DOM for a node with ws-template="clientTpl", but it won't be there, because the current document isn't quite index.html. Instead it's a processed version of index.html in which that node has been replaced with the placeholder in which client <@ ClientFun() @> will be rendered.

The proposed solution is that if clientLoad = ClientLoad.FromDocument, and the server is building the root template, then it re-adds all the sub-templates as hidden nodes at the bottom of the body.