Fork me on GitHub
#shadow-cljs
<
2019-08-14
>
Quest03:08:12

I want to do a xhrio GET against another service I'm running on local during development. The shadow-cljs server is at localhost:8280, and as a result any attempts to run an async HTTP request (GET http://google.com for instance) are forced to the same uri.

GET  404 (Not Found)
Since shadow-cljs is the thing serving the page during development, how can I get it to include the CORS headers? I noticed that it has some code to do this at https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/cljs/devtools/server/web/api.clj#L180 , but I'm not clear on how to get it to activate

Quest03:08:51

the default re-frame template using +handler will allow you to bring a server up on localhost:3000, but it doesn't seem possible to hit

thheller08:08:14

@quest that is not how CORS works. the server answering the request has to include CORS headers. not the server serving the initial page.

thanks2 4
Quest15:08:20

Ah, I was quite confused then. I thought the initial page would be responsible for "setting permissions" in this case -- thank you for educating my dense self 😅

Quest19:08:03

Got it working. Notes in case a future person sees this: • Make sure to include the protocol in the GET requests from your client - ex: • If you're using Ring on the serverside, you can use ring-CORS https://github.com/r0man/ring-cors • If you're using Aleph with Compojure (my case), see https://github.com/muhuk/aleph-middleware Your routes should look like so:

(def handler
  (-> (compojure/routes
       (GET "/"         [] root-handler)
       (GET "/healthz" [] healthcheck-handler)
       (route/not-found "No such page."))
      (middleware.cors/wrap-cors :access-control-allow-methods #{:get}
                                 :access-control-allow-headers #{"content-type"}
                                 :access-control-allow-origin #"[\s\S]+")
      (params/wrap-params)))
Note the #"[\s\S]+" regex -- this matches any incoming request, but you can also use it to limit the origin. tested with [aleph "0.4.6"], [aleph-middleware "0.2.0"], [ring-cors "0.1.10"], [compojure "1.6.1"]

thheller19:08:05

why are you adding CORS when you are running the server anyways?

thheller19:08:16

just have that server serve the .js files that shadow-cljs has generated

Quest19:08:00

Mainly lack of expertise in getting the tooling setup -- the origin server is Boot based & I'm not sure how to correctly integrate all of the clientside re-frame-template into it, plus getting cider-jack-in-cljs working with it. Though it sounds like I could blindly have the Boot webserver serve the client's resources/index.html from the filesystem?

Quest19:08:36

Hmm. I'll give that a shot then, definitely cleaner than CORS-ing everything for development mode. The dev-http-proxy would also work fine, but seems like a less clean solution.

thheller19:08:57

yeah its purely there for convenience in case you don't control the server

thheller19:08:09

but if you do it is best to just use that server to serve the files

thheller19:08:21

since you are going to do that in production anyways

Quest19:08:20

Makes sense. I've been building my stack on localhost but have yet to operationalize it & I've been wondering about where to serve the browser resources. You've been quite responsive today -- appreciate the advice subbed to your Patreon @ http://patreon.com/thheller

thheller19:08:20

thanks! happy to help.

thheller08:08:53

> and as a result any attempts to run an async HTTP request (GET http://google.com for instance) are forced to the same uri.

thheller08:08:08

that also isn't true. nothing is forcing the same URI. you are just passing nil to the URL

danielneal11:08:50

hey @thheller I’ve got a branch of our production react native app running on shadow-cljs and it all seems to be working great!

danielneal11:08:20

The code is much slicker now, too really nice to get rid of all those extraneous bits (like figwheel-bridge.js)

danielneal11:08:44

I have one question - occassionally I get this error No application has connected to the REPL server. Make sure your JS environment has loaded your compiled ClojureScript code., when I’m running shadow-cljs watch app in one terminal, shadow-cljs cljs-repl app in another, and expo-cli start --lan -c in the third.

danielneal11:08:26

When I get this error, I’ve been quitting and restarting everything, but I was wondering if there was a better way, or something I need to watch out for as the likely cause.

thheller12:08:11

@danieleneal that just means that the expo app has not connected back to the shadow-cljs process

thheller12:08:34

the websocket connect may have failed

thheller12:08:51

check the logs. there should be a websocket connected message when you start the app

thheller12:08:59

but your app needs to be running if you want to use the REPL

thheller12:08:22

oh and there should be any need to restart anything except maybe the expo app

sogaiu12:08:48

i encounter a similar issue when working with vscode extensions compiled using shadow-cljs -- i have been restarting everything to get my cljs-repl back. i hadn't checked my logs, but will do so next time i encounter this situation.

danielneal15:08:24

Interestingly I see

WebSocket connected!
REPL init successful
Running application on iPhone SE
in the logs sometimes, but still get the can’t connect issue. It’s almost like it’s connected to somewhere else

danielneal15:08:55

I’ve noticed that the watch and the cljs-repl have different nrepl ports, is this relevant?

thheller16:08:21

@danieleneal check if you maybe have 2 shadow-cljs processes running

thheller16:08:44

cljs-repl doesn't have an nrepl port at all?

jpmonettas19:08:10

hi everybody, I'm trying some experiments with cljs and this npm library https://github.com/projectstorm/react-diagrams/tree/v5.3.2, a nice library to handle diagrams with react, but for some reason the shadow-cljs output isn't working. I created a very basic example in js and compiled it with webpack and it works, replicated the same in cljs and compiled with shadow-cljs and browser console shows like it is missing some stuff (some stuff works, but some other fail) So far played with :js-provider and optimizations but can't make it work and don't know how to debug it further, any ideas?

thheller19:08:32

you shouldn't need to adjust anything

thheller19:08:44

what is the error?

jpmonettas19:08:09

Uncaught TypeError: Cannot read property 'BaseModel' of undefined
    at o.t$jscomp$0.PortModel [as constructor]

jpmonettas19:08:13

I tried to step thru the working and non working apps but they are different

jpmonettas19:08:38

if I change the output to es6, then I see a different error

thheller19:08:05

@jpmonettas it all looks find to me when I import it. how do I trigger an error?

jpmonettas19:08:36

yeah that works, this triggers a error

jpmonettas19:08:16

(ns test.storm
  (:require ["@projectstorm/react-diagrams" :as storm]
            ["react" :as react]
            ["react-dom" :as react-dom]))

(defn doit []
  (let [engine (doto (storm/DiagramEngine.) (.installDefaultFactories))
        model (storm/DiagramModel.)
        node1 (doto (storm/DefaultNodeModel. "Node 1" "rgb(0,192,255)") (.setPosition 100 100))
        port1 (.addOutPort node1 "Out")
        node2 (doto (storm/DefaultNodeModel. "Node 2" "rgb(0,192,255)") (.setPosition 400 100))
        port2 (.addOutPort node2 "In")
        link1 (.link port1 port2)]
    (.addAll model node1 node2)
    (.setDiagramModel engine model)
    (react-dom/render
     (react/createElement
      (storm/DiagramWidget.
       #js {:className "srd-demo-canvas"
            :diagramEngine engine}))
     (js/document.getElementById "app"))))

jpmonettas19:08:09

package.json dependencies being

"dependencies": {
    "@projectstorm/react-diagrams": "5.3.2",
    "closest": "0.0.1",
    "create-react-class": "^15.6.3",
    "dagre": "^0.8.4",
    "lodash": "^4.17.15",
    "mathjs": "^6.0.4",
    "pathfinding": "^0.4.18",
    "paths-js": "^0.4.10",
    "react": "^16.9.0",
    "react-dom": "^16.8.6",
    "webpack": "^4.39.2",
    "webpack-cli": "^3.3.6"
  },

thheller19:08:59

pretty sure you are using that incorrectly

thheller19:08:16

(react/createElement
        storm/DiagramWidget
        #js {:className "srd-demo-canvas"
             :diagramEngine engine})

