shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
Jon 2020-12-18T04:01:03.019Z

I think it's during migrating.

Jon 2020-12-18T04:01:18.019200Z

the old content can be found at https://github.com/shadow-cljs/shadow-cljs.org/blob/master/markdown/introduction.md

Eugen 2020-12-18T08:18:23.019800Z

hi, http://shadow-cljs.org/ is down for me

Eugen 2020-12-18T08:19:01.020Z

now it directs to github

Eugen 2020-12-18T08:38:18.021Z

I've just ran npx create-cljs-project web-syntax-highligh and got

web-syntax-highlight
├── node_modules
|-- REDACTED
├── package.json
├── package-lock.json
├── shadow-cljs.edn
└── src
    ├── main
    └── test
It is a bit surprising - no files are present? Is this expected?

Eugen 2020-12-18T08:48:25.021500Z

also shadow-cljs is almost empty

;; shadow-cljs configuration
{:source-paths
 ["src/dev"
  "src/main"
  "src/test"]
 :dependencies
 []
 :builds
 {}} 

Eugen 2020-12-18T09:10:53.022600Z

I checked my previous project and I was using https://github.com/filipesilva/create-cljs-app which provides a more opinionated experience for new apps - which is what I need

Jakub Holý 2020-12-18T12:55:38.030800Z

Hello! In JS, with Webpack, I can do

import "some_node_module/some.css"
Is something similar possible with Shadow? I could cp node_modules/some_node_module/some.css public every time before I deploy but ☝️ is even less effort.

thheller 2020-12-18T12:56:57.031900Z

no, CSS is not supported

👍 1
Eugen 2020-12-18T13:59:47.037Z

@holyjak I've also hit shado-cljs webpack integration just now. Trying to make a clojurescript app with monaco-editor (VSCode in browser). Can you share some hints/ strategies on how to approach it? All monaco examples seem to be with webpack or directly in browser

Eugen 2020-12-18T14:01:56.037600Z

I can't even import the JS because of :

(ns app.monaco
  (:require [reagent.core :as r]
            ["react-monaco-editor" :default monaco]))

----
Failed to inspect file
  /home/ieugen/proiecte/hledger-grammars/examples/hledger-web-demo/node_modules/monaco-editor/esm/vs/editor/standalone/browser/standalone-tokens.css

it was required from
  /home/ieugen/proiecte/hledger-grammars/examples/hledger-web-demo/node_modules/monaco-editor/esm/vs/editor/standalone/browser/standaloneEditor.js

Errors encountered while trying to parse file
  /home/ieugen/proiecte/hledger-grammars/examples/hledger-web-demo/node_modules/monaco-editor/esm/vs/editor/standalone/browser/standalone-tokens.css
  {:line 8, :column 1, :message "primary expression expected"}

Eugen 2020-12-18T14:14:42.039100Z

@thheller Monaco seems to distribute module with esm that imports CSS so requireing it in shadow, fails. Do you have any suggestions on how to approach this sittuation? https://microsoft.github.io/monaco-editor/

flowthing 2020-12-18T15:10:06.041100Z

My understanding is that if I use an NPM module that uses e.g. Object.assign and I want shadow-cljs handle polyfills for me such that the resulting JS bundle works with IE11, I just need to add :js-options {:babel-preset-config {:targets {:ie 11}}} into my shadow-cljs.edn. That doesn't appear to work, though: I still get Object doesn't support property or method 'assign'. Should that work, or should I take another approach? FWIW:

λ du -hs .shadow-cljs/babel-worker/babel-worker.js
2.8M    .shadow-cljs/babel-worker/babel-worker.js

Jakub Holý 2020-12-18T15:33:57.041500Z

Sorry, I do not integrate with web pack

JAtkins 2020-12-18T15:43:27.043800Z

Has anyone seen the $jscomp error? I'm seeing this on the console of my release build occasionally.

shadow-cljs - failed to load 973
jLb @ main.js:14558
CZ @ main.js:14559
(anonymous) @ main.js:15924
(anonymous) @ main.js:18690
main.js:6386 Uncaught ReferenceError: $jscomp is not defined
    at main.js:6386
    at main.js:6028
    at Object.shadow$provide.<computed> (main.js:6028)
    at jLb (main.js:14558)
    at main.js:6630
    at Object.shadow$provide.<computed> (main.js:6630)
    at jLb (main.js:14558)
    at Object.shadow$provide.<computed> (main.js:6770)
    at jLb (main.js:14558)
    at Object.shadow$provide.<computed> (main.js:6771)
This is reproducible with the same code. However, I cannot find what in the code is inducing this behavior.

