Fork me on GitHub
#beginners
<
2019-11-15
>
conceivably01:11:58

Hi πŸ™‚ I'm want to build an app that has a non-Clojure backend and a ClojureScript frontend. It is my (possibly wrong or naive) understanding that there are two ways of handling deps, packaging, and minification etc. in the frontend – webpack and Leiningen. I can find plenty of information about how to set up both, but it is not clear to me what exactly the trade-offs of either choice are. Leiningen appears to be the default choice, but are there any advantages of using webpack in an app that hopefully won't have to use plain JavaScript (presumably, in that case webpack would be the way to go?)? Thanks.

noisesmith01:11:48

if you aren't using maven for dependencies, leiningen might not be the right tool for deps - it's primarily(?) a dep resolution tool

noisesmith01:11:42

I can't speak to what the best choice is for js, but it would make sense to use a js dep manager for an app with no jvm clojure code beyond the cljs compiler itself

noisesmith01:11:49

I hear shadow-cljs is good

conceivably01:11:22

Ah I suspect my understanding of how the different parts fit together is incomplete and incorrect then. I'll have a look at the tools you mentioned, thank you πŸ™‚

noisesmith01:11:53

it's slightly weird because clojure and clojurescript are each java libraries you would fetch from maven, and lein is the most popular way to manage projects that use clojure

noisesmith01:11:11

it actually launches java with your deps and the entrypoint you ask for

noisesmith01:11:22

(or the implicit one eg. for a repl)

conceivably01:11:00

Hm...upon reading up on it some more, I'm starting to wonder if it makes any sense at all to use ClojureScript in the frontend without a Clojure backend.

tkjone00:11:35

I believe there are benefits: dead code elimination, less tooling, language consistency, immutable state, spec, a stable environment, google closure library…the benefits are significant. I will eventually write a review of the above, but until then you can get a feel for it with https://betweentwoparens.com/start-a-clojurescript-app-from-scratch

noisesmith01:11:33

it's definitely done, but you end up pulling in java + clojure just to run the clojurescript compiler in most cases

noisesmith01:11:37

in your build that is

neo255106:11:44

@conceivably I use CLJS as front end with python Backend, and it has been a joy to develop.

jezy08:11:54

@neo2551 Is there any boilerplate that you know for CLJS, similar to create-react-app?

neo255108:11:10

I would start with shadow-CLJS and the re-frame todomvc

jezy08:11:30

Thank you!

neo255108:11:35

There is also a create CLJS project I don’t really remember

neo255108:11:45

But shadow-CLJS helps a lot

neo255108:11:57

The hard part is the tooling.

jezy08:11:10

That's what I thought πŸ˜‰

regen10:11:47

If you don't want to setup your own tooling https://github.com/filipesilva/create-cljs-app/

jezy10:11:15

Thanks for that.

jezy10:11:22

Will have a look.

jezy07:11:11

Thank you.

byrongibby12:11:49

Hi. I am struggling to get a repl up and running with Leiningen on Windows Server 2019. I keep getting Caused by: java.net.ConnectException: Connection timed out: connect, I've tried a couple of different ports, but no luck. Any ideas? lein ring server is able to get a server up and running without a hitch.

seancorfield19:11:58

@byrongibby Perhaps it's a firewall issue blocking the connection on the nREPL port?

byrongibby19:11:43

@seancorfield Hey. In that case wouldn't it make it impossible to start a server serving off the same port?

seancorfield19:11:20

lein ring server just starts a server process. lein repl starts an nREPL server and client and tries to connect the client (the interactive REPL) to the server (nREPL). I've definitely seen that fail on Windows.

byrongibby19:11:01

Okay, let me do some further research.

seancorfield19:11:18

You may need to specify the host as 127.0.0.1 for lein repl -- I think it may try to bind to 0.0.0.0 by default? Or maybe it's the other way around.

byrongibby19:11:40

I tried both.

seancorfield19:11:47

It may also differ for IPv6 / IPv4 (but it's been years since I worked with lein).

seancorfield19:11:58

(and never much on Windows)

byrongibby19:11:10

You use boot?

byrongibby19:11:24

I will ask IT for assistance, the network guys should be able to help me out if I can adequately describe the problem. Thanks for the help as always.

seancorfield19:11:18

Switched completely to Clojure's CLI/`deps.edn` last year (from Boot -- we'd switched from Leiningen to Boot back in 2015/2016)

seancorfield19:11:03

Also ask in #leiningen -- it's likely a common, known issue on Windows systems (and probably Windows Server specifically).

seancorfield19:11:58

Welcome @tony050!

tony05019:11:51

@seancorfield πŸ‘‹:skin-tone-2:

sova20:11:38

i'm trying to do a simple javascript ajax POST but i keep getting 403 forbidden

sova20:11:57

<script type="text/javascript">
function sendMark( kanji, meaning)
{
	console.log ( kanji, meaning, '{{aft}}');
	var sendMarkData = { 'kanji': kanji,
						 'meaning': meaning,
						 "__anti-forgery-token": '{{aft}}' };
    var xmlHttp = new XMLHttpRequest();
        xmlHttp.onreadystatechange = function()
        {
            if(xmlHttp.readyState == 4 && xmlHttp.status == 200)
            {
                alert(xmlHttp.responseText);
            }
        }
        xmlHttp.open("POST", "/mark-mk"); 
        xmlHttp.send(sendMarkData); 
}
</script>

