WebSharper 8.0
This is a major release of WebSharper. NuGet version 8.0.0.540
.
Templates for .NET Core SDK: dotnet new install WebSharper.Templates::8.0.0.541
WebSharper version 8 is running on .NET 8, the current LTS .NET framework. A WebSharper 9 upgrade is soon in the pipeline. The WebSharper 7 version haven't reached maturity, so it is skipped as a production-ready release. The below change summaries reflect changes since WebSharper 6.
Changes to JavaScript translation
WebSharper 8 writes modern module-based JavaScript code. This is a break from previous versions which still had EcmaScript 5 compatible output that could be directly interpreted by browsers. With WebSharper 8, usually some bundling tool is required if you use code that would import any npm packages or if you want to optimize your site for production. Many WebSharper bindings have been updated to use npm imports.
For an overview of WebSharper's JavaScript translation with F# examples (but everything is also valid for C#), see the WebSharper 8 translation document.
Changes to Sitelets (web projects)
Along with the JavaScript change, using dynamic code lookup has been eliminated, initializing web pages always use explicit import statements. A production-ready mode has been added to serve optimized bundled code.
Please read the WebSharper 8 update guide on how to update your older projects or create a new WebSharper 8 project from a template using dotnet new install WebSharper.Templates
.
- #1359 Web.Controls now use a
ws-id
attribute on elements to mark where to insert dynamic content. - #1361 By default, output follows one class per file rule, and there is an additional
root.js
for web projects that re-exports everything needed by the site. This file can be used as an entrypoint for a bundler like esbuild. - #1372 If you specify
"prebundle": true
inwsconfig.json
, then the WebSharper compiler will create readable npm-based prebundles, and Sitelets runtime will expect fully bundled code export their contents through a global variable calledwsbundle
. Configure a bundler likeesbuild
to create a final bundle.
See new templates for an example. - #1438 Prebundling is also supported for offline sitelets. Use a bundler to generate fully offline-compatible JavaScript.
- #1408 Added a
UseWebSharperScriptRedirect
helper for Asp.NET Core, which starts up avite
server on the url setting"DebugScriptRedirectUrl"
inappconfig.json
's"websharper"
section. - #1403 Added
Content.PageFromFile
, which serves a html file from application root, while inserting an initializer scripts where exact placeholder<script ws-replace="scripts"></script>
is found.
Changes to Remoting and JSON serialization
- #1343 Remoting now uses a symmetric JSON serialization, requests and responses have use the same serializers. In JavaScript code, a function is created for every RPC function, that wraps this deserialization and handles the asynchronicity.
- #1346
Web.Control
initialization now takes place in ascript
block, instead of grabbing data from ameta
element. - #1336 RPC endpoints are exposed by default at
yourURL/TypeName/MethodName
, and do not expect any custom headers any more, but behave like a standard API. - #1424 The above default path can be overridden with the
Remote
attribute, example:Remote("alternatePath")
. - #1339 Record types can now be used for instance-based remoting. Example:
type RecordRemote = { [<Remote>] R1 : string -> Async<string> } let recordRemoteImpl = { R1 = fun x -> async { return (x + "_fromRecordRemote") } } do AddRpcHandler typeof<RecordRemote> recordRemoteImpl
- #1047 Interfaces can now be used for instance-based remoting, similar to classes and records.
New features
- #1299 Added the
Import
attribute, sample usage:[<Import("sayHi.js")>] // imports the default export, applies to all Inlines/Stubs within class type SayHi [<Inline "new $imported()">] () = // FooInst is an instance member, we don't have to refer to an import directly, so its effect is ignored [<Inline "$this.FooInst()">] member this.FooInst() = X<string> // Foo is a static member of SayHi class, this inherits the Import attr from the type [<Inline "$imported.Foo()">] static member Foo() = X<string> // Bar is a separate named export, we redefine the Import attr which hides the one inherited from the type [<Import("Bar", "sayHi.js"); Inline "$imported()">] static member Bar() = X<string>
- #1391 Added
WebSharper.JavaScript.ImportFile
function which adds a side-effecting import, that can be used for css and other non-code resources. - #1347 Added
ImportFile
helper to WebSharper.InterfaceGenerator, example usage:"default" => T<unit> ^-> T<unit> |> ImportFile (sprintf "highlight.js/styles/default.css" name)
. - #1333 Added
JS.Verbatim
which takes a string and exact JS code will be printed in the code output. Supports string interpolation to include values. AlsoJS.jsx
for supporting jsx HTML fragments. - #1325 You can use
"JsOutput": "path"
to make the compiler output all generated code from library projects too. - #1350 Added support of
SPAEntryPoint
attribute for library projects. Combined with the"JsOutput"
setting, this allows library projects to be used for producing .js files for external use. An$EntryPoint.js
file will contain the call for the annotated function. - #1337 You can add static members
EncodeJson
/DecodeJson
on a type to enable WebSharper's client-side JSON serialization on them. - #1340 Query parameters can be included in
Endpoint
attribute values:| [<EndPoint "/FindBook?isbn={isbn}&ty={ty}">] FindBook of isbn:string * ty:string option
- #1388 Added proxy for
System.StringBuilder
- #1389 Added proxy for
System.Convert
- #775 Added proxy for
stderr
/System.Console.Error
- #1355 Added the
!...
operator for F# use, which translates directly to the JavaScript spread operator...
- #1383 Metaprogramming: macros defined on the type level is now invoked before the macro on a member. The type level one can return a
MacroFallback
value to let use the default translation for a member. - #1368
Stub
attribute is valid for interfaces, with the equivalent effect ofName("")
, translating member names without prepended type name. - #1373 Metaprogramming: generators now get the expression of the member they are used on, so they can act as decorators, dynamically adjusting the code of the member.
- #1377 Metaprogramming: you can define your own attribute, put
Macro
orGenerator
attribute on them, and your attribute will work as an alias. - #1386 You can use
"StubInterfaces": true
inwsconfig.json
to automatically treat all interfaces in your project as aStub
(interface for JavaScript interop). - #1395
Stub
attribute now accomodates for overloads, keeping the JavaScript name always as is in .NET. - #1397 F#
option
arguments inStub
types translate to plain arguments. - #1404
wsconfig.json
files can defineDebug
andRelease
sections. - #1405 Added missing
Style
property forHTMLElement
.
Fixes
- #1387 Implicit quotations in client-side code are not pre-compiled as a separate member.
- #1412 Fix dead code elimination around interface methods.
- #1351 Fix WIG created dlls to have file information when looked at by Windows file properties dialog.
Language features
- The compilers now run on .NET 8.
- #1366 F# 8.0 new features: syntax sugar (property shorthand, nested record field copy, etc.), static interface members,
try/with
within collection expressions - #1294 C# 11.0 new feature: list patterns
- #1367 C# 12.0 new features: primary constructors for non-record classes, collection expressions and the
..
operator
Cleanup and optimizations
- #1445 All standard proxies are now merged into a single
WebSharper.StdLib.dll
- #1362 removed the
requestAnimationFrame
polyfill. - #1364 removed the
JSON
polyfill. - #1431
printf
functions now generate cleaner code when a string is used in a%s
hole. - #1443 Removed
UseStdlibCdn
and other WebSharper CDN-related settings. - #1444 Removed
UseMinifiedScripts
setting. WebSharper now outputs readable code, to be processed by external JavaScript tooling for production purposes.
Breaking changes
- The serialization/url changes around remoting can break code if you depended on unspecified internal mechanisms of RPC calls. The goal of the remoting changes is to provide reliable API shapes now.
- Removed two fields from
Resources.Context
type:DebuggingEnabled
andGetAssemblyRendering
, these had a very low chance to be needed from any user code directly. - #1351 was achieved by WIG building atop the definitions library. In WIG, make sure you don't have namespace conflicts between your definitions and the defining code, and ideally hide the definitions by making them internal.