jpmonettas19:08:46

this is the code that works for me in js

import {
    DiagramEngine,
    DiagramModel,
    DefaultNodeModel,
    LinkModel,
    DiagramWidget,
    DefaultLinkModel
} from "@projectstorm/react-diagrams";
import * as React from "react";
import * as ReactDOM from "react-dom";


//1) setup the diagram engine
var engine = new DiagramEngine();
engine.installDefaultFactories();

//2) setup the diagram model
var model = new DiagramModel();

//3-A) create a default node
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
node1.setPosition(100, 100);

let port1 = node1.addOutPort("Out");

//3-B) create another default node
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
node2.setPosition(400, 100);

let port2 = node2.addInPort("In");

// link the ports
let link1 = port1.link(port2);

//4) add the models to the root graph
model.addAll(node1, node2, link1);

//5) load model into engine
engine.setDiagramModel(model);

//6) render the diagram!
ReactDOM.render(
  React.createElement(DiagramWidget, {className: "srd-demo-canvas", diagramEngine: engine}, null),
  document.getElementById("app")
);

thheller19:08:58

yeah exactly

thheller19:08:22

see how you were constructing the (storm/DiagramWidget. ...)?

thheller19:08:31

you are supposed to just pass it as a react element type

thheller19:08:55

> React.createElement(DiagramWidget, {className: "srd-demo-canvas", diagramEngine: engine}, null),

jpmonettas19:08:09

let me try that

thheller19:08:22

you wrote the equiv of new DiagramWidget(), ...

thheller19:08:00

other stuff looks correct though

jpmonettas19:08:07

yeah, I tweaked that a bunch of times and got the wrong thing

thheller19:08:05

it seems to do something when I run it

jpmonettas19:08:23

yeah that is working now, sorry for all that, my bad!

jpmonettas19:08:15

and thanks for shadow-cljs!

😎 4
thheller19:08:53

that lib looks nice. might be useful for a visualization I've been thinking about

jpmonettas20:08:43

yeah looks great

jpmonettas20:08:12

just figured out if I don't do :compiler-options {:output-feature-set :es6} I still see the same error I was seeing before

thheller20:08:07

unlikely this is actually needed. try actually restarting your watch, maybe it is in a confused state or something

thheller20:08:56

but if you are fine with es6 that works too, nothing wrong with that (and actually better unless you need to support IE10 or so)

jpmonettas20:08:06

tried stopping, cleaning .shadow-cljs and commenting/uncommenting that toggles between working and that reported error, no idea

jpmonettas20:08:50

but I'm ok with that, I'm trying to build a dev tool, so no need for old browsers support

thheller20:08:12

yeah then its best to go with as little transpilation as possible