Skip to content

Commit 356cb2c

Browse files
committed
Merge branch 'master' into routing-with-single-model
2 parents 451b81f + 4a390a8 commit 356cb2c

File tree

84 files changed

+283
-356
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+283
-356
lines changed
File renamed without changes.

docs/component-elmish.md renamed to docs/components/component-elmish.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ stateDiagram-v2
1414
```
1515

1616
## How does Elmish integrate with SAFE?
17-
Elmish is the library used to build the front-end application in SAFE and that application is compiled to JavaScript by [Fable](component-fable.md) to run in the browser. The [SAFE Stack template](template-overview.md) comes pre-bundled with the [Elmish React](https://elmish.github.io/react/) module, which (as the name suggests) uses the [React](https://reactjs.org/) library to handle the heavy lifting of modifyng the DOM in an efficient way. This allow us to use the pure functional style of the MVU pattern whilst still retaining the ability to have a highly performant user interface.
17+
Elmish is the library used to build the front-end application in SAFE and that application is compiled to JavaScript by [Fable](component-fable.md) to run in the browser. The [SAFE Stack template](../template-overview.md) comes pre-bundled with the [Elmish React](https://elmish.github.io/react/) module, which (as the name suggests) uses the [React](https://reactjs.org/) library to handle the heavy lifting of modifyng the DOM in an efficient way. This allow us to use the pure functional style of the MVU pattern whilst still retaining the ability to have a highly performant user interface.
1818

1919
Because Elmish works alongside React, it is possible to use the vast number of available React components from the JavaScript ecosystem within our Elmish applications.
2020

docs/component-fable.md renamed to docs/components/component-fable.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ It also provides *rich* integration with the JS ecosystem which means that you c
99

1010
## How does Fable integrate with SAFE?
1111

12-
Fable is a tool that generates JavaScript files from F# code. This allows us to write full front end applications using F#. Being able to write both the Server and Client in the same language offers huge benefits especially when you can share code between the two, without the need for duplication. More information on code sharing can be found [here](feature-clientserver.md).
12+
Fable is a tool that generates JavaScript files from F# code. This allows us to write full front end applications using F#. Being able to write both the Server and Client in the same language offers huge benefits especially when you can share code between the two, without the need for duplication. More information on code sharing can be found [here](../features/feature-clientserver.md).
1313

1414
## Fable and Vite
1515

16-
As Fable allows us to integrate into the JS Ecosystem, we can make use of tools such as Vite with features including [Hot Module replacement](feature-hmr.md) and Source Maps.
16+
As Fable allows us to integrate into the JS Ecosystem, we can make use of tools such as Vite with features including [Hot Module replacement](../features/feature-hmr.md) and Source Maps.
1717

18-
The [SAFE Template](template-overview.md) already has Vite configured to get you up and running immediately.
18+
The [SAFE Template](../template-overview.md) already has Vite configured to get you up and running immediately.
1919

2020
Learn more about Fable [here](http://fable.io/).

docs/component-saturn.md renamed to docs/components/component-saturn.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Saturn provides the ability to drive your SAFE applications from the server. It
1515
* Hosting of your client-side assets, such as HTML, CSS and JavaScript generated by Fable.
1616
* Other cross cutting concerns e.g. authentication etc.
1717

18-
It also integrates with SAFE to allow seamless sharing of types and functions, since Fable will convert most F# into JavaScript. In addition, you can seamless transport data between client and server using either the Fable.JSON or Fable.Remoting libraries, both of which have support for Saturn. You can read more about this [here](feature-clientserver.md).
18+
It also integrates with SAFE to allow seamless sharing of types and functions, since Fable will convert most F# into JavaScript. In addition, you can seamless transport data between client and server using either the Fable.JSON or Fable.Remoting libraries, both of which have support for Saturn. You can read more about this [here](../features/feature-clientserver.md).
1919

2020
```mermaid
2121
flowchart TB
File renamed without changes.

docs/faq-troubleshooting.md renamed to docs/faq/faq-troubleshooting.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ You may see the following `SocketProtocolError` message in the Debug Console onc
2525

2626
> `WebSocket connection to 'ws://localhost:8000/socketcluster/' failed: Error during WebSocket handshake: Unexpected response code: 404`
2727
28-
<center><img src="../img/feature-debugging-5.png" style="height: 175px;"/></center>
28+
<center><img src="../../img/feature-debugging-5.png" style="height: 175px;"/></center>
2929

