Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some minor corrections to the documentation #367

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/components/component-elmish.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Elmish is a library for building single page applications in F#, following the [model-view-update](https://guide.elm-lang.org/architecture/) architecture made famous by [Elm](http://elm-lang.org).

> The following diagram is a simplified, high-level view of the MVU pattern. `Model` in this case refers to your application's state, with `Update` and `View` the two functions that handle the flow of messaging. If you wish to read more, we also recommend reading the excellent [Elmish Book](https://zaid-ajaj.github.io/the-elmish-book/#/chapters/elm/the-architecture).
> The following diagram is a simplified, high-level view of the MVU pattern. `Model` in this case refers to your application's state, with `Update` and `View` as the two functions that handle the flow of messaging. If you wish to read more, we also recommend reading the excellent [Elmish Book](https://zaid-ajaj.github.io/the-elmish-book/#/chapters/elm/the-architecture).

```mermaid
stateDiagram-v2
Expand All @@ -14,7 +14,7 @@ stateDiagram-v2
```

## How does Elmish integrate with SAFE?
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.
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 modifying the DOM in an efficient way. This allows us to use the pure functional style of the MVU pattern whilst still retaining the ability to have a highly performant user interface.

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.

Expand Down
2 changes: 1 addition & 1 deletion docs/components/component-saturn.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Saturn provides the ability to drive your SAFE applications from the server. It
* Hosting of your client-side assets, such as HTML, CSS and any JavaScript files generated by Fable.
* Other cross cutting concerns e.g. authentication etc.

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).
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 seamlessly 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).

```mermaid
flowchart TB
Expand Down
6 changes: 3 additions & 3 deletions docs/faq/faq-troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

You may receive an error when trying to run the app, e.g. the current version might require `{"node":"~18 || ~20","npm":"~9 || ~10"}` but your locally installed versions are different. Ideally we'd like to install different versions side-by-side, which we can do using [Node Version Manager](https://www.freecodecamp.org/news/node-version-manager-nvm-install-guide/).

Once NVM is installed, identify the version of Node that you'd like to install by checking this [matrix](https://nodejs.org/en/download/releases). For our example here we can identify version `20.10.0` as satifying both the Node and npm version requirements. To install this version for the current project run:
Once NVM is installed, identify the version of Node that you'd like to install by checking this [matrix](https://nodejs.org/en/download/releases). For our example here we can identify version `20.10.0` as satisfying both the Node and npm version requirements. To install this version for the current project run:

```
nvm install 20.10.0
Expand Down Expand Up @@ -31,7 +31,7 @@ Whilst these messages can be safely ignored, you can eliminate them by installin

### Node Process does not stop after stopping the VS Code debugger
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
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).
port 8080 and prevent you from 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).

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

Expand All @@ -50,7 +50,7 @@ WARNING in entrypoint size limit: The following entrypoint(s) combined asset siz

We're striving to optimise the bundle size, however with a number of different options and dependencies it's not that easy to stay below the Webpack recommended limit.