thheller 2020-12-18T15:54:10.044900Z

@jatkin $jscomp is for polyfills. which version do you use? I thought I had fixed those issues. if you can afford it the best option is setting :compiler-options {:output-feature-set :es6} or higher if you can (:es7, :es8, ...)

thheller 2020-12-18T15:54:48.045800Z

@flowthing not all sources are processed with babel so that might not apply. you can set :compiler-options {:force-library-injection #{"es6/object/assign"}}

thheller 2020-12-18T15:54:56.046100Z

not 100% sure on the name but I think thats it

JAtkins 2020-12-18T15:57:28.046200Z

I'm using 2.11.8

flowthing 2020-12-18T16:05:04.047400Z

@thheller Thank you! I'll give it a shot and let you know. How do I figure out what to put in :force-library-injection if I need polyfills for other things?

flowthing 2020-12-18T16:05:59.047900Z

Great, thanks!

ghaskins 2020-12-18T16:24:12.050100Z

@thheller we've been using your :proxy-predicate feature to great success, thanks again for that. A related problem we are running into is Secure cookie handling when using the dev-proxy against a TLS backend. I think what we need to do is simply strip the "Secure" flag in the cookies as they pass through when the backend is https, which I think is essentially the opposite of https://undertow.io/javadoc/2.0.x/io/undertow/server/handlers/SecureCookieHandler.html

ghaskins 2020-12-18T16:25:33.050600Z

i was trying to see where I might propose such a feature: it looks like it might fit somewhere in here: https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/undertow.clj#L304

ghaskins 2020-12-18T16:25:39.050900Z

but guidance appreciated

flowthing 2020-12-18T16:58:21.052Z

@thheller It works, many thanks! This really saves me a lot of trouble. Sadly, the Closure compiler doesn't provide a polyfill for Symbol.for, so I need to figure out a way to add one myself.

Eugen 2020-12-18T18:08:24.052900Z

thank you, that confirmed my worries 🙂

Eugen 2020-12-18T18:19:11.053300Z

I found this out and going to try it https://github.com/suren-atoyan/monaco-react

Eugen 2020-12-18T18:19:16.053600Z

looks promissing

flowthing 2020-12-18T18:19:38.053800Z

I'd be interested in hearing whether it works for you.

Eugen 2020-12-18T18:19:52.054Z

sure I will update you

Eugen 2020-12-18T18:56:28.054200Z

it works, I can see the editor and type into it

(ns app.monaco
  (:require [reagent.core :as r]
            ["@monaco-editor/react" :as Editor]))

(defn editor []
  [:<>
   [:p "Hello, hledger-web-demo is running!"]
   [:p "Here's an example of using a component with state:"]
   [(r/adapt-react-class Editor/default) {:height "90vh" :languge "javascript"}]])

crs 2020-12-18T19:02:58.057400Z

advanced compilation question. Is there an annotation that preserves a name rather than just exporting an alias? E.g.

shadow$umd$export = {MyName:MyName}
instead of
shadow$umd$export = {MyName:kA}
I want the meaningful name to be available for debugging when logging this object in the console

flowthing 2020-12-18T19:03:35.057900Z

Nice, thanks for letting me know!

flowthing 2020-12-18T19:06:12.058100Z

(Just a small side note: you can also do [:> Editor/default ,,,] instead of r/adapt-react-class.)

Eugen 2020-12-18T19:09:44.058300Z

thanks, I'll have to read throught the re-agent docs 🙂

thheller 2020-12-18T19:14:24.058900Z

@chris.smothers externs control that. if you add MyName to externs it won't be renamed. https://shadow-cljs.github.io/docs/UsersGuide.html#_simplified_externs

thheller 2020-12-18T19:17:03.059800Z

@ghaskins not a clue. seems like that would need to be something the proxy handler from undertow has to do? not sure we can control that

lilactown 2020-12-18T19:22:05.061400Z

hey thheller. I have a lib that has certain feature flags you can turn on locally for certain runtime and compile time behavior, like:

(defnc my-component []
  {:helix/features {:fast-refresh true}} ;; turn on compile-time processing for react-refresh
  )
I'm trying to figure out an easy way for consumers to enable this globally w/o wrapping the defnc macro. wdyt?

lilactown 2020-12-18T19:23:12.062400Z

I thought about :closure-defines but I don't think that would work here, since I don't think I can get at those during compile-time to know whether I should do the processing

crs 2020-12-18T19:32:15.062500Z

I’m trying this and it’s still getting renamed. Is there a special syntax for CLJS namespaces? ns/var or ns$var ?

ghaskins 2020-12-18T19:36:44.063300Z

@thheller i reverse engineered Undertow's SecureCookieHeader to come up with this prototype

commit 4a9ea2d9e07c6f87364ef9f613b31751e935be8f (HEAD -> strip-secure-2.10-backport, refs/patches/strip-secure-2.10-backport/dev-http-strip-secure-cookies)
Author: Greg Haskins <greg@manetu.com>
Date:   Fri Dec 18 12:50:05 2020 -0500

    [dev-http] Strip secure cookies

    Signed-off-by: Greg Haskins <greg@manetu.com>

diff --git a/src/main/shadow/cljs/devtools/server/dev_http.clj b/src/main/shadow/cljs/devtools/server/dev_http.clj
index 9e3e803a..d28c7c11 100644
--- a/src/main/shadow/cljs/devtools/server/dev_http.clj
+++ b/src/main/shadow/cljs/devtools/server/dev_http.clj
@@ -95,7 +95,8 @@

               ;; proxy-url but no proxy-predicate, proxy everything
               (not proxy-predicate)
-              [::undertow/proxy config]
+              [::undertow/strip-secure-cookies
+               [::undertow/proxy config]]

               ;; proxy-url + proxy-predicate, let predicate decide what to proxy
               ;; should be symbol pointing to function accepting undertow exchange and returning boolean
@@ -105,7 +106,8 @@
                 [::undertow/predicate-match
                  {:predicate-fn (fn [ex]
                                   (pred-var ex config))}
-                 [::undertow/proxy config]
+                 [::undertow/strip-secure-cookies
+                  [::undertow/proxy config]]
                  req-handler])

               :else
