shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
johnjelinek 2021-02-28T08:57:22.134100Z

(def my-stack #(let [stack %
                     _ (DockerProvider. stack "default")
                     image (Image. stack "nginxImage" {})
                     container (Container. stack "nginxContainer" {} #_{:ports [{:internal 80
                                                                                 :external 8000}]})]
                 (set! (.-name image) "nginx:latest")
                 (set! (.-keepLocally image) false)
                 (set! (.-image container) (.-latest image))
                 (set! (.-name container) "tutorial")
                 #_(set! (.-ports container) {"internal" 80
                                            "external" 8000})))
I should be able to set opts for these js interop objects like this:
(Container. stack "nginxContainer" {:port [{:internal 80 :external 8000}])
but this isn't working and so I'm having to use (set! -- any idea why that's not working?

johnjelinek 2021-02-28T08:57:46.134200Z

I don't seem to be getting any errors, but the values just aren't getting set during runtime

johnjelinek 2021-02-28T08:59:13.134500Z

side-note: the actual ports example fails either way (with or without set!) -- the error there is that it can't seem to map over [{,,,}]

thheller 2021-02-28T09:27:59.134700Z

first of all. why is this a def with an anonymous function? makes its terribly hard to read.

thheller 2021-02-28T09:28:37.134900Z

(Container. stack "nginxContainer" {:port [{:internal 80 :external 8000}]) I assume Container is some JS Object and you are passing a CLJS map as an argument which it very likely won't understand

thheller 2021-02-28T09:28:57.135100Z

use (Container. stack "nginxContainer" (clj->js {:port [{:internal 80 :external 8000}]))

thheller 2021-02-28T09:29:56.135300Z

the last commented out set! has the same issue. trying to pass a CLJS map to any JS object will either fail directly or fail silently since they all expect plain JS objects

thheller 2021-02-28T09:30:34.135500Z

you can also construct JS objects directly via #js {:foo "bar"}

nmkip 2021-02-28T14:46:10.143400Z

Hi, I'm trying to make a simple chrome extension but I'm having some problems with the initial setup of the project. When I watch the :extension build and then open the url that I'm matching in my shadow-cljs.edn I'm getting the following error multiple times:

browser.cljs:406 WebSocket connection to '<ws://localhost:9630/ws/worker/extension/13b81eb2-ba6f-458a-b497-defe7df73dbb/acea096f-5091-4a70-ab73-10aafb9a60a5/browser>' failed: Unknown reason
shadow$cljs$devtools$client$browser$ws_connect_impl @ browser.cljs:406
shadow$cljs$devtools$client$browser$ws_connect @ browser.cljs:388
browser.cljs:20 🠢 shadow-cljs: websocket error EventΒ {isTrusted: true, type: "error", target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
browser.cljs:20 🠢 shadow-cljs: WebSocket disconnected!
It keeps trying to reconnect and always fails. I'm using binaryage/chromex shadow example as my template with some changes: β€’ Removed deps.edn β€’ Removed all dependencies β€’ Changed the :content-script :matches to a specific url instead of &lt;all_urls&gt; More info in thread 🧡

nmkip 2021-02-28T14:47:04.143500Z

This is how my shadow-cljs.edn file looks like:

{:source-paths ["src/background"
                "src/popup"
                "src/content-script"]

#_#_ :dependencies [[binaryage/chromex "RELEASE"]
                [binaryage/devtools "RELEASE"]]
 
 :builds {:extension

          {:target           :chrome-extension
           :extension-dir    "resources/unpacked"
           :manifest-file    "resources/unpacked/manifest.edn"
           :compiler-options {; <https://github.com/google/closure-compiler/issues/1704>
                              :closure-output-charset "US-ASCII"
                              ; we need to fully inline source maps to avoid devtools security restrictions of loading .map
                              ; files via chrome-extension://&lt;extension-id&gt;/out/cljs-runtime/goog.debug.error.js.map urls
                              :source-map-inline      true}
           :outputs          {:background     {:output-type :chrome/background
                                               :entries     [chromex-sample.background]}
                              :content-script {:output-type    :chrome/content-script
                                               :chrome/options {:matches ["<https://classroom.google.com/u/*/ta/not-reviewed/all>"]
                                                                :run-at  "document_end"}
                                               :entries        [chromex-sample.content-script]}
                              :popup          {:output-type :chrome/shared
                                               :entries     [chromex-sample.popup]}}}}}

nmkip 2021-02-28T14:47:06.143700Z

This is how my manifest.edn file looks like:

{:name             "Test chrome extension"
 :version          "1.0"
 :description      "Test chrome extension"
 :manifest-version 2

 :permissions      ["http://*/*"
                    "https://*/*"]

 :browser-action   {:default-title "Show the popup"
                    :default-icon  "images/icon48.png"
                    :default-popup "popup.html"}

 :content-security-policy
                   ["default-src 'self';"
                    ;; FIXME: unsafe-eval should be injected for dev, user shouldn't have to write this
                    "script-src 'self' 'unsafe-eval' <http://localhost:9630>;"
                    "connect-src * data: blob: filesystem:;"
                    "style-src 'self' data: chrome-extension-resource: 'unsafe-inline';"
                    "img-src 'self' data: chrome-extension-resource:;"
                    ;; FIXME: localhost only? don't want to allow any origin though
                    "frame-src 'self' <http://localhost>:* data: chrome-extension-resource:;"
                    "font-src 'self' data: chrome-extension-resource:;"
                    "media-src * data: blob: filesystem:;"]}

johnjelinek 2021-02-28T15:23:05.143900Z

@thheller: thanks! clj-js worked! #js {,,, did not

johnjelinek 2021-02-28T15:34:58.144100Z

ah, if I'm doing #js, I gotta apply it more liberally:

(Container. stack "nginxContainer" #js {:image (.-latest image)
                                              :name "tutorial"
                                              :ports #js [#js {:internal 80
                                                               :external 8000}]})

johnjelinek 2021-02-28T15:36:35.144300Z

πŸ˜† this should address your first-of-all:

(defn my-stack [app name]
  (let [stack (TerraformStack. app name)
        image (Image. stack "nginxImage" #js {:name "nginx:latest"
                                              :keepLocally false})]
    (DockerProvider. stack "default")
    (Container. stack "nginxContainer" (clj-&gt;js {:image (.-latest image)
                                                 :name "tutorial"
                                                 :ports [{:internal 80
                                                          :external 8000}]}))))

