{"id":13658621,"url":"https://github.com/dotnet-websharper/mvu","last_synced_at":"2025-04-06T05:31:59.150Z","repository":{"id":68008499,"uuid":"129095583","full_name":"dotnet-websharper/mvu","owner":"dotnet-websharper","description":"Model-View-Update architecture for WebSharper client-side applications.","archived":false,"fork":false,"pushed_at":"2025-03-13T18:05:37.000Z","size":842,"stargazers_count":26,"open_issues_count":7,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-21T18:06:52.328Z","etag":null,"topics":["fsharp","mvu","spa","websharper"],"latest_commit_sha":null,"homepage":"https://dotnet-websharper.github.io/mvu/","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dotnet-websharper.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-11T13:10:18.000Z","updated_at":"2025-03-13T18:05:29.000Z","dependencies_parsed_at":"2023-09-27T14:58:26.680Z","dependency_job_id":"648973ca-2970-4449-91de-159c1dd3db20","html_url":"https://github.com/dotnet-websharper/mvu","commit_stats":null,"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-websharper%2Fmvu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-websharper%2Fmvu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-websharper%2Fmvu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dotnet-websharper%2Fmvu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dotnet-websharper","download_url":"https://codeload.github.com/dotnet-websharper/mvu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247440381,"owners_count":20939220,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fsharp","mvu","spa","websharper"],"created_at":"2024-08-02T05:01:01.197Z","updated_at":"2025-04-06T05:31:58.171Z","avatar_url":"https://github.com/dotnet-websharper.png","language":"F#","funding_links":[],"categories":["Libraries"],"sub_categories":["Reactive libraries"],"readme":"# WebSharper.Mvu\r\n\r\nWebSharper.Mvu provides an [Elm](https://guide.elm-lang.org/architecture/)-inspired MVU (Model-View-Update) architecture for WebSharper client-side applications.\r\n\r\nIt is based on [WebSharper.UI](http://developers.websharper.com/docs/v4.x/fs/ui) for its reactivity and HTML rendering.\r\n\r\n## The MVU architecture\r\n\r\nModel-View-Update is an application architecture that aims to make the behavior and state of GUIs clear and predictable.\r\n\r\nThe state of the application is stored as a single **Model**, which is an immutable value (generally a record).\r\n\r\nThis is rendered by a **View** [1], which defines how the model is transformed into DOM elements.\r\n\r\nFinally, all changes to the model are applied by a pure **Update** function, which takes messages sent by the view and applies changes accordingly.\r\n\r\n[1] Although in WebSharper.Mvu we tend to use the term **Render** instead, to avoid confusion with the WebSharper.UI `View` type.\r\n\r\n## Features of WebSharper.Mvu\r\n\r\nWebSharper.Mvu provides a number of features on top of this architecture.\r\n\r\n### Time-travel debugging with RemoteDev\r\n\r\nWebSharper.Mvu integrates seamlessly with [RemoteDev](https://github.com/zalmoxisus/remotedev). This tool allows you to inspect the successive messages and states of your model, and even to replay old states and see the effect on your view.\r\n\r\n![RemoteDev screenshot](docs/images/remotedev.png)\r\n\r\nThis is done by adding a single line to your app declaration:\r\n\r\n```fsharp\r\nApp.Create initialModel update render\r\n|\u003e App.WithRemoteDev (RemoteDev.Options(hostname = \"localhost\", port = 8000))\r\n|\u003e App.Run\r\n```\r\n\r\n[Learn more about WebSharper.Mvu and RemoteDev.](docs/remotedev.md)\r\n\r\n### Automatic local storage\r\n\r\nWebSharper.Mvu can automatically save the model to the local storage on every change. This allows you to keep the same application state across page refreshes, which is very useful for debugging.\r\n\r\nThis is done by adding a single line to your app declaration:\r\n\r\n```fsharp\r\nApp.Create initialModel update render\r\n|\u003e App.WithLocalStorage \"key\"\r\n|\u003e App.Run\r\n```\r\n\r\n\u003e If you want to use _both_ local storage and RemoteDev, you must add `App.WithLocalStorage` _before_ `App.WithRemoteDev`, or you will run into problems with RemoteDev.\r\n\r\n### HTML templating\r\n\r\nWebSharper.Mvu can make use of WebSharper.UI's HTML templating facilities. This reinforces the separation of concerns by keeping the view contained in HTML files. The render function then just connects reactive content and event handlers to the strongly-typed template holes.\r\n\r\nTemplating also allows you to touch up your view without having to recompile the application.\r\n\r\n[Learn more about WebSharper.UI HTML templating.](http://developers.websharper.com/docs/v4.x/fs/ui#templating)\r\n\r\n### Paging\r\n\r\nThe `Page` type makes it easy to write \"multi-page SPAs\": applications that are entirely client-side but still logically divided into different pages. It handles parameterized pages and allows using CSS transitions between pages. Pages can specify their DOM behavior, such as keeping elements around to allow for smoother transitions.\r\n\r\nHere is a small application that demonstrates this. [You can run it live on TrywebSharper.](http://try.websharper.com/snippet/loic.denuziere/0000Kc)\r\n\r\n![Paging with transitions](docs/images/paging.gif)\r\n\r\nThis is the structure of [the view for the above application](https://github.com/dotnet-websharper/mvu/blob/master/WebSharper.Mvu.Tests/Client.fs):\r\n\r\n```fsharp\r\ntype EndPoint = Home | EditEntry of string\r\n\r\ntype Model = { EndPoint : EndPoint; (* ... *) }\r\n\r\nmodule Pages =\r\n\r\n    let Home = Page.Single(attrs = [Attr.Class \"home-page\"], render = fun dispatch model -\u003e\r\n        // ...\r\n    )\r\n\r\n    let EditEntry = Page.Create(attrs = [Attr.Class \"entry-page\"], render = fun key dispatch model -\u003e\r\n        // ...\r\n    )\r\n\r\nlet render model =\r\n    match model.EndPoint with\r\n    | EndPoint.Home -\u003e Pages.Home ()\r\n    | EndPoint.EditEntry key -\u003e Pages.EditEntry key\r\n\r\nlet main () =\r\n    App.CreatePaged initialModel update render\r\n    |\u003e App.Run\r\n```\r\n\r\nThe transitions are specified as [CSS transitions on the `home-page` and `entry-page` classes](https://github.com/dotnet-websharper/mvu/blob/master/WebSharper.Mvu.Tests/wwwroot/index.html).\r\n\r\n### Routing\r\n\r\nThe page's URL can be easily bound to the application model. The URL scheme is declared using a [WebSharper router](http://developers.websharper.com/docs/v4.x/fs/sitelets#sitelet-infer), and the parsed endpoint value is stored as a field in the model.\r\n\r\nRouting and paging work nicely together, but neither requires the other.\r\n\r\nRouting is implemented by adding a single line to your app declaration:\r\n\r\n```fsharp\r\ntype EndPoint = // ...\r\n\r\ntype Model = { EndPoint : EndPoint; (* ... *) }\r\n\r\nlet app = App.Create initialModel update render\r\nApp.WithRouting (Router.Infer\u003cEndPoint\u003e()) (fun model -\u003e model.EndPoint) app\r\n|\u003e App.Run\r\n```\r\n\r\n## Differences with other MVU libraries\r\n\r\nThe main point that differenciates WebSharper.Mvu from other MVU libraries is the way the render function works.\r\n\r\nIn most MVU libraries, the view function directly takes a Model value as argument. It is called every time the model changes, and returns a new representation of the rendered document every time. This new representation is then applied to the DOM by a diffing DOM library such as React.\r\n\r\nIn contrast, in WebSharper.Mvu, the render function takes a WebSharper.UI `View\u003cModel\u003e` as argument. It is called only once, and it is this `View` that changes every time the model is updated. This helps make more explicit which parts of the rendered document are static and which parts are reactive.\r\n\r\n## Learn more...\r\n\r\nTry WebSharper.Mvu examples live:\r\n\r\n* [A simple counter](http://try.websharper.com/#/snippet/loic.denuziere/0000Kf)\r\n* [A list of counters](http://try.websharper.com/#/snippet/loic.denuziere/0000Kg)\r\n* [Paging](http://try.websharper.com/snippet/loic.denuziere/0000Kc)\r\n* [TodoMVC](http://try.websharper.com/#/snippet/loic.denuziere/0000Kj)\r\n\r\nSample repositories:\r\n\r\n* [TodoMVC](https://github.com/websharper-samples/Mvu)\r\n* [CRUD client](https://github.com/websharper-samples/PeopleClient)\r\n\r\nLearn more about WebSharper:\r\n\r\n* [WebSharper](https://websharper.com)\r\n* [WebSharper UI](http://developers.websharper.com/docs/v4.x/fs/ui)\r\n* [WebSharper Forums](https://forums.websharper.com)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotnet-websharper%2Fmvu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdotnet-websharper%2Fmvu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdotnet-websharper%2Fmvu/lists"}