{"id":13764509,"url":"https://github.com/dam5s/fsharp-react-starter","last_synced_at":"2025-05-10T19:31:18.919Z","repository":{"id":47512443,"uuid":"371812771","full_name":"dam5s/fsharp-react-starter","owner":"dam5s","description":"A starter application with examples of common architecture and testing patterns.","archived":false,"fork":false,"pushed_at":"2021-08-25T16:47:45.000Z","size":1212,"stargazers_count":16,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-05T17:16:50.860Z","etag":null,"topics":["fable","fsharp","react","redux"],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dam5s.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-28T20:34:04.000Z","updated_at":"2024-11-15T22:52:12.000Z","dependencies_parsed_at":"2022-09-23T12:03:49.228Z","dependency_job_id":null,"html_url":"https://github.com/dam5s/fsharp-react-starter","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dam5s%2Ffsharp-react-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dam5s%2Ffsharp-react-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dam5s%2Ffsharp-react-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dam5s%2Ffsharp-react-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dam5s","download_url":"https://codeload.github.com/dam5s/fsharp-react-starter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253470797,"owners_count":21913735,"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":["fable","fsharp","react","redux"],"created_at":"2024-08-03T16:00:21.857Z","updated_at":"2025-05-10T19:31:18.474Z","avatar_url":"https://github.com/dam5s.png","language":"F#","funding_links":[],"categories":["Examples"],"sub_categories":[],"readme":"# F# React Starter App\n\nThis small application is here to demonstrate how I would start a React frontend\napplication for a customer using [F#](https://fsharp.org) + [Fable](https://fable.io) + [Feliz](https://zaid-ajaj.github.io/Feliz/).\n\n## Things that I look for in a codebase\n\n * Can be Test Driven (encourages me to write code that is simple to test)\n * Easy to expand without increasing complexity\n * Easy to change\n * Confidence I'm not breaking things\n\n## Techs used\n\n * [.NET 5](https://dotnet.microsoft.com/download)\n * [F# 5](https://fsharp.org)\n * [Fable](https://fable.io)\n * [Feliz](https://zaid-ajaj.github.io/Feliz/)\n * [Jester](https://shmew.github.io/Fable.Jester/)\n\n## Redux/Elm style Architecture\n\nI really really like Elm and Elmish, but there are a couple things \nthat make it a bit more tedious to use on large projects.\nWhen the project grows big, it requires a fair amount of work to \"componentize\" the codebase.\n\nFor instance, if I wanted to have an app made of 10 different pages with their own state plus some shared state,\nit requires a lot of wiring by passing down functions to components for wrapping/unwrapping messages...\n\nOne things that's nice in Redux, it doesn't enforce the action type that is dispatched. While this removes some type safety,\nit also adds a lot of flexibility. In particular, different reducers can have their own Action type and not worry about\nwrapping them into an App-Level Action type before dispatching.\n\nAnother thing inherent to React is that it's easy to have components that don't care about Redux,\nthose components can have children that do care about it but they don't have to pass things down.\n\n### Important Redux related files\n\n * [Frontend/src/Prelude/Redux.fs](Frontend/src/Prelude/Redux.fs) for the generic `StateStore` implementation\n * [Frontend/src/StateStore/Main.fs](Frontend/src/StateStore/Main.fs) for the top-level declaration of the application's `stateStore`\n * [Frontend/src/Components/StoreProvider.fs](Frontend/src/Components/StoreProvider.fs) for the React provider of the application `stateStore`, it depends on the above for extra type-safety.\n * [Frontend/src/App.fs](Frontend/src/App.fs) where it gets initially configured\n * [Frontend/src/Components/JokePage.fs](Frontend/src/Components/JokePage.fs) where it's used\n\n## Networking and testing\n\nI believe there is no need to stub the networking layer when testing a webapp. Even for testing.\nIt is so easy these days to quickly spin up a local HTTP server that I would rather do that instead.\n\nThe advantage of doing that is that you can choose whatever implementation you want, the testing remains\nthe same. It makes refactoring of your networking layer a lot easier!\n\nFor the implementation I simply use Javascript's `fetch` function,\nduring tests I import `whatwg-fetch` as a polyfill for the NodeJS runtime.\n\n### Important Networking related files\n\n * [Frontend/src/Networking/Http.fs](Frontend/src/Networking/Http.fs) for the base implementation of sending a request for JSON or not.\n * [Frontend-tests/src/TestingSupport/MockWebServer.fs](Frontend-tests/src/TestingSupport/MockWebServer.fs) for the test version of an HTTP server.\n * [Frontend-tests/src/Components/JokePage.test.fs](Frontend-tests/src/Components/JokePage.test.fs) for example tests.\n\n## Building/Deploying to multiple environments\n\nHaving worked extensively on backends, I am used to being able to build my application once on CI then deploying\nit to different environments by just changing configuration through Environment Variables and/or a configuration server.\n\nExternal source: [The Twelve-Factor App](https://12factor.net/config)\n\nI find it extremely important that the CI system builds one artifact, runs tests against that artifact\nand that same artifact is what is deployed everywhere. In the case of javascript applications that run in the browser,\nI want to run my highest level tests against the result of my webpack build.\n\nIn this case I made the webpack build produce two separate artifacts, the application and the environment. This way,\nwhen I want to deploy to a different environment, the environment artifact is the only one I need to change.\n\n### Important Environment related files\n\n * [Frontend/webpack.config.js](Frontend/webpack.config.js) defines the two separate entries.\n * [Frontend/src/env.js](Frontend/src/env.js) defines my default environment config.\n * [Frontend/src/Env.fs](Frontend/src/Env.fs) provides access to the environment.\n * [Frontend-tests/src/TestingSupport/TestEnv.fs](Frontend-tests/src/TestingSupport/TestEnv.fs) to configure the environment during tests.\n\n## TODO\n\n * Backend\n * Backend rendering?\n * End-to-end testing with Cypress\n * Fake build\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdam5s%2Ffsharp-react-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdam5s%2Ffsharp-react-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdam5s%2Ffsharp-react-starter/lists"}