johnjelinek 2021-02-28T15:37:01.144500Z

thank you again for your help!

thheller 2021-02-28T15:41:44.144800Z

> failed: Unknown reason

thheller 2021-02-28T15:41:57.145300Z

there must be a reaon. dunno how you find out what πŸ˜›

nmkip 2021-02-28T15:42:16.145600Z

There's probably a reason xD

thheller 2021-02-28T15:43:14.146500Z

yeah #js doesn't apply to nested values so clj-&gt;js is better for more complex structures where you don't care about performance

πŸ‘ 1
nmkip 2021-02-28T15:43:47.147100Z

and it's probably my fault πŸ˜›

thheller 2021-02-28T15:44:09.147500Z

config looks ok. does it work if you change the :matches?

nmkip 2021-02-28T15:45:40.148600Z

I believe the :matches is working as I'm only getting shadow error messages in this site: https://classroom.google.com/u/0/ta/not-reviewed/all

nmkip 2021-02-28T15:47:34.149200Z

nmkip 2021-02-28T15:52:21.150500Z

It works if I use :matches ["<http://localhost:9630/*>"]

thheller 2021-02-28T15:54:37.151300Z

well yeah it must be allowed to connect to the shadow-cljs server for the REPL and hot-reload stuff

nmkip 2021-02-28T15:54:48.151400Z

shadow-cljs connects to the websocket and if I eval a println in the content_script.cljs I can see it in the console

thheller 2021-02-28T15:54:52.151700Z

(for development builds, ie. watch and compile)

thheller 2021-02-28T15:55:15.152300Z

release can and should be stricter

nmkip 2021-02-28T15:55:35.152700Z

and how do I allow it?

thheller 2021-02-28T15:56:34.153100Z

its an array so just add multiple things

nmkip 2021-02-28T15:56:48.153400Z

what array are you talking about?

thheller 2021-02-28T15:56:56.153700Z

:matches ["<https://classroom.google.com/u/*/ta/not-reviewed/all>" "<http://localhost>:*/*"] probably

nmkip 2021-02-28T15:57:19.154300Z

I tried that

nmkip 2021-02-28T15:59:35.155Z

Using this shadow-cljs connects to the websocket in localhost, but I get the websocket error in google classroom

nmkip 2021-02-28T16:00:20.155200Z

This is the localhost console:

nmkip 2021-02-28T16:00:51.155600Z

This is google classroom console:

nmkip 2021-02-28T16:01:49.156Z

And this is the shadow-cljs.edn file:

{:source-paths ["src/background"
                "src/popup"
                "src/content-script"]

 #_#_:dependencies [[binaryage/chromex "RELEASE"]
                    [binaryage/devtools "RELEASE"]]

 :builds {:extension

          {:target           :chrome-extension
           :extension-dir    "resources/unpacked"
           :manifest-file    "resources/unpacked/manifest.edn"
           :compiler-options {:closure-output-charset "US-ASCII"
                              :source-map-inline      true}
           :outputs          {:background     {:output-type :chrome/background
                                               :entries     [chromex-sample.background]}
                              :content-script {:output-type    :chrome/content-script
                                               :chrome/options {:matches ["<http://localhost:9630/*>" "<https://classroom.google.com/u/*/ta/not-reviewed/all>"]
                                                                :run-at  "document_end"}
                                               :entries        [chromex-sample.content-script]}
                              :popup          {:output-type :chrome/shared
                                               :entries     [chromex-sample.popup]}}}}}

