Coder Social home page Coder Social logo

fab's Introduction

FAB Re-Frame Starter Project

[Fenton](https://github.com/ftravers) and [Alex’s](https://github.com/aeberts) re-frame starter project.

This is a full-stack, single-page application starter project based on re-frame and Datomic Free. The goal of this project is to explore a modern clj/cljs-centric web application architecture and to serve as a solid base project that can be used to quickly prototype ideas. This readme not only serves as a guide to using the project but also as a repository for notes, background and rationale for the choices we made during development.

This is being developed on MacOS and Linux and while it may work on Windows, there are no plans to officially support it (sorry).

Getting Started

Development Setup

Install the dependencies in <a href=”#environment-setup”>environment setup</a>

Install the javascript project dependencies: “`npm install“`

Install the shadow-cljs cli

Run the development environment: “`shadow-cljs watch app“`

Wait to see the line: `[:app] Build completed.`

To get a clojure repl simply connect to the nrepl server running on port 8777

To get a clojurescript repl connect to a clojure repl and then in the repl run the following command:

“`clojurescript (shadow.cljs.devtools.api/nrepl-select :app) “`

Production Setup

TBD

Deployment to Heroku

TBD

Features

  • Hot Code Reloading (via shadow-cljs)
  • Configuration Management
  • Other TBD

Environment Setup

<a name=”environment-setup”/>

  1. Install [JDK 8 or later](https://openjdk.java.net/install/) (Java Development Kit)
  2. Install [Leiningen](https://leiningen.org/#install) (Clojure/ClojureScript project task &

dependency management)

  1. Install [Node.js](https://nodejs.org/) (JavaScript runtime environment) which should include [NPM](https://docs.npmjs.com/cli/npm) or if your Node.js installation does not include NPM also install it.
  2. Install [karma-cli](https://www.npmjs.com/package/karma-cli) (test runner): “`sh npm install -g karma-cli “`
  3. Install [Chrome](https://www.google.com/chrome/)
  4. Install [Datomic Free](https://my.datomic.com/downloads/free)
  5. Install [clj-kondo](https://github.com/borkdude/clj-kondo/blob/master/doc/install.md) (linter)
  6. Clone this repo and open a terminal in the `fab` project root directory
  7. (Optional) Download project dependencies: “`sh npm install “`

Project Architecture

What follows is a detailed explanation of each component of the system. The goal is to provide enough information so that a beginner Clojure(script) web developer can understand the responsibilities of each component in this system and be able to swap them out with libraries of their own choosing if necessary.

The tech stack below was chosen based on the following criteria:

  • Support for modern (bleeding edge?) technologies and protocols (which may mean that it is not supported by all browsers)
  • Clojure and Java-centric choices (i.e. choose good Clojure(script) options when available e.g. Transit vs JSON)
  • Where possible prefer options that are data-oriented and declarative in nature (i.e. “say what should be done” vs. “do what I say”)
  • Use simple, modular components where possible to make substitution of modules easier
  • Use components that favour ease of use over performance (i.e. ones that don’t require extensive configuration and work ADOBE)

<add architecture diagram>

Build Tools

Leiningen

shadow-cljs

shadow-cljs allows easy use of javascript libraries without having to provide “externs” files. The primary maintainer of shadow-cljs Tomas Heller (@thheller) is very active in maintaining shadow-cljs and pushes useful new features regularly.

Other development benefits of shadow-cljs are:

  • hot code reloading
  • cljs inspectors
  • cljs-devtools provides some enhancements for cljs developers using Chrome:
  • Better formatting of cljs values in Chrome’s DevTools console
  • More informative exceptions
  • Long stack traces of async calls

Web Server: HTTP-Kit

What is a Web server?

Most developers know what a web server is and how it works but bear with me, the discussion below is relevant and Clojure(script) related.

A web server is designed to store and deliver web pages to browsers (a.k.a. “Clients” or “User Agents”) via HTTP. Web servers can refer to the physical hardware that responds to HTTP requests or the software running on a physical server somewhere. While the type of hardware your server is running on is important for performance we’re mostly interested in the web server software and how it interacts with you Clojure(script) application.

Eric Normand did a great write-up of Clojure web servers here: https://purelyfunctional.tv/mini-guide/clojure-web-servers/

Peter Taoussains published some benchmarks of the major clojure web servers here: https://github.com/ptaoussanis/clojure-web-server-benchmarks/tree/master/results The benchmarks are 5 years old but the results are still interesting and relevant.

While not the fastest of java or clojure web servers we chose http-kit for this project because it is simple to use, supports the Ring spec, has limited dependencies and can be extended to support more exotic configurations.

What is this Ring thing and do we need it?

If you are exploring developing web applications in Clojure you will no doubt have run across references to Ring. But what is Ring and why should I care about it? Ring is Clojure web application library which abstracts the details of HTTP into a simple Clojure API. You can think of Ring as more of an interface or specification of the components that are needed for a web application. The full spec is on Github, if you’re interested in the details. The benefit of using Ring is that libraries that implement the Ring specification are modular and can all work together.

Other Web Server Options:

Pedestal/Jetty (http://pedestal.io/index)

Pedestal/Jetty is another great web server option for Clojure apps but we went with http-kit for this project because it’s a little simpler to configure out of the box and has fewer dependencies.

Application Server

Simple clojure applications do not need a separate application per-se. The clojure code in clj and cljc files is called by handlers from the web server (in our case http-kit) and returns responses to the client via the web server. The clojure application is started by the “traditional” methods i.e. via leiningen.

System Lifecycle Management : Integrant

Note: Integrant support is not yet implemented

What is system lifecycle management? (SLM)

Any client / server system contains multiple components: servers, databases, application servers, etc. Even in small systems, these separate components must be supplied with a particular configuration and started and stopped in a particular order. System lifecycle management libraries are useful to orchestrate the startup and shutdown of these separate compoents.

There are many clojure-based SLM libraries available (Integrant, Component, Mount, Duct, etc.) - what responsibilities do they have and how do they work?

(TBC)

Why did we choose Integrant?

  • Regularly maintained
  • Declarative and data-driven
  • Dependencies are resolved from the configuration before the system is initialized

Back-End Router: Reitit (TBC)

What is a back-end router?

A back-end router is part of your application server and is the component that decides how to respond to web requests received from a client (for example the the client application running in a browser). Back-end routers can respond to simple “static” routes which respond to urls that have no additional details (e.g. “http://yoursite.com/home”) or more complicated “dynamic” routes where details are provided (e.g. “http://yoursite.com/users/42”). Back in the “old days” of the internet when web pages were mostly rendered on the server, back-end routers translated inbound web requests into application logic, fetched whatever data was required, filled in HTML templates with the data and returned the response to the client browser to be displayed.

As web applications became more interactive, more of the work for rendering the client UI was done in the client browser.

Why do I need a back-end router?

What features does a back-end router need to have?

What are the “nice to have” features of a back-end router?

Why did we choose reitit as our back-end routing library?

What other options are there?

“A small routing library for Ring”

Secretary

Bidi

Clerk

Accountant

Back-End Database: Datomic

(TBD)

Front-End Router: Reitit (TBC)

What is a front-end router?

Single Page Applications (SPAs) often only have one back-end route which supplies a simple index.html file and the applications javascript files. The application’s UI and all logic is rendered by a javascript library in the browser (e.g. React) and the back-end is mostly responsible for other tasks such as interacting with databases or 3rd-party services (e.g. like marketing mail servers). In practice, front-end routers are primarily responsible for managing what views an application renders when the user requests a particular URL. There are other

A front-end router is responsible for:

  • Interpreting or “resolving” URIs
  • Handling the case where the user clicks the browser’s “back” or “forward” buttons
  • Managing HTML5 pushState

What features does a front-end router need to have?

(TBD)

What are the “nice to have” features?

Why did we choose reitit as our front-end routing library?

What is HTML5 pushState?

Front-End UI Framework : Re-frame

(TBD)

Deployment : Heroku

  • Push to git repo on Heroku and you’re done.
  • Free tier available
  • Supports custom domains

Testing

(TBD)

Todo’s

AE find out what dev-after-load (reagent thing)

`after-load` is a shadow-cljs lifecycle hook which tells shadow-cljs to load a function before or after hot-code loading.

`before-load` ensures that the function loads before hot-code reload and `after-load` loads the function after.

(defn ^:dev/before-load stop []
  (js/console.log "stop"))

(defn ^:dev/after-load start []
  (js/console.log "start"))

AE there is a circular reference problem with main-page view?

FT Get shadow FE working with Cider.

Works on Alex’s machine to test on Fenton’s machine

(ns fab.router
...
   {:use-fragment true}))

AE make links/nav work with reitit

have a link on home page to another page, and back again.

AE Get history (back/forward) buttons working push state

use-fragment = false…

AE shadow-cljs command to build production

(for integration with heroku deployment)

Target: must be able to create a *.js file somewhere (advanced compilation?), so can be served up in production.

AE get tracing working for production, stubs.

AE setup local-prod

We have three envs (at least): dev, local-prod, deploy-prod (remote, real)

FT checkout logging with transducers for application

where they keep the last 3 states, for a function call.

KILL AE Fix bad navigation does 404 or something…

Not sure what the issue is here…

AE coercion is breaking page??

(ns fab.router [reitit.coercion.spec :as rcs]

Removed and page still works

Meeting: May 26, 2020

Agenda

Check in ShadowCLJS and FT to test on his side

Discussion:

Issue Tracking

  • Consider putting bugs into Github issue tracker at some point.

Meeting: May 24, 2020

Agenda

AE to demo reitit

FT Share AERO config, secrets.edn for storing passwords etc…

Meeting Minutes

Discussions

Web Server

AE likes http-kit. FT heard rumors about it… options: http-kit.

Decision: Stick with Ring/Jetty until more of the base is solidified.

http-kit: pure clojure solution, supports WebSockets. pedestal: batteries included (framework-y), too heavyweight. ring-jetty: doesn’t support WebSockets out-of-the-box.

BE Routing

Compojure maybe but doesn’t support WebSockets. Reitit seems better and works FE/BE. Mostly setup for FE.

Decision: Stick with Reitit for now

Decisions

Web Server:

Stick with Ring/Jetty but try to move towards http-kit.

Future Agenda Items

A testing story FE&BE.

bring together shadow & heroku

Integrate everything that we have ATM.

FE get cider working with shadow

FE/BE ??? Authentication

Testing FE/BE

fab's People

Contributors

aeberts avatar dependabot[bot] avatar ftravers avatar

Watchers

 avatar  avatar  avatar

Forkers

ftravers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.