30-
Whilst these messages can be safely ignored, you can eliminate them by installing **Redux Dev Tools** in the launched Chrome instance as described in the debugging [prerequisites](v4-recipes/developing-and-testing/debug-safe-app.md#0-install-prerequisites) section.
30+
Whilst these messages can be safely ignored, you can eliminate them by installing **Redux Dev Tools** in the launched Chrome instance as described in the debugging [prerequisites](../v4-recipes/developing-and-testing/debug-safe-app.md#0-install-prerequisites) section.
3131

3232
### Node Process does not stop after stopping the VS Code debugger
3333
VS Code does not kill the Fable process when you stop the debugger, leaving it running as a "zombie". In such a case, you will have to explicitly kill the process otherwise it will hold onto
3434
port 8080 and prevent you starting new instances. This should be easily doable by sending Ctrl+C in the Terminal window in VS Code for `Watch Client` task. Tracked [here](https://github.com/SAFE-Stack/SAFE-template/issues/191).
3535

36-
<center><img src="../img/faq-troubleshoot-debugging.png" style="height: 175px;"/></center>
36+
<center><img src="../../img/faq-troubleshoot-debugging.png" style="height: 175px;"/></center>
3737

3838
### Chrome opens to a blank window when debugging in VS Code
3939

File renamed without changes.
File renamed without changes.
Lines changed: 72 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,72 @@
1-
Using F# on both client and server is at the core of the SAFE stack, as it simplifies the way we think about building web applications by using the same language, idioms and in many cases sharing our code and domain models.
2-
3-
However, building a client and a server app requires a fundamentally different way of thinking. On the server side we build [stateless APIs in Saturn](component-saturn.md) that map HTTP requests to internal functionality, whereas on the frontend we use the Elmish model, implementing the [model-view-update pattern](component-elmish.md): a stateful pattern that lets us think about the application state as it evolves while the application is running.
4-
5-
Even though we use the same language across platforms, applying these two different programming models forces us to switch our way of thinking back and forth when writing code for the client and for the server. This is where the [Elmish.Bridge](https://github.com/Nhowka/Elmish.Bridge) library comes into play: it brings the Elmish programming model *to the server* and unifies the way we write the application as a whole.
6-
7-
## How does Elmish work on the server?
8-
Think of Elmish on the server as the model-view-update pattern but *without the view part*. Instead, you only need to implement `init` and `update` functions to manage the *server* state as it evolves while the server is running.
9-
10-
* Server state can contain data that is relevant to a single or all clients
11-
* The dispatch loop running on the server is connected to the dispatch loop on the client via a *persistent stateful websocket connection*
12-
* The `update` functions on client and server can exchange data via message passing.
13-
14-
## A simple example
15-
Let's see a simple example of how this might work in practice:
16-
17-
```fsharp
18-
// Client-side
19-
let update msg state =
20-
match msg with
21-
| LoadUsers ->
22-
// send the message to the server
23-
state, Cmd.bridgeSend ServerMsg.LoadUsers
24-
| UsersLoaded users ->
25-
// receive message from the server
26-
let nextState = { state with Users = users }
27-
nextState, Cmd.none
28-
29-
// Server-side
30-
let update clientDispatch msg state =
31-
match msg with
32-
| ServerMsg.LoadUsers ->
33-
let loadUsersCmd =
34-
Cmd.ofAsync
35-
getUsersFromDb // unit -> Async<User list>
36-
() // input arg = unit
37-
UsersLoadedFromDb // User list -> ServerMsg
38-
DoNothing // ServerMsg
39-
state, loadUsersCmd
40-
41-
| ServerMsg.UsersLoadedFromDbSuccess users ->
42-
// answer the current connected client with data
43-
clientDispatch (ClientMsg.UsersLoaded users)
44-
state, Cmd.none
45-
46-
| ServerMsg.DoNothing ->
47-
state, Cmd.none
48-
```
49-
50-
The above example mimics what would have been a `GET` request to the server to get user data from database. However, now the client sends a fire-and-forget message to the server to load users, and at some point the server messages the current client back with the results. Notice that the server could have decided to do other things than just messaging the client back: for example, it could have broadcasted the same message to other clients updating their local state of the users.
51-
52-
## When to use Elmish.Bridge
53-
There are many scenarios where it makes sense to use Elmish.Bridge:
54-
55-
* Chat-like applications with many connected users through many channels
56-
* Syncing price data in real-time while viewing ticket prices
57-
* Multiplayer games that need real-time update of game states
58-
* Other applications of web sockets through an Elmish model
59-
60-
## Things to consider
61-
The biggest distinction between using this and "raw" Saturn is that your web server becomes a stateful service. This introduces several differences for application design.
62-
63-
1. The server state has a lifespan equal to the that of the process under which the server instance is running. This means if the server application restarts then the server state will be reset.
64-
65-
2. The server state is *local to the server instance*. This means that if you run multiple web servers, they won't be sharing the same server state by default.
66-
67-
As of now there is no built-in persistence for the state, but you can implement this yourself using any number of persistance layers such as Redis Cache, Azure Tables or Blobs etc.
68-
69-
In addition Elmish.Bridge does not use standard HTTP verbs for communication, but rather websockets. Therefore, it is not a suitable technology for an open web server that can serve requests from other sources than Elmish.Bridge clients.
70-
71-
## Learn more about Elmish.Bridge
72-
Head over to [Elmish.Bridge](https://github.com/Nhowka/Elmish.Bridge) to learn more.
1+
Using F# on both client and server is at the core of the SAFE stack, as it simplifies the way we think about building web applications by using the same language, idioms and in many cases sharing our code and domain models.
2+
3+
However, building a client and a server app requires a fundamentally different way of thinking. On the server side we build [stateless APIs in Saturn](../components/component-saturn.md) that map HTTP requests to internal functionality, whereas on the frontend we use the Elmish model, implementing the [model-view-update pattern](../components/component-elmish.md): a stateful pattern that lets us think about the application state as it evolves while the application is running.
4+
5+
Even though we use the same language across platforms, applying these two different programming models forces us to switch our way of thinking back and forth when writing code for the client and for the server. This is where the [Elmish.Bridge](https://github.com/Nhowka/Elmish.Bridge) library comes into play: it brings the Elmish programming model *to the server* and unifies the way we write the application as a whole.
6+
7+
## How does Elmish work on the server?
8+
Think of Elmish on the server as the model-view-update pattern but *without the view part*. Instead, you only need to implement `init` and `update` functions to manage the *server* state as it evolves while the server is running.
9+
10+
* Server state can contain data that is relevant to a single or all clients
11+
* The dispatch loop running on the server is connected to the dispatch loop on the client via a *persistent stateful websocket connection*
12+
* The `update` functions on client and server can exchange data via message passing.
13+
14+
## A simple example
15+
Let's see a simple example of how this might work in practice:
16+
17+
```fsharp
18+
// Client-side
19+
let update msg state =
20+
match msg with
21+
| LoadUsers ->
22+
// send the message to the server
23+
state, Cmd.bridgeSend ServerMsg.LoadUsers
24+
| UsersLoaded users ->
25+
// receive message from the server
26+
let nextState = { state with Users = users }
27+
nextState, Cmd.none
28+
29+
// Server-side
30+
let update clientDispatch msg state =
31+
match msg with
32+
| ServerMsg.LoadUsers ->
33+
let loadUsersCmd =
34+
Cmd.ofAsync
35+
getUsersFromDb // unit -> Async<User list>
36+
() // input arg = unit
37+
UsersLoadedFromDb // User list -> ServerMsg
38+
DoNothing // ServerMsg
39+
state, loadUsersCmd
40+
41+
| ServerMsg.UsersLoadedFromDbSuccess users ->
42+
// answer the current connected client with data
43+
clientDispatch (ClientMsg.UsersLoaded users)
44+
state, Cmd.none
45+
46+
| ServerMsg.DoNothing ->
47+
state, Cmd.none
48+
```
49+
50+
The above example mimics what would have been a `GET` request to the server to get user data from database. However, now the client sends a fire-and-forget message to the server to load users, and at some point the server messages the current client back with the results. Notice that the server could have decided to do other things than just messaging the client back: for example, it could have broadcasted the same message to other clients updating their local state of the users.
51+
52+
## When to use Elmish.Bridge
53+
There are many scenarios where it makes sense to use Elmish.Bridge:
54+
55+
* Chat-like applications with many connected users through many channels
56+
* Syncing price data in real-time while viewing ticket prices
57+
* Multiplayer games that need real-time update of game states
58+
* Other applications of web sockets through an Elmish model
59+
60+
## Things to consider
61+
The biggest distinction between using this and "raw" Saturn is that your web server becomes a stateful service. This introduces several differences for application design.
62+
63+
1. The server state has a lifespan equal to the that of the process under which the server instance is running. This means if the server application restarts then the server state will be reset.
64+
65+
2. The server state is *local to the server instance*. This means that if you run multiple web servers, they won't be sharing the same server state by default.
66+
67+
As of now there is no built-in persistence for the state, but you can implement this yourself using any number of persistance layers such as Redis Cache, Azure Tables or Blobs etc.
68+
69+
In addition Elmish.Bridge does not use standard HTTP verbs for communication, but rather websockets. Therefore, it is not a suitable technology for an open web server that can serve requests from other sources than Elmish.Bridge clients.
70+
71+
## Learn more about Elmish.Bridge
72+
Head over to [Elmish.Bridge](https://github.com/Nhowka/Elmish.Bridge) to learn more.
File renamed without changes.

0 commit comments

Comments
 (0)