diff --git a/src/main/shadow/undertow.clj b/src/main/shadow/undertow.clj
index 26060df6..0299d803 100644
--- a/src/main/shadow/undertow.clj
+++ b/src/main/shadow/undertow.clj
@@ -19,6 +19,7 @@
            [org.xnio ChannelListener Xnio OptionMap]
            [java.nio.channels ClosedChannelException]
            [io.undertow.util AttachmentKey MimeMappings Headers]
+           [io.undertow.server ResponseCommitListener]
            [io.undertow.server.handlers.resource PathResourceManager ClassPathResourceManager]
            [io.undertow.predicate Predicates Predicate]
            [io.undertow.server.handlers.encoding EncodingHandler ContentEncodingRepository GzipEncodingProvider DeflateEncodingProvider]
@@ -237,6 +238,26 @@

     (assoc state :handler handler)))

+(defmethod build* ::strip-secure-cookies [state [id next]]
+  (assert (vector? next))
+
+  (let [{next :handler :as state}
+        (build state next)
+
+        listener
+        (reify
+          ResponseCommitListener
+          (^void beforeCommit [_ ^HttpServerExchange ex]
+            (doseq [[_ cookie] (.getResponseCookies ex)]
+              (.. cookie (getValue) (setSecure false)))))
+
+        handler
+        (reify
+          HttpHandler
+          (handleRequest [_ ex]
+            (.addResponseCommitListener ex listener)
+            (.handleRequest ^HttpHandler next ex)))]
+    (assoc state :handler handler)))

 (def compressible-types
   ["text/html"

ghaskins 2020-12-18T19:36:56.063600Z

its hooking the right place, now im just sorting out the details

ghaskins 2020-12-18T19:37:36.064300Z

(ProxyHandler was where I looked first, but it doesnt seem to be extensible at that layer...but Undertow in general is)

ghaskins 2020-12-18T19:41:14.064900Z

anyway, assuming you are conducive to such a feature, you can guide me on how best to integrate it for merge consideration after I prove out the if/how

thheller 2020-12-18T21:44:22.065400Z

@ghaskins can't you just configure SSL for shadow-cljs? that seems to be the easiest option?

thheller 2020-12-18T21:51:05.065500Z

no just MyNane one line

thheller 2020-12-18T21:52:44.065700Z

you can use the same stuff as cljs-devtools I guess but closure defines would work too

ghaskins 2020-12-18T22:03:46.066400Z

@thheller on the dev-proxy? is that an option

ghaskins 2020-12-18T22:03:47.066600Z

?

ghaskins 2020-12-18T22:04:17.067100Z

i know sometimes dealing with the self-signed certs is a pain, too, but I havent tried to do that

thheller 2020-12-18T22:14:36.067500Z

certs can be a bit annoying yeah

JB 2020-12-18T22:41:08.069100Z

I'm getting cannot instantiate non-constructor when I run shadow-cljs check buildName despite trying simple externs ConstructorThing and manual externs

/**
 * @constructor
 */
constructorThing = function() {};

JB 2020-12-18T22:42:28.069400Z

I'm also prepending ^js/ to the name

ghaskins 2020-12-18T22:48:49.070900Z

@thheller ty for the doc link, I didnt know that was an option. Still, it may be worth considering some version of what I am proposing as it reduces dev friction to not have to deal with SSL unless necessary. We have found that this patch solves our problem

commit 836ec3dfe35bc3342f76e5ed0373163e8f8b47c5 (HEAD -> strip-secure-2.10-backport)
Author: Greg Haskins <greg@manetu.com>
Date:   Fri Dec 18 12:50:05 2020 -0500

    [dev-http] Strip secure cookies

    Signed-off-by: Greg Haskins <greg@manetu.com>

diff --git a/src/main/shadow/cljs/devtools/server/dev_http.clj b/src/main/shadow/cljs/devtools/server/dev_http.clj
index 9e3e803a..d28c7c11 100644
--- a/src/main/shadow/cljs/devtools/server/dev_http.clj
+++ b/src/main/shadow/cljs/devtools/server/dev_http.clj
@@ -95,7 +95,8 @@

               ;; proxy-url but no proxy-predicate, proxy everything
               (not proxy-predicate)
-              [::undertow/proxy config]
+              [::undertow/strip-secure-cookies
+               [::undertow/proxy config]]

               ;; proxy-url + proxy-predicate, let predicate decide what to proxy
               ;; should be symbol pointing to function accepting undertow exchange and returning boolean
@@ -105,7 +106,8 @@
                 [::undertow/predicate-match
                  {:predicate-fn (fn [ex]
                                   (pred-var ex config))}
-                 [::undertow/proxy config]
+                 [::undertow/strip-secure-cookies
+                  [::undertow/proxy config]]
                  req-handler])

               :else
diff --git a/src/main/shadow/undertow.clj b/src/main/shadow/undertow.clj
index 26060df6..e102f986 100644
--- a/src/main/shadow/undertow.clj
+++ b/src/main/shadow/undertow.clj
@@ -18,7 +18,8 @@
            (java.security KeyStore)
            [org.xnio ChannelListener Xnio OptionMap]
            [java.nio.channels ClosedChannelException]
-           [io.undertow.util AttachmentKey MimeMappings Headers]
+           [io.undertow.util AttachmentKey MimeMappings Headers HttpString]
+           [io.undertow.server ResponseCommitListener]
            [io.undertow.server.handlers.resource PathResourceManager ClassPathResourceManager]
            [io.undertow.predicate Predicates Predicate]
            [io.undertow.server.handlers.encoding EncodingHandler ContentEncodingRepository GzipEncodingProvider DeflateEncodingProvider]
@@ -237,6 +238,34 @@

     (assoc state :handler handler)))