thheller 2021-02-28T16:02:31.156200Z

try "<http://localhost>:*/*" instead of "<http://localhost:9630/*>"

thheller 2021-02-28T16:03:36.156600Z

not a clue really. been a while since I looked at any of this. maybe chrome got stricter security restrictions these days

thheller 2021-02-28T16:03:47.156800Z

do you still have some csp rules in your HTML maybe?

nmkip 2021-02-28T16:05:20.157Z

I'm using brave browser I don't know if that's a problem

thheller 2021-02-28T16:05:49.157200Z

might be. not a clue, never used it.

nmkip 2021-02-28T16:06:27.157400Z

As far as I know brave uses the same extensions as chrome.

nmkip 2021-02-28T16:06:33.157600Z

I will download chrome and try there.

thheller 2021-02-28T16:08:54.157800Z

more likely that something in your config doesn't quite match

thheller 2021-02-28T16:09:00.158Z

what about your html?

thheller 2021-02-28T16:09:09.158200Z

is there any?

nmkip 2021-02-28T16:09:14.158400Z

the only html is the popup, just a hello world πŸ˜›

thheller 2021-02-28T16:09:31.158600Z

ok, does that have some csp rules?

thheller 2021-02-28T16:09:51.158900Z

&lt;meta name="Content-Security-Policy" ...&gt;

nmkip 2021-02-28T16:10:29.159100Z

nope

thheller 2021-02-28T16:10:42.159300Z

then I'm out of ideas

nmkip 2021-02-28T16:11:32.159500Z

okay, no problem! Thanks a lot πŸ™‚ I'll try a bit more and if I fail I'll just use javascript and suffer πŸ˜›

thheller 2021-02-28T16:12:23.159700Z

well the websocket is only used for hot-reload and REPL. if you don't care about those then you can just set :devtools {:enabled false} and it won't try to connect

nmkip 2021-02-28T16:13:52.159900Z

good to know , maybe Ill do that

nmkip 2021-02-28T17:38:03.160600Z

@thheller I've noticed that I'm having this problem with https sites

thheller 2021-02-28T17:56:56.160800Z

hmm yeah that might be a reason. might need to setup ssl for shadow-cljs so is all ssl

naomarik 2021-02-28T18:42:23.163300Z

Has anyone got react-native project going using WSL2? I'm wondering how/where the port from the app (below 50594 and 50612) is being determined so I can forward it properly to my WSL2 instance:

[Sun Feb 28 2021 22:39:55.649]  ERROR    shadow-cljs - remote-error {"isTrusted": false, "message": "failed to connect to /172.25.210.33 (port 9630) from /192.168.0.166 (port 50594) after 10000ms"}
[Sun Feb 28 2021 22:40:10.782]  WARN     The shadow-cljs Websocket was disconnected.
[Sun Feb 28 2021 22:40:10.792]  ERROR    shadow-cljs - remote-error {"isTrusted": false, "message": "failed to connect to /172.25.210.33 (port 9630) from /192.168.0.166 (port 50612) after 10000ms"}
[Sun Feb 28 2021 22:40:10.852]  LOG      giving up trying to connect

thheller 2021-02-28T18:45:01.163800Z

that is the port of the react-native app client. you don't need to do anything for that port as it will be random always

thheller 2021-02-28T18:45:17.164200Z

you just need to be able to connect from the app to shadow-cljs. looks like that is trying to use the wrong IP

naomarik 2021-02-28T18:46:07.165400Z

yeah it's using the IP internally from WSL2... I have adb tcpip running from windows then within WSL2 adb connect to connect to the device

thheller 2021-02-28T18:46:16.165600Z

shadow-cljs watch app --config-merge '{:local-ip "1.2.3.4"}' lets you set a specific one

naomarik 2021-02-28T18:48:51.166200Z

that worked πŸ˜‰

naomarik 2021-02-28T18:49:18.166700Z

I can't just add the local-ip key within my shadow-cljs.edn ?

naomarik 2021-02-28T18:49:23.166900Z

I tried that first and didn't seem to do anything

thheller 2021-02-28T18:49:35.167300Z

currently needs to go into the build config

thheller 2021-02-28T18:49:48.167600Z

still need create a better way to control all this

naomarik 2021-02-28T18:50:43.167800Z

cool that works too