This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-05
Channels
- # adventofcode (95)
- # announcements (3)
- # babashka (11)
- # beginners (39)
- # boot (19)
- # bristol-clojurians (1)
- # cider (32)
- # clj-kondo (39)
- # cljsrn (8)
- # clojure (156)
- # clojure-dev (35)
- # clojure-europe (4)
- # clojure-italy (15)
- # clojure-nl (28)
- # clojure-spec (43)
- # clojure-uk (153)
- # clojurescript (168)
- # core-async (13)
- # core-logic (11)
- # cryogen (4)
- # cursive (13)
- # datomic (26)
- # duct (3)
- # emacs (8)
- # fulcro (33)
- # garden (4)
- # graalvm (18)
- # graphql (4)
- # jobs-discuss (2)
- # kaocha (1)
- # leiningen (3)
- # malli (8)
- # off-topic (1)
- # pathom (7)
- # re-frame (21)
- # reagent (3)
- # rewrite-clj (1)
- # schema (4)
- # shadow-cljs (40)
- # sql (2)
- # uncomplicate (3)
Hey All, How do I use the Garden library to generate the CSS and then include it in my project? I understand (css [:h1 {:font-weight "bold"}]) will output the appropriate CSS string, but how do I create a CSS file from this and include it in my ClojureScript project? I'm using shadow-cljs as my build tool
If you generate CSS strings on the frontend, I think you have to explicitly create a <script>
tag dynamically with the desired content and add it to the body.
If you generate CSS strings on the backend, you can include them in your HTML, however you serve it. Or you can just cache it and serve as a CSS file.
I'm quite new at this, but bumped up against this recently.
The way I solved it was just using plain scss files and have a yarn build:sass
script in my package.json that runs something like: yarn sass --load-path node_modules/ sass/main.scss:resources/public/css/main.css
Now, in the html file (resources/html, for me) I added the following line somewhere: {% style "/css/main.css" %}
Et voila! I don't know about Garden, but presumably it has the equivalent of the sass command somewhere to generate the css.
Hope that helps!
With Garden, the process would be similar iff you have static CSS. If you need to generate some particular CSS during the runtime, you cannot use such approach. All in all, depends on what OP needs, yeah.
@UR71VR71S We're using lein-jsass and it's working well.
Oo, that does look good. Thanks @U0HJJF9A4!
i recently "upgraded" an old project using promesa
to it's newest version, but the await
function seems to have been removed
i have code like this (p/let [resp (p/await (send-http-request! ...))] (decode-response resp))
that is no longer valid due to p/await
missing
last time this topic came up (and promise usage comes up a fair bit), my take away is that yeah you can just go core-async but the initial macro to do it isn't very accessible to newcomers
https://clojure.atlassian.net/browse/ASYNC-230 tracks making that more acessible
you can find it as a lib in https://github.com/filipesilva/async-interop
i might as well take the time to rewrite the entire http API to use http-fx with re-frame instead, then these pain points are nicely abstracted away
I remember someone mentioned it was removed from promesa
because there were broken corner cases
but I don't know the real reason, or have a link to the removal
Does anyone here used schema before?
I would like to create one for maps within a map
If you are going to use a react component lib with regent, reframe
such as blueprintjs
, does the constant interop with JS
kill the perf and dev experience or converting between cljs and js is fast enough?
I've being happily interop'ing with semantic-ui-react for about a year. In terms of dev experience, a lot of hiccup looking like:
[:> ui/Item {:on-click #(rf/dispatch [:b/nav-product-detail product-idstr])}
[bc/c-product-logo logo]
[:> ui/ItemContent
[:> ui/ItemHeader {:class "shorten"}
pname]
[:> ui/ItemExtra {:class "product-tags shorten"}
[bc/c-categories product]]]]
Looks ok, what about data side? Esp. if you have frequent(10hz?) json incoming you have to convert to clojure do sth type then back to json does that have too much overhead? Any numbers I could find?
Many of my components are connected to graphql subscriptions over websockets from hasura passed through re-frame subs to update in realtime. Working well, but I don't have hard data.
If you encounter performance problems while handling JSON data (or even before that), consider using https://github.com/mfikes/cljs-bean or https://github.com/binaryage/cljs-oops
If you want to just embed some static data that's available during compilation, I would just write a Clojure macro.
I’m very new to clojure. What would that look like, and what’s the advantage of doing it that way?
I ended up just doing (def myJson (js/require "../path/to/my.json"))
which seems to work just fine for loading it as a js object
Ah, so your platform is Node.js? At least to my knowledge, that's the only place where js/require
works.
require
is usable on almost all JS platforms these days. It isn’t implemented in the browsers but almost all js apps are built using bundlers these days which do support import/require and many other features which are compiled down to browser compatible code. In this case I’m using react-native.
To be honest, I don't know that much about ES5-style, ES6-style, CommonJS-style imports/requires. Although I would argue that a bundler is not a part of a platform. It can do whatever it wants. In your case, since it works just fine, I would say that using it is just fine as well.
Out of curiosity, what would using a macro look like? I don’t understand clojure macros well enough to understand why they would be useful for static data.
Macro expansion is done in Clojure, the expanded code is the ClojureScript code, that is then transpiled into JavaScript for the target platform. Suppose my target platform is browser. Ideally, I want to supply a single JS file that has all of the required information needed to for the app to start. Suppose, that JSON must be part of this information. I would then write a macro that looks something like this, I suppose (not tested):
(defmacro static-json [path]
(core/list 'js* (slurp path)))
It would be used something like this:
(let [data (static-json "path/to/data.json")]
(do-something-with data))
During the macro expansion phase, the (static-json ...)
part would turn literally to what the JSON file contains. Because of the 'js*
used in the macro, it would be treated as a JS statement so ClojureScript won't turn it into a ClojureScript map.I've done something like this to turn e.g. a static SVG into a Hiccup data simply because I needed to manipulate it before displaying it.
Hey all, I'm having some issues with http libraries in cljs, for some reason I can't access a given endpoint no matter what I do
Usually it's a cors error
But setting a cors header that might fix it is forbidden
And when I access the endpoint from postman or Dev tools it works fine
Even with the same headers
It's driving me crazy lol
I assume that's because none of the dev tools actually check for CORS. I don't think there's any reasonable way to make it work in a browser without changing the relevant headers on the server.
It's weird because I believe that JavaScripts fetch will get a response but some reason xhrio doesn't like this endpoint / server configuration for those endpoints?
I think because fetch can set headers xhrio can't?
NBA.js works for NBA endpoints essentially but for some reason I can't replicate the same in cljs
Yes I ran NBA.js in node
Yes in the browser
But in the Dev tools as well when I resend the request with the same headers that the original xhr request uses it returns a correct response, I don't understand why
Unfortunately not right now but perhaps later
For instance in the network tab, I see a given xhr request that my cljs has, if I press (resend request) it'll work?
(ns ^:figwheel-hooks tylerherro-io.core
(:require
[goog.dom :as gdom]
[httpurr.client :as http]
[httpurr.client.xhr :refer [client]]
[promesa.core :as p]
[reagent.core :as reagent :refer [atom]]))
(def stat-req-p (http/send! client
{:method :get
:url ""
:headers {}
}))
Because running a plain fetch
on this URL doesn't work for me because of CORS, just as expected.
I'll just double check, one moment 😄
So in Firefox under the network tab essentially I can look at my xhr requests and resend them.
Host:
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Origin:
Connection: keep-alive
Referer:
Pragma: no-cache
these are the headers
Well OK, you did send out the request. But were you able to get the response and access it?
@U2FRKM4TW only after a resend via the dev tools, the request made by my cljs app returns nothing essentially
I know
I know firefox must be doing something internally that doesn't mirror what CLJS is doing
perhaps it's sending with a different origin?
Can you send me a screenshot that contains the response that you see in the dev tools?
the valid response?
Heh, I can't check anything right now because the URL has completely stopped working for me - it just hangs here and time outs.
yeah, without headers etc it'll just hang
idk why
it's very weird lol
tbh the NBA api in general is just tough to work with, I just wanted a toy problem to learn some CLJS haha
I thought when my app would start it'd just do a GET to a given API and display the data nicely basically
but I guess maybe a given client can't do this, I don't know. I don't know the different between say a client running code and a general browser request
My current guess is that you can view the response in Firefox, but you cannot actually use it in the code. The browser just won't let you because of CORS. NodeJS doesn't enforce CORS, that's why requests work there.
Ahh..
gotcha
because Node is a server-side language? or is it arbitrary?
I guess maybe clojure itself can make the request but not CLJS perse?
or does clojure enforce it as well (CORS)?
Because it's server side, yeah. CLJS is a language, not a platform. You can have a CLJS app that runs on Node for example.
@U2FRKM4TW via shadow-cljs? (CLJS on Node)
and yh, that's true
but say for example, cljs aside, I wanted to write a given clojure api that needed to make a GET request, would that have CORS?
I know it's kinda backwards but couldn't I myself have a given endpoint that just goes to that other endpoint with CORS ignored?
I'm being a bit dishonest here. De facto it's the platform that matters. But nothing prevents a particular language having a CORS check in its standard library (although, you would still be able to just not use the library and issue requests some other way).
@U2FRKM4TW gotcha, so in theory I could use some low-level stuff to form a XHR request without a CORS check?
You could use shadow-cljs for that, sure. Although I don't think it's necessary. You can make any requests from Clojure! So yeah, you can write an endpoint that proxies your requests just to deal with CORS. I'm not sure about low level stuff in browser. I think it would work only if you can open raw socket connections from browser, and I don't think you can.
@U2FRKM4TW nice, I guess the proxy endpoint would be the way to go then!
sounds like fun!
@U2FRKM4TW what's a nice way to go about writing a clj API, the ring library?
It's the default choice for many, yeah. But if you want to just test your CLJS code, you just need to proxy a request, replace some request headers, and remove a bunch of response headers - you don't need CLJ for this. There should be plenty of already written tools for this. It's fine if you just want to play around with CLJ and learn a bit though.
@U2FRKM4TW which tools? I tried modifying headers but somehow google's xhrio library is used by most http libs?
This, for example: https://github.com/Rob--W/cors-anywhere/
@U2FRKM4TW can I use JS libraries in cljs?
Sure! Consider using shadow-cljs for this since it makes it much easier, especially if you need NPM.
so I've decided to use shadow-cljs but where exactly would I write javascript or can I somehow interop with javascript in cljs?
Even when I proxy it through cors-anywhere I get "Missing required request header. Must specify one of: origin,x-requested-with"
when I try to set origin it says I cannot set a forbidden header
You cannot do it from the browser alone. You have to use some sort of proxy.
cors-anywhere
doesn't work probably because the server requires additional headers. Although it's strange that it doesn't detect Origin
because it should be the one responsible for CORS as well. Have you tried setting x-requested-with
manually?
shadow-cljs will not help you with CORS in any way. It's just a build tool. But it's a good one and it makes JS interop much more simpler and robust, especially when you use NPM libraries.
yes I tried x-requested-with but I guess https://funcool.github.io/httpurr/latest/ doesn't allow me to set it
You're trying to solve a problem by changing multiple things at once. Try just using raw JS.
yeah I think I should yh
raw JS with fetch?
gotcha
fetch cannot set a origin header for a request?
for some reason fetch form a OPTIONS request
but if I resend in the browser with GET as the method I get a valid JSON response
I'm not setting Origin
oops, I forgot to delete Origin from my fetch request fields lol, one sec
async function getData(url = '', data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'omit', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
'x-requested-with': 'XMLHttpRequest'
},
redirect: 'follow', // manual, *follow, error
referrer: ' ' // no-referrer, *client
});
return await response.json(); // parses JSON response into native JavaScript objects
}
getData("")
If you dispatch a request from some backend platform, likely it won't be in your way and will just send the request as is. Meaning, it will add only the stuff you ask it to add. If you dispatch a request from a not horribly outdated browser, it will do all sorts of stuff for you. Set origin, set cookies, check CORS etc.
oh I understand
damn HTTP is real complicated lol, so many layers
but I did read in MDN that it'll do a preflight OPTIONS request sometimes
I guess because it's cross-origin? I don't know
I guess I should try to make the request from a backend then..
uh oh, there's more!
crazy stuff..
It's like this technology is vastly important and useful and has been around for ages or something. 🙂
but I guess it's the browser that makes it complicated
not the protocol perse?
I don't mind the complexity as long as it's tractable or can be abstracted nicely
HTTP protocol has not been of interest in this discussion at all. CORS is a mechanism on top of HTTP. Browsers just follow the rules to implement CORS.
oh ok
why is it that a server can set headers explicitly but not a client?
For security reasons. You can use a random website that can be malicious. You usually don't use a random server.
Okay, that makes sense.
Thanks for the help, I know I am a little slow let's say 😄
One day I hope I can have this knowledge but I guess it's years of experience away perhaps
I was hoping I could find a clojure job in the future but this is like finding a unicorn perhaps haha
Not really. It depends on what you end up doing. Or on what you want to do. Knowing HTTP and all of the related stuff maybe useful for some, but it's not that helpful for someone that e.g. writes desktop software.
that's true
hmm, that's a good point
Even for web development, the vast majority of what there is to know can be more or less safely skipped simply because "it just works".
I guess my toy problem is actually a little advanced in the respect it doesn't just work haha
because the NBA API is little more less client friendly?
Probably. I have never had to deal with CORS at all - I have never needed my frontend to load someone else's resources that have been protected with CORS. Maybe someday I will, I don't know.
okay so I got an API that provides a nice response ;D
question is, how do I begin deploying something like this to heroku?
:thumbsup:
Will do