seancorfield20:11:29

CORS perhaps @sova?

sova20:11:55

Yeah that's my suspicion, I thought adding the anti-forgery-token into sendMarkData would handle tha

seancorfield20:11:16

That's for CSRF tho', CORS is about how your backend handles OPTIONS requests for preflight checks on other actions.

sova20:11:43

I am vaguely aware of preflight checks

sova20:11:45

what does CORS need that I'm not doing? looks like xmlRequest.open and stuff?

seancorfield20:11:53

The browser sends the preflight check automatically. It's purely a backend thing.

seancorfield20:11:35

So your backend needs to support /OPTIONS and respond appropriately. If you're using Ring, add ring-cors as your outermost middleware.

lennart.buit21:11:12

(CORS violations give pretty sizable warnings in your browsers console)

sova23:11:37

I am not getting very much in terms of feedback in the browser so.. yeah I will add ring-cors πŸ˜„

sova23:11:34

so if I'm adding middleware to something like this...

sova23:11:38

(defn -main [ & args]
		(server/run-server (wrap-defaults all-routes site-defaults) {:port 8117})
		(println "server on @ localhost:8117"))

sova23:11:36

Well I wrapped it but I still get a 403 in javascript console

sova23:11:40

fobidden

sova23:11:27

Ah thanks so much y'all! @seancorfield @lennart.buit

sova23:11:32

Sorted it out finally ^.^

sova23:11:17

+CORS + xmlHttp.setRequestHeader('X-CSRF-Token', '{{aft}}')

sova23:11:14

So... I have a vector of maps

sova23:11:30

I'd like to remove the first occurrence of a match on all keys and values...

sova23:11:40

actually it could just match on one k-v, but i'm not sure how to do "remove one" from a vec

sova23:11:57

There's probably a smarter way to lay this problem out

seancorfield23:11:48

If there are multiple matches, you only want to remove the first one and leave the rest in there?

sova23:11:49

it's kinda like I have values that can be A, B, C, D, and they get counted... like 4 As, 4 Ds, 1 B, 1 C, and when I click remove A it should get rid of just one. I suppose keeping a count makes more sense.

sova23:11:47

I have been conj'ing [{m1} {m2} {m3}] and i'd like to remove one of the {m}s if on an identical match, but just one

sova23:11:16

i naively tried something like (swap! jpc-users-atom update-in [email :kanji-stumbles] disj {:kanji kanji :meaning meaning})))

hiredman23:11:29

get a database, stop using a vector

sova23:11:27

come on man let me build my tooth pick skyscraper lol

seancorfield23:11:54

Tooth picks:

user=> (def v [{:a 1 :b 2} {:a 1 :b 3} {:a 2 :b 1} {:a 2 :b 2} {:a 3 :b 3}])
#'user/v
user=> (let [seen (atom false)] (reduce (fn [v m] (if (and (= 1 (:a m)) (not @seen)) (do (reset! seen true) v) (conj v m))) [] v))
[{:a 1, :b 3} {:a 2, :b 1} {:a 2, :b 2} {:a 3, :b 3}]
user=> (let [seen (atom false)] (reduce (fn [v m] (if (and (= 2 (:a m)) (not @seen)) (do (reset! seen true) v) (conj v m))) [] v))
[{:a 1, :b 2} {:a 1, :b 3} {:a 2, :b 2} {:a 3, :b 3}]
user=> (let [seen (atom false)] (reduce (fn [v m] (if (and (= 3 (:a m)) (not @seen)) (do (reset! seen true) v) (conj v m))) [] v))
[{:a 1, :b 2} {:a 1, :b 3} {:a 2, :b 1} {:a 2, :b 2}]
user=> 
πŸ™‚ πŸ™‚

hiredman23:11:34

you basically what the same data available sorted 2 different ways, insertion order and then a composite of your A B C D tags and insertion order

hiredman23:11:22

the insertion order sort mimics the vector, and the sort on tag and insertion order lets you lookup the "first" inserted of each tag

hiredman23:11:49

a database is basically a system that maintains multiple sorts of data for you

sova23:11:02

your point is indisputabo @hiredman ... however i realize that i am making it complex for no reason, i can just store :keyword instead of a map for each entry. i'm not sureally how (not @seen) works up there @seancorfield is it a bitwise comparison of T/F of sorts?

seancorfield00:11:20

@sova Logical negation. seen contains true or false. (not @seen) is therefore false or true respectively.

noisesmith23:11:31

usually if you are using a mutable store as a one-way switch you can use delay or promise and check the realized? status

noisesmith23:11:05

user=> (let [seen (delay true)] (reduce (fn [v m] (if (and (= 3 (:a m)) (not (realized? seen))) (do @seen v) (conj v m))) [] v))
[{:a 1, :b 2} {:a 1, :b 3} {:a 2, :b 1} {:a 2, :b 2}]

noisesmith23:11:02

it looks nicer if you also have (def open? (complement realized?))

noisesmith23:11:12

or whatever name you like for the opposite check