---
# System prepended metadata

title: WebSharper 7 bundling

---

# WebSharper 7 bundling

The current non-dependence on node.js is also an upside of WebSharper.
It would be ideal if WebSharper 7 allows new modes of output that can be well integrated with outside bundling (TS/webpack) but also keep the option to rely on pure JS output by WS only.

There are 3 main project types to consider:

* Sitelets 
* Offline sitelets (alias: HTML projects)
* SPAs (alias: bundle projects) also standalone JS output projects (bundleonly)

Additional concerns:
* Any outside JS/TS code using WS output?
* DCE
* Source mapping
* RPCs

Output options:

## 1) Dev/Interop mode (new WS7 mode)

One ES6 module per .NET class, readable and predictable format.
This is good for:
* Debug mode Sitelets, Sitelets runtime creates a small mini-script that imports all required `Web.Control` code and let the browser waterfall-load everything. Not good perf, but clean for debugging.
  * Pain point: F# source mapping. Source mapping is ideal use case for this, but currently WS does source mapping by including full source code files in the map file itself. This was ok where there was only one output .js file per assembly, and there was no cross-assembly source mapping (source locations on inlines are erased). But with many output modules not touching this logic creates a 60MB+ dll for `WebSharper.Main`, so that's why source-mapping is currently turned off for WS7 WIP. For source mapping, WS must switch to store source files as resources, unpack them, and serve them for the map files to refer to them so that they are not replicated many times across the `.js.map` files.
* JS/TS interop. This readable module output is great when you intend to use the WS output as integral part of a larger JS/TS project, where your .NET code and JS/TS code is developed in parallel. 
  * Pain point: RPCs as is use dynamic import in this mode. This is working for Debug mode Sitelets, but for bundling is a no-no. So if you want to use RPCs from outside code, we need to switch RPCs to use the typed, symmetric JSON protocol.

## 2a) Sitelets compatibility mode (option/proposal)
Similar to WS6 output, but optionally with DCE and even stronger minification. - all non-strongly named (no `Name` attribute) function/member names could be minified.
* The main idea behind Sitelets runtime dependency exploration is that it can serve back a list of .js links on pages that the page actually needs. For this to still work, we can't use imports, so again we just write side-effecting .js files per assembly but optional upgrades compared to WS6:
  * If we know the total scope of JS needed (all the Web.Controls, and all the server-side quoted methods and anything marked with JavaScriptExport), we can DCE all code, write it split by assembly and use existing Sitelets logic. This helps with WebSharper.Main.js getting larger for example, you will have a DCE-d WebSharper.Main.js instead for your app only.
  * Also we could apply obfuscation/minification on all non-strongly named (no `Name` attribute) function/member names, getting the .js files even smaller for Prod mode.

## 2b) Alternative to current Sitelets (option/proposal)
We could also throw out current Sitelets runtime dependency search completely, if only we allow the compiler to know at compile-time the dependency requirements of all possible pages served, then we pre-bundle everything separately, while recognizing common parts that can be moved to separate files so they are reused in multiple pages.
* Hard part: writing the server-side code analyzer for gathering sitelets page deps at compile time. This might require giving errors on some possible Sitelets handlers, for example if you would pass an Endpoint object to a function-valued (lambda) mutable var or argument. But if you just use F# matches or the C# Sitelets builder, and call straight up methods/local functions then compiler could gather the deps. If it encounters any other branching (if/match on Endpoint value) then all branches are collected. This can adds some more deps than needed, but you can resolve by making your Endpoint have that info too that you branch on.
* I do think it's best to choose between 2a or 2b for MPAs, not have both, less things to support. 2b might be breaking in some cases as above, but we

## 3) Two-way JS/TS interop - webpack mode (option/proposal)
One more possible combination: what if we do want to include main parts of app logic written in JS/TS, depending on some WS output, but then again have the entire thing integrated back to a Sitelets project. This is not trivial to solve, but as you are writing JS/TS, I think it's ok to offload this to webpack.
* we use mode 1) for output + generate an entry point js for all WS code per assembly for 2a) or for each page for 2b) then use webpack [multiple entry point feature](https://webpack.js.org/configuration/entry-context/#entry-descriptor) to bundle it up along with the external code.

## 4) Offline sitelets
This is actually easy enough after Sitelets work. Current API is usable, and would make use of upgrades in either 2a/2b/3 path. Offline sitelets structure the .js + assets the same as Sitelets, just they also do html generation for given list of Endpoint values.

## 5) Bundle mode
Bundling is currently used to: produce standalone libs for JS use, SPA sites and webworkers. For all of these, main logic of bundling can remain as is: we run DCE then write to a single file. 
Webworkers could be improved by adding a "modulepreload" link to html which makes webworker startup faster as browsers already preload and pre-parse the bundle created for the webworker.
* Do we support both module and non-module output? We can just go with module only I think but it's breaking change of existing bundle projects.
* Tricky part: how to structure exports (either module exports or added on "globalThis").
  * If used to run an SPA site's entry point only, how it exposes JS functions is irrelevant. It could just be a .js script that does not export or save anything on "globalThis". This is also the way for webworker bundles.
  * If we want to expose specific functions/types to use as a JS lib via the JavaScriptExport attribute,  how do we structure these? Do "namespacing" as WS does? Like `MyApp.MyModule.MyFunc` or require every exported name to be different and flattening it? (In case of namespacing `MyApp` either goes on global object for non-module output or is a named export of module.) Middle ground: if you don't have Name attribute, or you use a simple name, it goes to top level otherwise you need to fully specify your access path in your Name attribute.