|
| 1 | +This article shows the steps required in order to create a SAFE Stack 5-style app from scratch. [This repository](https://github.com/CompositionalIT/safe-from-scratch) should be used as a guide to follow whilst reading this tutorial; each section links to a specific commit from the [history of the repository](https://github.com/CompositionalIT/safe-from-scratch/commits/main/). |
| 2 | + |
| 3 | +## 1. Folders and tools |
| 4 | +This first section creates some basic folders and tools that will simply coding going forwards and represents some best practices. |
| 5 | + |
| 6 | +### 1.1 [Create a basic source-controlled repository](https://github.com/CompositionalIT/safe-from-scratch/commit/eef17c091ac66e65c02e15267c6327ccb9e848c1) |
| 7 | +* Create a new folder. |
| 8 | +* Put the folder under source controlled: |
| 9 | +```bash |
| 10 | +git init |
| 11 | +``` |
| 12 | +* We recommend also creating a `.gitignore` file to ensure that you do not accidentally commit unnecessary files into your repository. *[This example file](https://github.com/CompositionalIT/safe-from-scratch/blob/main/.gitignore) has been generated through VS Code and fine-tuned with extra files / folders required for SAFE Stack applications.* |
| 13 | + |
| 14 | +### 1.2 [Set up basic tooling support](https://github.com/CompositionalIT/safe-from-scratch/commit/21e62db348f6f58046558053313e93338003b7b6) |
| 15 | +* Create standard dotnet tooling support with \`dotnet new tool-manifest`. |
| 16 | +* Install the Fantomas tool for F# formatting. |
| 17 | +```bash |
| 18 | +dotnet tool install fantomas |
| 19 | +``` |
| 20 | +* We also recommend creating an `.editorconfig` file which configures Fantomas as required for optimal F# formatting. |
| 21 | +* You should also create a basic [`global.json` file](https://github.com/CompositionalIT/safe-from-scratch/blob/main/global.json) to pin the repository to a specific version of .NET. |
| 22 | +```bash |
| 23 | +dotnet new global.json |
| 24 | +``` |
| 25 | + |
| 26 | +## 2. Creating client & server |
| 27 | +Now that we have basic core tools installed, we can go about creating a basic F# server and client and get them communicating with one another. |
| 28 | + |
| 29 | +### 2.1 [Create a basic server application](https://github.com/CompositionalIT/safe-from-scratch/commit/90b4fcb6ef948886bb872b3b24d3e5a9d21ecdc0) |
| 30 | +* Create a folder e.g. `server`. |
| 31 | +* Create a plain F# console application |
| 32 | +```bash |
| 33 | +dotnet new console -lang F# |
| 34 | +``` |
| 35 | +* Reference the Giraffe NuGet package (if you wish to use Paket, feel free to install that tool at this point). |
| 36 | +* Create a basic Giraffe application to e.g. simply return the text "Hello world!" for every request. |
| 37 | +* Run the application and confirm that it returns the expected text. |
| 38 | +```bash |
| 39 | +dotnet run |
| 40 | +``` |
| 41 | + |
| 42 | +### 2.2 [Create a basic client application](https://github.com/CompositionalIT/safe-from-scratch/commit/0c05a1022357b5dd3b2a43d8f3738dcff161b6b4) |
| 43 | +* Create a folder e.g. `client`. |
| 44 | +* Create another plain F# console application in it. |
| 45 | +* Add the Fable dotnet tool. |
| 46 | +* To prove that Fable is installed, you should now be able to transpile the stock "Hello from F#" console app into JavaScript. |
| 47 | +```bash |
| 48 | +dotnet fable |
| 49 | +``` |
| 50 | + |
| 51 | +### 2.3 [Create a basic web application](https://github.com/CompositionalIT/safe-from-scratch/commit/ac025b31ab49506a8a6199e80ac0825147e21b95) |
| 52 | +Now that we have a running HTTP server and the ability to create JS from F#, we can now install the required browser libraries and tools required to host a full app in the browser. |
| 53 | + |
| 54 | +* Create an `index.html` file that will be used as the launch point for the web application; it will also load the JS that is generated by Fable. |
| 55 | +* Install Vite with npm (install NPM and Node if you haven't already!). |
| 56 | +```bash |
| 57 | +npm install vite |
| 58 | +``` |
| 59 | +> Vite is a multi-purpose tool used to aid development and packaging of JavaScript applications. |
| 60 | +* You can now launch the application. |
| 61 | +```bash |
| 62 | +dotnet fable watch -o output -s --run npx vite` |
| 63 | +``` |
| 64 | + This command tells Fable to compile all F# into the `output` folder and then launches Vite, which acts as a local development web server. |
| 65 | + |
| 66 | +* You should see output in your terminal similar to this: |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | +* Browse to the Local URI displayed e.g. `http://localhost:5173` in your browser and view the console output using the dev console (normally `F12`). You should see the console output from your client's `Program.fs` e.g. |
| 71 | +
|
| 72 | + |
| 73 | +
|
| 74 | +### 2.4 [Set up basic Client / Server communication](https://github.com/CompositionalIT/safe-from-scratch/commit/a14a7c9ca117da3b00da4187c6a68bd1cba0b5a3) |
| 75 | +Now that we have running client and server F# applications, let's have them communicate with each other over HTTP. We'll use a basic library for this called SimpleHttp. |
| 76 | +
|
| 77 | +* Start by adding a configuration file for Vite, `vite.config.mts` which will tell it to redirect traffic destined for the server (which we assume always starts with `/api/`) to port 5000 (which is the port the server runs on). |
| 78 | +> See [here](faq/faq-build.md) for more information about this redirection process. |
| 79 | +* Add a simple button to the HTML which we will be using handle the "on click" event to communicate with the server. |
| 80 | +* Add the **Fable.SimpleHttp** package to the Client project. |
| 81 | +* Change your Client `Program.fs` to handle the on-click event of the button so that when it is clicked, it makes a request to e.g. `/api/data` and puts the response in the console and a browser alert. |
| 82 | +* Start **both client and server applications**. |
| 83 | +* Confirm that when you click the button in the browser, you get the response "Hello world" (sent from the server). |
| 84 | + |
| 85 | +
|
| 86 | +Congratulations! At this stage, you have a working F# client / server application that can communicate over HTTP. |
| 87 | +
|
| 88 | +## 3. Adding React |
| 89 | +We now spend the next few steps getting React working within the app and with F# support. |
| 90 | +
|
| 91 | +### 3.1 [Add basic React support](https://github.com/CompositionalIT/safe-from-scratch/commit/0b331ad76fdc59442bf8024d4300ae1073a20715) |
| 92 | +Now that we have a (very) basic F# client/server app, we'll now add support for React - a front-end framework that will enable us to create responsive and rich UIs. |
| 93 | + |
| 94 | +* Add the `react` and `react-dom` packages to your NPM dependencies. |
| 95 | +* Add the `@vitejs/plugin-react` and `remotedev` packages to your NPM dev dependencies. |
| 96 | +* Add react to the list of plugins in your vite config. |
| 97 | + |
| 98 | +### 3.2 [Add F# React support](https://github.com/CompositionalIT/safe-from-scratch/commit/1409820300e2b09db11003c077ff3e2c82f6d9d2) |
| 99 | +Now that we have React added to our application, we can add the appropriate F# libraries such as Feliz to start to use React in a typesafe, F#-friendly manner. |
| 100 | + |
| 101 | +* Add the Feliz NuGet package to the Client project. |
| 102 | +* Remove the `<button>` element from the `index.html` - we'll be creating it dynamically with React from now on. |
| 103 | +* Add an empty `<div>` with an named `id` to the body of the `index.html`. This will be the "root" element that React will attach to from which to make HTML elements. |
| 104 | +* Using the Feliz React wrapper types, replace the contents of your `Program.fs` in the Client project so that it creates a React button that can behave as the original static HTML button. |
| 105 | +
|
| 106 | +### 3.3 [Add JSX support *(optional)*](https://github.com/CompositionalIT/safe-from-scratch/commit/78e4093502ec4b8281ec5c14f113e3ad14b4a6f6) |
| 107 | +This next step adds Feliz's JSX support, which allows you to embed standard React JSX code directly in your F# applications. |
| 108 | + |
| 109 | +* Add the Fable.Core and Feliz.Jsx.React NuGet packages to the Client project. |
| 110 | +* Instead of using the Feliz F# dialect for React components (such as the `button []` element), use standard JSX code with string interpolation. |
| 111 | +* Reference `Program.jsx` instead of `Program.js` in your `index.html` file. |
| 112 | +* Run the client application using the extra flag that instructs Fable to emit `.jsx` instead of `.js` files: |
| 113 | + |
| 114 | +```bash |
| 115 | +dotnet fable watch -o output -s -e .jsx --run npx vite |
| 116 | +``` |
| 117 | + |
| 118 | +## 4. Taking advantage of F\# |
| 119 | +This next section takes advantage of F#'s typing for both client and server. |
| 120 | +
|
| 121 | +### 4.1 [Add type-safe Client / Server communication](https://github.com/CompositionalIT/safe-from-scratch/commit/0e47e2fd3d56c6213474dc1af485fa8077375b3a) |
| 122 | +* **On the Server**: |
| 123 | + * Add the **Fable.Remoting.Giraffe** package. |
| 124 | + * Create a new folder, `shared`, and a `Contracts.fs` file inside it. |
| 125 | + * Reference this file from both Client and Server projects. |
| 126 | + * Inside this file create an API type and a Route builder to be used by Fable Remoting (so that client and server can route traffic). |
| 127 | + * On the Server, create an implementation of the Api you just defined, convert it to an Http Handler and replace the `text "Hello world"` call with it. |
| 128 | +* **On the Client**: |
| 129 | + * Add the **Fable.Remoting.Client** package. |
| 130 | + * Instead of using SimpleHttp to make client / server calls, create a Fable Remoting API proxy and use that. |
| 131 | +
|
| 132 | +### 4.2 [Add Elmish support](https://github.com/CompositionalIT/safe-from-scratch/commit/1e39a36133ee26c18ddb4f08c11858b33cbaeea1) |
| 133 | +Elmish is an F# library modelled closely on the Elm language model for writing browser-based applications, which has popularised the "model-view-update" paradigm. |
| 134 | +
|
| 135 | +* Add the **Fable.Elmish.Debugger**, **Fable.Elmish.HMR** and **Fable.Elmish.React** packages. |
| 136 | +* Create a set of standard model, view and update types functions. |
| 137 | +* Update your basic application root to use Elmish instead of a "raw" ReactDOM root. |
| 138 | +* Ensure you add the required polyfill for remotedev in `index.html`. |
| 139 | +
|
| 140 | +## 5. More UI capabilities |
| 141 | +This last section adds more UX capabilities. |
| 142 | +
|
| 143 | +### 5.1 [Add Tailwind support](https://github.com/CompositionalIT/safe-from-scratch/commit/fb8b8d02ac4b9b8e97292af23bf37bcee917daff) |
| 144 | +Follow the [Tailwind](ui/add-tailwind.md) guide to add Tailwind to your project. |
| 145 | +### 5.2 [Revert to "standard" F# Feliz](https://github.com/CompositionalIT/safe-from-scratch/commit/ce4705c5d497cbebf91ea2e4f74dbd0345901e28) *(optional)* |
| 146 | +If you do not want to use the JSX support: |
| 147 | +
|
| 148 | +* Remove references to Feliz.JSX |
| 149 | +* Do not use `JSX.jsx` to create components but rather standard `[ReactComponent]`. |
| 150 | +* Use the standard Feliz types for creating standard React elements such as `div` and `button` etc. |
0 commit comments