+(defn secure-cookie? [t]
+  (some? (re-matches #"\s*Secure\s*" t)))
+
+(defmethod build* ::strip-secure-cookies [state [id next]]
+  (assert (vector? next))
+
+  (let [{next :handler :as state}
+        (build state next)
+
+        listener
+        (reify
+          ResponseCommitListener
+          (^void beforeCommit [_ ^HttpServerExchange ex]
+            (let [headers (.getResponseHeaders ex)]
+              (when-let [cookie (.get headers "set-cookie" 0)]
+                (as-> cookie $
+                      (str/split $ #";")
+                      (remove secure-cookie? $)
+                      (str/join ";" $)
+                      (.put headers (HttpString. "set-cookie") $))))))
+
+        handler
+        (reify
+          HttpHandler
+          (handleRequest [_ ex]
+            (.addResponseCommitListener ex listener)
+            (.handleRequest ^HttpHandler next ex)))]
+    (assoc state :handler handler)))

 (def compressible-types
   ["text/html"

ghaskins 2020-12-18T22:49:18.071400Z

if you are open to considering some form of it, id be happy to work a PR to your satisfaction

thheller 2020-12-18T22:53:37.071500Z

check is not reliable. thats why it is not documented. it will always give you a lot of false positives

thheller 2020-12-18T22:54:41.072100Z

looks fine to me just rather hard to test

JB 2020-12-18T23:28:15.073100Z

Ah thanks for clarifying! I saw in the the “simplified externs” section of the docs and assumed it was

wilkerlucio 2020-12-18T23:44:05.073500Z

is there a way to set a custom REPL timeout for (shadow/browser-repl)?

✅ 1
ghaskins 2020-12-18T23:59:44.074500Z

> looks fine to me just rather hard to test Its a good point. I can probably at least split the header-handling into a defn so I can add a test for it. I will do so

ghaskins 2020-12-18T23:59:45.074700Z

ty