Fork me on GitHub
#clojurescript
<
2019-05-22
>
rickmoynihan09:05:03

I’ve just started looking at clojurescript/react frameworks. A hard requirement is that we have a clojure backend; and I’d like to do SSR with isomorphic components. I’ve got basic SSR going with a clojure backend in rum; and it seems to work as advertised — however rum seems to be locked on a very old react implementation. We also have a FE designer who is writing some components in js/react that we’d like to operate with… and he’d like to be using the latest and greatest react. Has anyone got SSR going with reagent/re-frame but with a clj backend? Am I asking too much?

rickmoynihan09:05:52

Or are there other frameworks that will do this?

Roman Liutikov09:05:11

@rickmoynihan There’s no official way to render Reagent on JVM, but it’s still possible to achieve, see http://yogthos.net/posts/2015-11-24-Serverside-Reagent.html though I’m not aware of anyone going this way

rickmoynihan09:05:57

why not? Does everyone just do SPAs?

Roman Liutikov09:05:16

@rickmoynihan Other option is the library that I’m developing https://github.com/roman01la/uix, it’s based on latest React APIs and supports SSR on JVM. But keep in mind that it’s very much a work in progress, even though I’m using it in a project.

👍 4
rickmoynihan10:05:16

thanks this looks interesting

Roman Liutikov09:05:08

yep, SSR is overrated IMO

rickmoynihan09:05:21

Well I think it would be very useful if it also incorporated a pattern for re-hydrating state API’s via a component oriented backend.

rickmoynihan09:05:45

i.e. if components exist both on the client and server… and components can effectively have their own API

rickmoynihan09:05:29

I know graphql etc is seen as a solution to some of this

rickmoynihan09:05:47

but graphql is kinda annoying if you want to share clojure(script) types on front and backend. As it leads to artificially deep schemas.

borkdude10:05:53

When I compile this code:

