A lightweight alternative template to the full-fledged official SAFE Template. Lowers the entry barrier by choosing the simplest possible opinionated defaults:
- Nuget for package management
- FAKE build script as a console project (see ./build)
- Saturn as server web framework
- Fable.Remoting for client-server communications
- Feliz as the React DSL on the front-end
- Expecto for server unit-tests project
- Fable.Mocha for client unit-tests project (runs in Node.js when on CI servers or live during development)
- Serilog for logging server-side stuff
- Simple application variable configuration (see below sections)
Clone this repository or use it as template via Github UI to get started. Currently there are no plans to publish a separate dotnet template for it.
To work with and develop the application, you need to both the server and the client project running at the same time. The server application is in the server directory and the client is in client directory. To run them both, simply open two shell tabs, each for either applications then:
Shell tab c:\project\simplified-safe Shell tab c:\project\simplified-safe
-------------------------------------- --------------------------------------
> cd server > cd client
> dotnet restore > npm install
> dotnet run > npm startAs shown here below
The server web application starts listening for requests at http://localhost:5000 where as the client application will be hosted at http://localhost:8080 during developments. All web requests made from the front-end are automatically proxied to the backend at http://localhost:5000. In production, there will no proxy because the front-end application will be served from the backend itself.
That is unless you are hosting the backend serverless and would like to host the front-end project separately.
You can easily run the build targets as follows:
./build.sh {Target}on Linux/Macbuild {Target}on Windows- Hitting F5 where
Build.fsprojis the startup project
There are a bunch of built-in targets that you can run:
Serverbuilds the server in Release modeClientbuilds the client in production modeCleancleans up cached assets from all the projectsServerTestsruns the server unit-tests projectClientTestsruns the client unit-tests project by compiling the project first and running via Mocha in node.jsLiveClientTestsruns a standalone web application athttp://localhost:8085that shows test results from the unit tests and recompiles whenever the tests change.Packbuilds and packs both server and client into the{solutionRoot}/distdirectory after running unit tests of both projects. You can run the result application usingdotnet Server.dllin thedistdirectory.PackNoTestsbuilds and packs both server and client projects into{solutionRoot}/distwithout running tests.
NOTE: while inside your IDE, build targets like
Cleanand restore can fail because the IDE locks caches asset files inside ofobjdirectories so soemtimes you have to close the IDE and run the targets from the terminal. Do not run build targets while running the application.
The server web application picks up the environment variables by default from the host machine and makes them available from an injected IConfiguration interface. However, it adds a nice feature on top which allows to add more application-specific local variables by adding a JSON file called config.json inside your server directory:
{
"DATABASE_CONNECTIONSTRING": "ConnectionString",
"APP_NAME": "SimplifiedSafe",
"VERSION": "0.1.0-alpha"
}Just including the file will allow the variables to be picked up automatically and will also be made available through the IConfiguration interface.
Even the client can use build variables. Using the Config.variable : string -> string function, you can have access to the environment variables that were used when the application was compiled. Webpack will pick them up automatically by default. To use local variables other than the environment variables, you add a file called .env into the client directory. This file is a dotenv variables file and has the following format:
KEY1=VALUE1
KEY2=VALUE2
WELCOME_MESSAGE=Welcome to full-stack F#
Then from your Fable application, you can use the variables like this:
Config.variable "WELCOME_MESSAGE" // returns "Welcome to full-stack F#"Since this file can contain variables that might contain sensitive data. It is git-ignored by default.
Since we are using Fable.Remoting in the template, make sure to check out the Functional Dependency Injection article from the documentation of Fable.Remoting that goes through the required steps of injecting services into the functions of Fable.Remoting APIs