To minimize the bundle size in your project you can try restricting browser compatibility by modifying the [Babel Preset targets for Browserslist](https://babeljs.io/docs/en/babel-preset-env#targets) and thus using less polyfills.
To minimize the bundle size in your project, you can try restricting browser compatibility by modifying the [Babel Preset targets for Browserslist](https://babeljs.io/docs/en/babel-preset-env#targets) and thus using fewer polyfills.

For more info, see this [issue](https://github.com/SAFE-Stack/SAFE-template/issues/185).

Expand Down
6 changes: 3 additions & 3 deletions docs/features/feature-azurefunctions.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ For SAFE apps we see various use cases for FAAS:

The [Azure Portal](https://portal.azure.com) allows you to create and edit Functions and their source code via an online editor.

For a short test go to the portal, click the "New" button and search for "Function App". Click through the wizard to create a new Function App. Open the app when it's created and add a new function. Pick "Timer" as scenario and F# as language.
For a short test go to the portal, click the "New" button and search for "Function App". Click through the wizard to create a new Function App. Open the app when it's created and add a new function. Pick "Timer" as the scenario and F# as the language.

Replace the contents of function.json with:

Expand Down Expand Up @@ -50,7 +50,7 @@ and replace the run.fsx with the following F# code:

Now observe the logs to see that the function runs every minute and outputs the message about the meetup duration.

While it seems very convenient, the online editor should only be used for testing and prototyping. In SAFE-Stack you usually benefit from reusing your domain model at various places [see Client/Server](feature-clientserver.md) - so we recommend to use "precompiled Azure Functions" as described below.
While it seems very convenient, the online editor should only be used for testing and prototyping. In SAFE-Stack you usually benefit from reusing your domain model at various places [see Client/Server](feature-clientserver.md) - so we recommend using "precompiled Azure Functions" as described below.

## Deployment
In SAFE-Stack scenarios we recommend all deployments should be automated. Here, we discuss two options for deploying your functions apps into Azure.
Expand All @@ -68,4 +68,4 @@ In the case of a CI server etc., you will need to install the Functions Core Too
### HTTPS Upload
Since Azure Functions sits on top of Azure App Service, the same mechanisms for deployment there also exist here. In this case, you can use the exact same HTTPS upload capabilities of the App Service to upload a zip of your functions app into your Functions app. The standard SAFE Template can generate this for you for the core SAFE application as part of the FAKE script; the exact same mechanism can be utilised for your functions app.

As per the standard App Service, HTTPS upload uses a user/pass supplied in the header of the zip which is PUT into the functions app. This user / pass can be taken from the App Service in the Azure Portal directly, or extracted during deployment of your ARM template (as per the FAKE script does for the App Service).
As per the standard App Service, HTTPS upload uses a user/pass supplied in the header of the zip which is PUT into the functions app. This user / pass can be taken from the App Service in the Azure Portal directly, or extracted during the deployment of your ARM template (as per the FAKE script does for the App Service).
4 changes: 2 additions & 2 deletions docs/features/feature-clientserver-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Reference this project from your server project. You can now reference those typ
Finally, reference this project in your client project (as above). You can now reference those types on the client; Fable will automatically convert your F# types into JavaScript in the background.

## Sharing Behaviour
You can also share behaviour using the same mechanism at that for sharing types. This is extremely useful for e.g shared validation or business logic that needs to occur on both client and server.
You can also share behaviour using the same mechanism as for sharing types. This is extremely useful for e.g shared validation or business logic that needs to occur on both client and server.

Fable will translate your functions into native JavaScript, and will even translate many calls to the .NET base class library into corresponding JavaScript! This allows you to compile your domain model and domain logic to many many different targets including:

Expand All @@ -35,4 +35,4 @@ Fable will translate your functions into native JavaScript, and will even transl
You can read more about this [on the Fable website](http://fable.io/docs/compatibility.html).

## Conditional sharing
When sharing assets between client and server, you may wish to have different implementations for the "client" and "server" sides. For example, if the client-side version of a function should call an NPM package but the server-side version should use a NuGet package. This is a more advanced scenario where you may require different implementations for the JS and .NET version of code. In such situations, you can use `#IF` directives to conditionally compile code for either platform - see the [Fable](https://fable.io/) website for more information.
When sharing assets between client and server, you may wish to have different implementations for the "client" and "server" sides. For example, if the client-side version of a function should call an NPM package but the server-side version should use a NuGet package. This is a more advanced scenario where you may require different implementations for the JS and .NET versions of code. In such situations, you can use `#IF` directives to conditionally compile code for either platform - see the [Fable](https://fable.io/) website for more information.
10 changes: 5 additions & 5 deletions docs/features/feature-clientserver-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,24 @@ let update clientDispatch msg state =
state, Cmd.none
```

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.
The above example mimics what would have been a `GET` request to the server to get user data from a 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.

## When to use Elmish.Bridge
There are many scenarios where it makes sense to use Elmish.Bridge:

* Chat-like applications with many connected users through many channels
* Syncing price data in real-time while viewing ticket prices
* Multiplayer games that need real-time update of game states
* Multiplayer games that need real-time updates of game states
* Other applications of web sockets through an Elmish model

## Things to consider
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.
The biggest distinction between using this and "raw" Saturn is that your web server becomes a stateful service. This introduces several differences in application design.

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.
1. The server state has a lifespan equal to 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.

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.

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.
As of now there is no built-in persistence for the state, but you can implement this yourself using any number of persistence layers such as Redis Cache, Azure Tables or Blobs etc.

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.

Expand Down
2 changes: 1 addition & 1 deletion docs/features/feature-clientserver-remoting.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ async {
}
```

Notice here, there is no need to configure routes or JSON serialization, worry about HTTP verbs, or even involve yourself with the Giraffe pipeline. If you open your browser network tab, you can easily [inspect](https://zaid-ajaj.github.io/Fable.Remoting/#/advanced/raw-http-communication) what remoting is doing behind the scenes.
Notice here, that there is no need to configure routes or JSON serialization, worry about HTTP verbs, or even involve yourself with the Giraffe pipeline. If you open your browser network tab, you can easily [inspect](https://zaid-ajaj.github.io/Fable.Remoting/#/advanced/raw-http-communication) what remoting is doing behind the scenes.
8 changes: 4 additions & 4 deletions docs/features/feature-clientserver-serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

When using basic HTTP communication between the client and server, you'll need to consider how to deserialize data from JSON to F# types.

In order to guarantee that the serialization / deserialization routines between client and server are compatible, you should replace the JSON converter in Giraffe / Saturn with the [Thoth](https://mangelmaxime.github.io/Thoth/index.html) library's serializer. This is the same library as that used in Fable for deserialization, and so will work seamlessly together.
In order to guarantee that the serialization / deserialization routines between client and server are compatible, you should replace the JSON converter in Giraffe / Saturn with the [Thoth](https://mangelmaxime.github.io/Thoth/index.html) library's serializer. This is the same library as that used in Fable for deserialization, and so they will work seamlessly together.

```fsharp
let configureSerialization (services:IServiceCollection) =
Expand All @@ -22,7 +22,7 @@ type Customer =
```

### Automatic Decoders
Automatic decoders are the quickest and easier way to deserialize data. It works by Thoth trying to decode JSON automatically from a raw string to an F# type using automatic mapping rules. In the sample below, we fetch data from the `/api/customers` endpoint and have Thoth create a strongly-typed Decoder for a `Customer` array.
Automatic decoders are the quickest and easiest way to deserialize data. It works by Thoth trying to decode JSON automatically from a raw string to an F# type using automatic mapping rules. In the sample below, we fetch data from the `/api/customers` endpoint and have Thoth create a strongly-typed Decoder for a `Customer` array.

```fsharp
fetchAs<Customer []> "/api/customers" (Decode.Auto.generateDecoder()) []
Expand All @@ -49,7 +49,7 @@ Notice how the decoder is bound to a single Customer, and not an array. This way
Manual decoders give you total control over how you rehydrate an object from JSON. Use them when:

* The JSON does not directly map 1:1 with your F# types
* You want flexibility to evolve JSON and F# types independently
* You want the flexibility to evolve JSON and F# types independently
* You are calling an external service and need fine-grained control over the deserialization process
* You are using F# on the client and another language on the server

Expand All @@ -69,4 +69,4 @@ You can now replace the automatically generated decoder from earlier. You can al
Decode.fromString customerDecoder """{ "id": 67, "customerName": "Joe Bloggs" }"""
```

If decoding fails on any field, an error case will be returned.
If decoding fails on any field, an error case will be returned.
4 changes: 2 additions & 2 deletions docs/features/feature-hmr.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Hot Module Replacement (HMR) allows to update the UI of an application while it is running, without a full reload. In SAFE stack apps, this can dramatically speed up the development for web and mobile GUIs, since there is no need to "stop" and "reload" an application. Instead, you can make changes to your views and have them immediately update in the browser, without the need to restart the application.
Hot Module Replacement (HMR) allows the update of the UI of an application while it is running, without a full reload. In SAFE stack apps, this can dramatically speed up the development of web and mobile GUIs, since there is no need to "stop" and "reload" an application. Instead, you can make changes to your views and have them immediately update in the browser, without the need to restart the application.

## How does it work?
In case of web development, the [Vite](https://vitejs.dev/) development server will automatically refresh the changed parts of your [elmish](https://github.com/elmish/elmish) views whenever you save a file. Alternatively, in the case of mobile app development, this is achieved through [React Native](https://facebook.github.io/react-native/)'s own bundler.
In the case of web development, the [Vite](https://vitejs.dev/) development server will automatically refresh the changed parts of your [elmish](https://github.com/elmish/elmish) views whenever you save a file. Alternatively, in the case of mobile app development, this is achieved through [React Native](https://facebook.github.io/react-native/)'s own bundler.

## Why does it work so well with SAFE?
Since SAFE uses the Model-View-Update architecture with immutable models, the application state only changes when a message is processed; this fits the HMR model very nicely. Here's an example of HMR in action to change the input of a textbox to automatically convert the input to upper case.
Expand Down
Loading