WebSharper 3.6 to 4.x update guide
Changes
WebSharper 4 was designed to be as compatible as possible with code written for WebSharper 3 while moving closer to .NET semantics, and adding C# support. Most code should compile and run without errors.
NuGet packages
To update your WebSharper 3 project, update all package references to 4.0
versions and
add WebSharper.FSharp
for F# projects, and WebSharper.CSharp
for C# projects.
(Previously there was no compilation from C#, but C# web projects supported unpacking and serving
WebSharper sites defined in dependent F# libraries. Now this unpacking needs WebSharper.CSharp
even if you do not plan to add C# code you would compile to JavaScript).
During the beta period packages were released under codename Zafir
.
If you were using the WebSharper 4 pre-releases, uninstall all Zafir.*
packages, and install their WebSharper.*
counterparts.
WebSharper.UI.Next
package should be replaced with WebSharper.UI
, and the code changed accordingly (check "UI.Next changes to UI" section bellow for further details).
JavaScript Attribute changes
The JavaScript
attribute is no longer an alias for ReflectedDefinition
.
New features: you can use the attribute on assembly level: [<assembly: JavaScript>]
.
Also [JavaScript(false)]
removes a module, type or member from the scope of the JavaScript translation.
Extra F# language features
Syntax forms previously disallowed by the limitations of ReflectedDefinition becomes available to use for client-side code.
These are object expressions, byref and &
operator, inner generic functions, pattern matching on arrays, statically resolved type parameters.
Also object-oriented features has been expanded, see below.
Object-oriented features
WebSharper now supports .NET semantics for method overrides, interface implementations, static constructors,
base calls, having no implicit constructor.
Previous workarounds for these missing features may be breaking:
JavaScript-compiled names of implementation and override methods are now resolved automatically, and using the Name
attribute on them is disallowed.
You can specify the JavaScript-compiled name at the interface or abstract method declaration.
Module-bound let
values are no more initialized on page load, but on the first access of any value in the same source file (as in .NET).
Instance-based remoting
Interface types cannot be used any more for instance method remote calls.
Abstract classes are the recommended way, because they allow the definition and implementation to be in different projects.
Also SetRpcHandlerFactory
has been replaced by an AddRpcHandler
(alias for WebSharper.Core.Remoting..AddHandler
) function,
call this in your application initialization with a single type and instance (call multiple times for more)
to assign an object instance to handle calls to methods of Remote<T>
from the client.
See example:
open WebSharper
[<AbstractClass>]
type RemoteStringFunctions() =
[<Remote>]
abstract DoSomething: string -> Async<string>
let createRemoteStringFunctions() =
// F# object expressions are just a shortcut to defining a subclass
{ new RemoteStringFunctions() with
override this.DoSomething input =
async {
return "Hello " + input
}
}
// call this in your app initialization, for example when creating the main Sitelet instance
AddRpcHandler typeof<RemoteStringFunctions> (createRemoteStringFunctions())
// in client code, call like this: Remote<RemoteStringFunctions>.DoSomething "world"
Namespace changes
Attribute types are now in WebSharper
namespace, not WebSharper.Pervasives
module.
Single Page Application changes
Bundling now creates minimal code using code path exploration.
You have to mark the entry point with the new [<SPAEntryPoint>]
attribute.
This must be a single static method with no arguments.
Translation changes
These changes may be breaking if some of your code relies on exact JavaScript form of some translated code.
Union types now respect the
UseNullAsTrueValue
flag. For example theNone
value is now translated tonull
.Delegates are now having proper proxies,
Combine
,Remove
,Target
andGetInvocationList
are usable on client-side. Previously delegates were a shortcut to create multiple-argument JavaScript functions (already deprecated in WebSharper 3 but not removed).Constructing a default value for example
Unchecked.defaultof
now always uses compile-time type information. This can be problematic if the type is a generic parameter. For example usingmatch dict.TryGetValue x with ...
can throw an error if dict has a generic value type, as the F# compiler is implicitly creating a default value to pass to the out parameter ofTryGetValue
. You can get around it by wrapping the expression in the new helperDefaultToUndefined
which allows translating default values inside to justundefined
:match DefaultToUndefined(dict.TryGetValue x) with ...
By default, classes (including F# records and unions) with no methods translated to JS instance methods and having no base class are now translated not to have a prototype. JSON serializer was fixed to handle this. This is a performance optimization, but disallows type checks or inheriting from a class like this. So a new attribute
Prototype
was added to opt-in for generating a prototype for the type in the translation. Extra features:Prototype(false)
forces the type to have no prototype, converting instance methods to static in translation.Previously, having
[<Inline "myLibrary.doSomething()">]
and[<Inline "$global.myLibrary.doSomething()">]
was working equivalently. Now access to global scope without the$global
object is assumed to be initialized before the current script starts running (WebSharper itself takes care of this, if you use theRequire
attribute) and will not change, so it is safe to shorten. Whenever you want the exact call on the current global scope (window object), be sure to use$global
.Classes have now automatic reference equality. If you have relied on classes having automatic structural equality in the WebSharper translation, this is now incorrect. Implement an override for
Equals
to fix it.Create an empty JavaScript plain object with
new JSObject()
/New []
. Previously this was equivalent tonew object()
/obj()
, but now the latter translates to an instance ofWebSharper.Obj
which defines its ownEquals
andGetHashCode
methods.Default hash value of classes are now always -1. This should not be breaking, but if you use a class as keys or rely on hashing in any other way, be sure to override
GetHashCode
on your class for performance.System.Decimal
support has been removed from WebSharper main libraries. It is now a part ofWebSharper.MathJS
and has correct precision.
WebSharper Extension changes
C#-friendly overloads (using delegates and new function wrapper types) has been added to all libraries created by the WebSharper Interface Generator. In some cases where the overloads would be ambigous with the F# versions (function with 0 or 1 arguments), the F# style overload has been removed. You may need to convert to a delegate when using these methods, you can do this implicitly by having a lambda as the argument. If the argument was previously an F# function value, you have to write a lambda for calling it.
Project settings
WebSharper compiler now replaces fsc.exe
and does the .NET and JavaScript translation, as well as unpacking resources in a single pass.
For sitelet projects, previously all dlls available in bin folder when the WebSharper build task ran was unpacked to Scripts and Content folders.
Now only explicit references are searched for WebSharper resources and scripts to unpack.
Macros and generators
As the compiler pipeline of WebSharper has been replaced, the intermediate AST representation has changed. Macros and generators also gained new features, they get more info as input and has more options for output. Full API documentation will be available later.
Type inference changes which were at some point introduced FSharp.Compiler.Service
can be breaking.
We have changed WIG Generic helper operators which can be used to construct generic types and members
to have different character lengts based on arity: for example use Generic -- fun t1 t2 -> ...
instead of just Generic - fun t1 t2 -> ...
MacroResult.MacroNeedsResolvedTypeArg
now needs the offending type parameter as a field. You can decide
if a type is a type parameter of any kind by using the new IsParameter
property.
Macros relying on type information
Some built-in macros like the client-side JSON serialization relies on compile-time type information to generate JavaScript code.
For example WebSharper.Json.Encode
is a function that previously could be called only with fully-specified type argument.
Now, you can use it in a generic function if you mark that function [<Inline>]
.
In general, tranlation that relies on type information is delayed within inlines until the type arguments has been resolved at the call point.
JSON APIs
Instead of using the CompiledName
attribute to specify JSON-serialized name of an F# union case, use WebSharper's Name
attribute.
Json.SerializeWith
and similar functions taking a custom serializer object have been removed.
UI.Next changes to UI in WebSharper 4.1
The package WebSharper.UI.Next has been renamed to WebSharper.UI. A legacy package named "WebSharper.UI.Next" still exists to help smoothen the transition, but it is recommended to switch to WebSharper.UI.
- Namespaces are renamed from
WebSharper.UI.Next
toWebSharper.UI
. - All
elementAttr
andelement
functions have been merged: there is now a singleelement
function which takes attributes and child elements. So for example, a call todiv [children]
becomesdiv [] [children]
, and a call todivAttr [attrs] [children]
becomesdiv [attrs] [children]
. - Templates that used the special
data-
prefixed attributes should replace them to usews-
prefix instead. - Instanciation of templates should be done with constructor instead of
.Doc
and passing values in chained method calls, and suffixed with a final call to.Doc()
. So a call like
becomesMyTemplate.Doc(Hole1 = "value1", Hole2 = "value2")
MyTemplate().Hole1("value1").Hole2("value2").Doc()
Missing features compared to WebSharper 3
- TypeScript definition output (was outdated and under-tested)
WebSharper.Warp
has not been released yet for WS4 (compiling fromReflectedDefinition
s in FSI)- Clean does not remove unpacked code