This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-10-10
Channels
- # babashka (37)
- # babashka-sci-dev (22)
- # beginners (16)
- # biff (12)
- # calva (40)
- # cider (6)
- # clj-kondo (7)
- # clojure (183)
- # clojure-austin (20)
- # clojure-doc (22)
- # clojure-europe (16)
- # clojure-nl (2)
- # clojure-norway (39)
- # clojure-romania (1)
- # clojure-uk (9)
- # clojuredesign-podcast (9)
- # clojurescript (29)
- # core-typed (66)
- # cursive (19)
- # data-science (14)
- # docker (5)
- # fulcro (6)
- # hyperfiddle (46)
- # java (5)
- # malli (19)
- # missionary (3)
- # off-topic (84)
- # pedestal (5)
- # portal (36)
- # reitit (35)
- # releases (2)
- # shadow-cljs (30)
- # web-security (2)
- # yamlscript (1)
I followed the starter app deploy on fly. The health check fails with insufficient memory available
. Is
fly scale vm shared-cpu-4x
still enough to run electric?our starter app runs on shared-cpu-1x@256MB. Our examples app (https://electric.hyperfiddle.net/) runs on shared-8x-cpu@2048MB
are you using a database? you may need to tune memory settings for your database
ram is basically free i would just add more ram
Also please post the full error with context? It could be a Fly issue, we hit random Fly issues often, search the forum. Fly issues can even be region specific
fly seems to be flaky as you said. I redeployed and reached the max restart count. Will experiment with the scaling values
max restart count implies the app didn't come up and it retried N times
check for exceptions in log
is there any documentation for hfql? i can run the demo app and here's what i see. seems like there's more to it but i can't get anything else to show up.
you're right that there's more to it, Geoffrey developed a lot of functionality that isn't visible in the basic demo. Unfortunately HFQL is currently parked while we're busy with other work
Support for map meta data in e/defn
I think that the following legal defn syntax is not supported by electric:
(e/defn F {:f 2} []
(dom/div (dom/text "foo")))
This fails with this error:
; Encountered error when macroexpanding hyperfiddle.electric/boot.
; Failed to analyse form
; {:in [(hyperfiddle.electric/fn F {:f 2} [] (dom/div (dom/text "foo")))]}
; ExceptionInfo: Failed to analyse form
; hyperfiddle.electric.impl.compiler/analyze-form (compiler.clj:706)
; hyperfiddle.electric.impl.compiler/analyze-form (compiler.clj:690)
; hyperfiddle.electric.impl.compiler/eval23168/analyze--23174/fn--23179/fn--23180 (compiler.clj:759)
; hyperfiddle.electric.impl.compil ....
Should this be supported with electric?It’s true we forgot to implement it. We will add it. Thank you for the report. In the meantime this works:
(e/defn ^{:f 2} F [] …)
generally speaking be careful with metadata and electric clojure, we do not transfer metadata and it is not checked by clojure.core/= which is used by the reactive propagation engine to decide if a computation can be skipped
We considered transferring metadata between client/server, but declined to because it can result in very difficult to debug issue: if the metadata contains an unserializable reference, you'll get an unserializable reference transfer but have no clue to help debug it. Some libraries put weird shit in metadata
We propose that there is no valid use case for userland runtime metadata (due to the value equality issue), so let us know if you find one
Plus it sucks in Clojure anyway, every time I have tried to do something interesting with it the edge cases were too severe
Thanks for your answers. I am currently working on a routing feature. The routing table is statically compiled and to do that I store the needed data as meta data on the var. I am not done yet. Usage will look like this :
(defrouter Home [primary-email]
{:segment ["home"]}
(dom/div (dom/text (str "Hello " primary-email ", welcome to Aeditto Backend."))))
(defrouter NotFound []
{:segment ["not-found"]}
(dom/div (dom/text "not found")))
(defrouter Settings []
{:segment ["settings"]}
(dom/div (dom/text "settings")))
(defrouter Nested []
{:segment ["nested"]
:targets [(Settings)]}
(dom/div (dom/text "nested"))
)
(defrouter Root [primary-email]
{:segment [""]
:root true
:initial [`Home {}]
:targets
[(Home primary-email)
(Nested)]
:not-found (NotFound)})
;
(e/defn [] (new Root ""))
(route-relative `Settings)
Metadata on the vars looks like this:
{::Bar
{:segment ["bar" :id],
:targets []},
::Bar2
{:segment ["bar2"],
:targets []},
::Foo
{:segment ["foo"],
:targets [[::Bar :id "arg"]
[::Bar2 "some arg"]]},
::Stay
{:segment ["stay"],
:targets []},
::NotFound {:segment ["not-found"],
:targets []},
::Root {:root true,
:targets [[::Foo 42]
[::Stay]
[::NotFound]],
:not-found ::NotFound,
:segment [""]}}
Do you think that meta data is the wrong way to do this?@U023LKF2PQV Interesting thought with an “Electric native” router. Though Reitit works very well with Electric: https://cljdoc.org/d/metosin/reitit/0.7.0-alpha7/doc/frontend/browser-integration, so unless there’s some specific motivation to write your own, you could use it for your routing needs.
I must admit, that I never took a closer look into reitit frontend integration. Despite the fact that my version uses reitit under the hood 😄 . Usage of my version is very closely to how you would use routing in Fulcro. Including the ability to prevent routing e.g if you want to react to unsaved data etc... I am not sure how I would achieve this with reitit frontend integration. Do you have an example of reitit frontend integration and electric?
I don’t have time to clean this up as much as I should, and it’s a) in an early stage, and b) got domain-specific stuff in there. I’ve cut out lots of stuff, but you’ll get the gist I bet. Throw out the stuff that doesn’t resolve.
The important bit is that router
is a reactive var that gives you a stream of route matches.
(ns app.electric.router
(:require
[hyperfiddle.electric :as e]
[reitit.coercion :as coercion]
[reitit.coercion.malli :as malli-coercion]
[reitit.core :as reitit]
[reitit.frontend.easy :as rfe]))
(defn- route-path
[kind]
(str "/" (namespace kind) "/:uuid"))
(def entity-coercion
{:coercion malli-coercion/coercion
:parameters {:path {:uuid uuid?}}})
(def routes
(reitit/router
[["/" home-name]
[(route-path account/id)
(merge entity-coercion
{:name account/id})]
[(route-path atom/id)
(merge entity-coercion
{:name atom/id})]
[(route-path prototype/id)
(merge entity-coercion
{:name prototype/id})]
[(route-path space/id)
(merge entity-coercion
{:name space/id
:handler (fn [{:keys [entity]}]
(reset! context/sidebar-selection-atom entity))})]
["/debugger/:etype/:uuid" {:name :debugger}]]
{:compile coercion/compile-request-coercers}))
(e/def router
"Returns a flow of route matches, for subscription in Electric."
(->> (m/observe
(fn start!
[!]
(rfe/start! routes (fn route!
[{:keys [data] :as match} _history]
(let [match (add-entity match)
handler (get data :handler helpers/nil-fn)]
;; Run the handler
(handler match)
;; Save ff-params
(reset! ff-query-params
(select-keys (get match :query-params) [:ff]))
;; Return match to stream
(! match)))
{:use-fragment false})))
(m/relieve {})
new))
(defn route-to-entity!
[entity]
(rfe/push-state (->key entity) {:uuid (->value entity)} @ff-query-params))
(defn route-to-root!
[]
(rfe/push-state home-name nil @ff-query-params))
Almost everything in route!
can go away, except for ! match
which is what returns successive navigations. (handler match)
might be nice to keep if you’re looking to do a side-effect upon navigating to a certain route.
As you can see, Reitit supports coercions, which you accidentally have an example of in there. If you have stuff that should be coerced to integers, UUIDs, whatever, they are nice.
for the record, i think our internal position is that Clojure hanging debug metadata on vars is OK, it's userland metadata that we don't like
example : having a http request library return the result object and hanging the http headers as object metas – bad idea, return a tuple
I think there’s some confusion about what’s appropriate metadata vs. just plain data as well.
the point is it will not be seen during equality checks inside the propagation engine, so if you depend on it in any capacity in userland you're gonna be unhappy
@U06B8J0AJ Thanks for sharing. I think my version could improve from rfe. There are some differences: rout-data [["/" {} ...]]
in my code is automatically build at compile time and I have no single top level subscription. There is one for each nested router, which results in a minimal diff of the dom
How much of your dom changes will have to do with how you choose to react to router
matches though. If you have some nested routing logic of [page [sub-page [sub-sub-page]]]
or similar, it’s just a matter of how you choose to parse your match.
Return matches where
{:page x
:sub-page y
:sub-sub-page z}
for example, and the app logic can choose to react to those, or not.
Of course, you can (and probably should) abstract somewhat over pure Reitit, but I don’t think it’ll lead to better or worse re-rendering.The main point of the Fulcro co-locating this with the components is more of a DX decision than a performance decision as far as I can tell. Not that there isn’t potentially merit to that.
Anyone care to brainstorm SEO strategies for electric app? Am thinking http://prerender.io might be good. Or might jut build a parallel set of components in cljs/rum and then host those at actual endpoints, to be overridden by electric app on page load
My best theory so far is to make parallel components using tonksy's rum and then embed the electric components into a larger page of rum components. Probably the right way forward. One thing i'm not sure about is putting more divs into the index.html for the rum asset to override, i reckon it would work as planned.
yes. we need a version of (dom/...) that renders to hiccup or whatever! genius! i guess that is painfully obvious now that i reflect! 😅
I wouldn’t mind a raise lol. Maybe I’ll be able to get one if I make electric sing and dance and make me more productive :)
Basically need to turn (dom/...) into string builder append append append like in tonsky's rum SSR https://github.com/tonsky/rum/blob/gh-pages/src/rum/server_render.clj to me it seems like a good approach
Other idea: instead of rendering directly to the browser DOM, render to an org.w3c.dom instance (jvm), then use the built in methods to get an html string out of it. Who knows, there might also be a way to get a stream of html chunks to stream to a browser 😉