(ns cljc.core
  #?(:cljs (:require-macros [cljc.core :refer [foo]])))

#?(:clj
   (defmacro foo [x]
     `(do (println ~x) (println ~x))))

(foo 1)
the output looks very clean:
$ cat out/cljc/core.js
// Compiled by ClojureScript 1.10.520 {:target :nodejs}
1
1
goog.provide('cljc.core');
goog.require('cljs.core');
cljs.core.println.call(null,(1));

cljs.core.println.call(null,(1));
However, when I remove the #?(:clj ...) condition, which is typically not present around macros in .cljc files, I get this:
$ cat out/cljc/core.js
// Compiled by ClojureScript 1.10.520 {:target :nodejs}
1
1
goog.provide('cljc.core');
goog.require('cljs.core');
var ret__4776__auto___545 = cljc.core.foo = (function cljc$core$foo(_AMPERSAND_form,_AMPERSAND_env,x){
return cljs.core.sequence.call(null,cljs.core.seq.call(null,cljs.core.concat.call(null,(new cljs.core.List(null,new cljs.core.Symbol(null,"do","do",1686842252,null),null,(1),null)),(new cljs.core.List(null,cljs.core.sequence.call(null,cljs.core.seq.call(null,cljs.core.concat.call(null,(new cljs.core.List(null,new cljs.core.Symbol("cljs.core","println","cljs.core/println",-331834442,null),null,(1),null)),(new cljs.core.List(null,x,null,(1),null))))),null,(1),null)),(new cljs.core.List(null,cljs.core.sequence.call(null,cljs.core.seq.call(null,cljs.core.concat.call(null,(new cljs.core.List(null,new cljs.core.Symbol("cljs.core","println","cljs.core/println",-331834442,null),null,(1),null)),(new cljs.core.List(null,x,null,(1),null))))),null,(1),null)))));
});
cljc.core.foo.cljs$lang$macro = true;

cljs.core.println.call(null,(1));

cljs.core.println.call(null,(1));
So that cljc.core.foo function is the runtime macro, that’s probably only used for self-hosted CLJS?

borkdude11:05:13

I’m trying to understand why, when you don’t have the #?(:clj ...) condition, CLJS doesn’t see the defmacro call in the CLJS interpretation/phase of the .cljc file as a re-definition. That has probably already been resolved and isn’t around anymore in that stage?

borkdude11:05:46

that’s probably it

mfikes11:05:00

@borkdude In self-hosted ClojureScript, when you require a macros namespace, the Vars in that namespace get put into a synthetically derived namespace name suffixed with $macros. (That's part of how you can have, for example, a macro and function with the same name without any collisions.)

borkdude11:05:02

@mfikes oh right. so what’s the use of var ret__4776__auto___545 = cljc.core.foo in the generated code above?

borkdude11:05:55

@mfikes but this code isn’t self-hosted, maybe can be omitted from “normal” programs? I don’t have a $macros namespace

mfikes11:05:58

@borkdude Yeah, perhaps CLJS-2015 could even be revised to generate less code under self-hosted

mfikes11:05:30

@borkdude Are you saying that defmacro could generate different code for JVM ClojureScript in the case that it happens to be used in JVM ClojureScript?

borkdude11:05:06

@mfikes let’s just say that I don’t understand at all why the code at var ret__4776__auto___545 = cljc.core.foo is needed in the cljc.core namespace when compiling with regular CLJS (non-self-hosted)

borkdude11:05:12

maybe I’m just missing something

mfikes11:05:39

@borkdude Is the question related to the use of defmacro in ClojureScript code when using JVM ClojureScript?

borkdude11:05:39

yes. with #?(:clj ...) (first example) you don’t get that code. why do I get it when I omit that conditional, and does it ever get used somewhere

borkdude11:05:50

(afk for 30 minutes)

mfikes12:05:49

I suppose what happens when you use defmacro in a runtime namespace in ClojureScript code is undefined.

mhuebert12:05:43

@mfikes I was interested to see your work re: supporting macros from cljs (chivorcam). one thing I was thinking about awhile back for maria was whether it would make sense to (via some evil, for-REPL-only means) let these self-hosted macros read functions that are accessible from their “non-macro” namespace, rather than something like defmacfn. eg if we (defmacro x ...) in cljs.user, we define it in cljs.user$macros, but perhaps also walk defmacro and resolve names in the context of cljs.user.

mhuebert12:05:24

(I’m not sure if this would cause any unexpected issues)

mfikes12:05:47

Yeah. I introduced defmacfn because I was actually exploring the general concept "why can't we intermix macros and functions in ClojureScript" (JVM-based). I think many of the arguments you see against it are incorrect, and part of chivorcam was to just try it and see empirically where things go, and let it stand as a proof that you can have them intermixed, apart from some leftover issues. defmacfn gets to the core of the grey area right away. But, you are right, if you start off assuming that you are in self-hosted ClojureScript, then the notion that you can have intermixed macros and function (just like Clojure) is completely feasible (IMHO), because self-hosted ClojureScript behaves like Clojure in important ways.

4
mhuebert12:05:31

I like the exploration.

mfikes12:05:08

It would be nice to say, "Not only can you intermix defmacro and defn in your ClojureScript namespaces, you don't even need support from the compiler to do it. You can just use a library. How do you like them Lisp apples?"

mhuebert12:05:25

it seems.. possible? I’ve been using macrovich quite a bit, sometimes in .cljc namespaces where I don’t do any host interop and just want to define macros that I use within the same namespace

mfikes12:05:27

By the way, Replete ships Chivorcam, so it is possible to play with it in the limited way it works. Replete prompts you before enabling it, because it is a non-standard thing 🙂

mfikes12:05:52

Yeah, a large class of macros are "clean"

mfikes12:05:08

I think that Rich could have defined ClojureScript as mixing macros and functions for that limited subset.

mhuebert12:05:31

that makes sense to me

mhuebert12:05:12

ie. using the JVM from a macro could be the special case that requires extra work

mfikes12:05:55

I would love to see what Rich's take on the whole thing is. I wouldn't be surprised if he said "yeah, we definitely could have mixed macros and functions for certain scenarios, but at the time we were trying to cleanly separate compile time and runtime, and the solution we ended up with is the pragmatic one that we could pull off at the time"

mfikes12:05:13

It is definitely an evergreen subject. And you often see responses regarding why it can't be done. With chivorcam we have a better feel for the specific areas where the "why" arguments hold water.

borkdude12:05:42

@mfikes what’s a runtime namespace, a namespace defined in the REPL?

mfikes12:05:11

Yeah, it might be good to precisely define that term, but to me the informal notion is the normal CloureScript namespaces you have that define functions that live on into runtime.

mfikes12:05:40

This is in contrast to macro namespaces that define macros for use at compile time.

mfikes12:05:14

An attempt to formally define it gets into that staged, Racket-inspired terminology .

borkdude12:05:04

I guess with :advanced the unused code gets cut away by Closure anyway

mfikes12:05:08

Maybe another stab at it is the distinction between require and require-macros

mfikes12:05:14

Oh, yeah, if you use defmacro in a ClojureScript runtime namespace, one thing that also helps is that the Var constructor is eliminated.

mfikes12:05:53

Try plk -co '{:def-emits-var false}' -v -r and create a macro and you'll see

mfikes12:05:41

(Or simply set :def-emits-var false as a compiler option in your favorite ClojureScript REPL.)

mfikes12:05:28

It looks like :advanced doesn't get rid of all of it.

mfikes12:05:22

I end up with some detritus left over that it doesn't seem to eliminate:

(function(){var a=cljs.b.a=function(){return null};cljs.b.a.c=!0;return a})()

scknkkrer15:05:30

Hey guys. I have a really simple question.

scknkkrer15:05:00

I wanted to create an Desktop Application with Clojurescript And Reagent --and react-- with Descjop template. This template has really strange cljsbuild format. But I want to import external libraries with Webpack. I can build and import my Webpack bundle result. This result can be included. But. I know, Reagent depends on cljsjs.react. And I know that I also have to exclude this dependency from Reagent. But I have to tell the Google Clouse that I have already a React Library in my project. If I didn’t make a mistake; :foreign-libs key is meant to be used for this purpose. But. I didn’t make this work. I have a dead-line for a simple prototype. Can someone tell me what is my mistake ? Thank you all.

scknkkrer15:05:40

This is my Electron App’s Console prints: ` index.html:8 Uncaught ReferenceError: process is not defined at index.html:8 (anonymous) @ index.html:8 index.html:9 Uncaught ReferenceError: process is not defined at index.html:9 (anonymous) @ index.html:9 invariant.js:24 Uncaught ReferenceError: process is not defined at invariant.js:24 (anonymous) @ invariant.js:24 warning.js:7 Uncaught ReferenceError: process is not defined at warning.js:7 (anonymous) @ warning.js:7 canDefineProperty.js:5 Uncaught ReferenceError: process is not defined at canDefineProperty.js:5 (anonymous) @ canDefineProperty.js:5 emptyObject.js:5 Uncaught ReferenceError: process is not defined at emptyObject.js:5 (anonymous) @ emptyObject.js:5 ReactComponent.js:36 Uncaught ReferenceError: process is not defined at ReactComponent.js:36 (anonymous) @ ReactComponent.js:36 ReactPropTypeLocationNames.js:5 Uncaught ReferenceError: process is not defined at ReactPropTypeLocationNames.js:5 (anonymous) @ ReactPropTypeLocationNames.js:5 ReactDOMFactories.js:10 Uncaught ReferenceError: process is not defined at createDOMFactory$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactDOMFactories (ReactDOMFactories.js:10) at module$Users$sckn$projects$business$qulak$desktopnew$node_modules$fbjs$lib$mapObject.default (mapObject.js:11) at ReactDOMFactories.js:16 createDOMFactory$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactDOMFactories @ ReactDOMFactories.js:10 module$Users$sckn$projects$business$qulak$desktopnew$node_modules$fbjs$lib$mapObject.default @ mapObject.js:11 (anonymous) @ ReactDOMFactories.js:16 ReactPropTypes.js:29 Uncaught ReferenceError: process is not defined at createChainableTypeChecker$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactPropTypes (ReactPropTypes.js:29) at createPrimitiveTypeChecker$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactPropTypes (ReactPropTypes.js:69) at ReactPropTypes.js:17 createChainableTypeChecker$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactPropTypes @ ReactPropTypes.js:29 createPrimitiveTypeChecker$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactPropTypes @ ReactPropTypes.js:69 (anonymous) @ ReactPropTypes.js:17 React.js:30 Uncaught ReferenceError: process is not defined at React.js:30 (anonymous) @ React.js:30 DOMProperty.js:54 Uncaught ReferenceError: process is not defined at DOMProperty.js:54 (anonymous) @ DOMProperty.js:54 ReactDOMComponentTree.js:12 Uncaught TypeError: Cannot read property 'ID_ATTRIBUTE_NAME' of undefined at ReactDOMComponentTree.js:12 (anonymous) @ ReactDOMComponentTree.js:12 EventPluginRegistry.js:64 Uncaught ReferenceError: process is not defined at EventPluginRegistry.js:64 (anonymous) @ EventPluginRegistry.js:64 ReactErrorUtils.js:22 Uncaught ReferenceError: process is not defined at ReactErrorUtils.js:22 (anonymous) @ ReactErrorUtils.js:22 EventPluginUtils.js:38 Uncaught ReferenceError: process is not defined at EventPluginUtils.js:38 (anonymous) @ EventPluginUtils.js:38 EventPluginHub.js:37 Uncaught TypeError: Cannot read property 'injectEventPluginOrder' of undefined at EventPluginHub.js:37 (anonymous) @ EventPluginHub.js:37 EventPropagators.js:17 Uncaught TypeError: Cannot read property 'getListener' of undefined at EventPropagators.js:17 (anonymous) @ EventPropagators.js:17 SyntheticEvent.js:99 Uncaught ReferenceError: process is not defined at SyntheticEvent.js:99 (anonymous) @ SyntheticEvent.js:99 SyntheticCompositionEvent.js:10 Uncaught TypeError: module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$SyntheticEvent.default.augmentClass is not a function at SyntheticCompositionEvent.js:10

scknkkrer15:05:14

This is my Electron App’s Console Print;

scknkkrer15:05:37

index.html:8 Uncaught ReferenceError: process is not defined
    at index.html:8
(anonymous) @ index.html:8
index.html:9 Uncaught ReferenceError: process is not defined
    at index.html:9
(anonymous) @ index.html:9
invariant.js:24 Uncaught ReferenceError: process is not defined
    at invariant.js:24
(anonymous) @ invariant.js:24
warning.js:7 Uncaught ReferenceError: process is not defined
    at warning.js:7
(anonymous) @ warning.js:7
canDefineProperty.js:5 Uncaught ReferenceError: process is not defined
    at canDefineProperty.js:5
(anonymous) @ canDefineProperty.js:5
emptyObject.js:5 Uncaught ReferenceError: process is not defined
    at emptyObject.js:5
(anonymous) @ emptyObject.js:5
ReactComponent.js:36 Uncaught ReferenceError: process is not defined
    at ReactComponent.js:36
(anonymous) @ ReactComponent.js:36
ReactPropTypeLocationNames.js:5 Uncaught ReferenceError: process is not defined
    at ReactPropTypeLocationNames.js:5
(anonymous) @ ReactPropTypeLocationNames.js:5
ReactDOMFactories.js:10 Uncaught ReferenceError: process is not defined
    at createDOMFactory$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactDOMFactories (ReactDOMFactories.js:10)
    at module$Users$sckn$projects$business$qulak$desktopnew$node_modules$fbjs$lib$mapObject.default (mapObject.js:11)
    at ReactDOMFactories.js:16
createDOMFactory$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactDOMFactories @ ReactDOMFactories.js:10
module$Users$sckn$projects$business$qulak$desktopnew$node_modules$fbjs$lib$mapObject.default @ mapObject.js:11
(anonymous) @ ReactDOMFactories.js:16
ReactPropTypes.js:29 Uncaught ReferenceError: process is not defined
    at createChainableTypeChecker$$module$Users$sckn$projects$business$qulak$desktopnew$node_modules$react$lib$ReactPropTypes (ReactPropTypes.js:29)
    at 

scknkkrer15:05:49

And it goes on like that.

Jimmy Miller15:05:17

If you can post the source I sure that will make it easier for people to be able to help you. But this seems related to the issue you are having. https://github.com/electron/electron/issues/18139

scknkkrer15:05:41

I think I have to done this with my win Object. I have changed it like this;

(reset! *win* (BrowserWindow. (clj->js {:width 800 :height 600 :webPreferences {:nodeIntegration true}})))

scknkkrer15:05:16

I’m about the uploading it to the github. Give me a couple of minutes.

scknkkrer15:05:26

@U5K8NTHEZ here is the source. I haven’t change it much. https://github.com/LeaveNhA/ElectronProblem

scknkkrer15:05:36

I’m all alone with my LTE Connection. I’m sorry for the delay. It’s still uploading.

Jimmy Miller16:05:02

Shutdown your app. run lein descjop-once-dev search app/dev/js/cljsbuild-main.js and make sure it has "nodeIntegration" somewhere in it. Then rerun the app

Jimmy Miller16:05:19

It looks like you have a stale compile from before you added that flag.

Jimmy Miller16:05:43

Also *var* is a convention for dynamic variables. You should remove the earmuffs there.

scknkkrer16:05:46

I’ve just resolved my problem. But, I don’t know how.

Jimmy Miller16:05:54

Hopefully that is helpful.

scknkkrer16:05:10

I have close everything. Stoped Repl. Closed Spacemacs. Closed iterm.

scknkkrer16:05:27

Start everything I’ve needed from stracth.

scknkkrer16:05:12

@U5K8NTHEZ, I’m living in Turkey. It is nice to meet you. Thank you. One day, if you come to Turkey. Write to me.

👍 4
jstaab19:05:11

Hey everyone, I just watched "Expeditious Code via Inference" by Mike Fikes (https://www.youtube.com/watch?v=tPnCtXrwvIw), and immediately went to my project to try it out. I'm on the latest version of shadow-cljs (2.8.37), which uses cljs version 1.10.520, but I'm not seeing all the type warnings that I would expect. Of the following forms:

(+ "a" 1)
(let [x "a"] (+ x 1))
(+ (fn [] 1) "a")
(#(+ % 1) "a")
((fn [x] (+ x 1)) "a")
Only the first three give me warnings. Is there no checking across function signature boundaries? Is there something I need to do to turn checking on? Is there any documentation I can read about what to expect and rely on? Is this relevant: https://clojurescript.org/reference/compile-time-type-checking?

mfikes19:05:13

@jstaab You'd get a warning if, for example you did

((fn [^string x] (+ x 1)) "a")

mfikes19:05:08

But, you don't otherwise, as the compiler doesn't know the type of the function argument x. (It's not looking that you are calling it with a literal string, right there inline.)

mfikes19:05:52

In other words, (fn [x] (+ x 1)) is legitimate, from a static analysis perspective

mfikes19:05:09

If you are curious:

cljs.user=> (defn foo [x] (+ x 1))
#'cljs.user/foo
cljs.user=> (foo "a")
WARNING: Type mismatch calling foo: expected [number], got [string] instead at line 1 <cljs repl>
"a1"
This is produced using https://gist.github.com/mfikes/1e2341b48b882587500547f6ba19279d which is the parameter type inference experiment I mentioned in the talk.

jstaab19:05:36

@mfikes thanks for that link, that clears things up a ton. I was wondering why the unsolved problems (changing function dependencies) were mentioned so casually! Any idea if/when this will land in clojurescript? Thanks for your work on it!

mfikes19:05:51

@jstaab Are you referring to the "calcification" problem?

mfikes19:05:25

I don't know. I don't even think a JIRA has been written for it, TBH.

jstaab19:05:52

I didn't realize it was quite so bleeding edge, this article (https://blog.klipse.tech//clojure/2019/05/20/type-inference-in-clojurescript.html) made it sound like a new feature

jstaab19:05:09

gotcha, that must be where I got confused

mfikes19:05:26

But general type inference has been in the compiler since about a year after it was first released.

jstaab19:05:32

of course, I started using cljs in earnest about that time, so I wasn't aware of the change

jstaab19:05:49

I think I remember seeing more warnings at one point early on, shrugged and kept on

mfikes19:05:09

Yeah, the numeric type check warnings you referred to above are from 2013. They've been around for a while 🙂

jstaab19:05:00

Yep, thanks for clearing that up!

johnj23:05:25
replied to a thread:yep, SSR is overrated IMO

SPAs are overrated 😜