Fork me on GitHub
#shadow-cljs
<
2020-12-18
>
Eugen08:12:01

now it directs to github

Eugen08:12:18

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?

Eugen08:12:25

also shadow-cljs is almost empty

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

Eugen09:12:53

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ý (HolyJak)12:12:38

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.

thheller12:12:57

no, CSS is not supported

👍 3
Eugen13:12:47

@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

Jakub Holý (HolyJak)15:12:57

Sorry, I do not integrate with web pack

Eugen18:12:24

thank you, that confirmed my worries 🙂

Eugen18:12:16

looks promissing

flowthing18:12:38

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

Eugen18:12:52

sure I will update you

Eugen18:12:28

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"}]])

flowthing19:12:35

Nice, thanks for letting me know!

flowthing19:12:12

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

Eugen19:12:44

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

Eugen14:12:56

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"}

Eugen14:12:42

@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/

flowthing15:12:06

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

JAtkins15:12:27

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.

thheller15:12:10

@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, ...)

JAtkins15:12:28

I'm using 2.11.8

thheller15:12:48

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

thheller15:12:56

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

flowthing16:12:04

@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?

flowthing16:12:59

Great, thanks!

ghaskins16:12:12

@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

ghaskins16:12:33

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

ghaskins16:12:39

but guidance appreciated

flowthing16:12:21

@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.

crs19:12:58

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

thheller19:12:24

@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

crs19:12:15

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

thheller21:12:05

no just MyNane one line

thheller19:12:03

@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

lilactown19:12:05

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?

thheller21:12:44

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

lilactown19:12:12

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

ghaskins19:12:44

@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 <[email protected]>
Date:   Fri Dec 18 12:50:05 2020 -0500

    [dev-http] Strip secure cookies

    Signed-off-by: Greg Haskins <[email protected]>

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"

ghaskins19:12:56

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

ghaskins19:12:36

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

ghaskins19:12:14

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

thheller21:12:22

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

ghaskins22:12:46

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

ghaskins22:12:17

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

thheller22:12:36

certs can be a bit annoying yeah

JB22:12:08

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() {};

JB22:12:28

I'm also prepending ^js/ to the name

thheller22:12:37

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

JB23:12:15

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

ghaskins22:12:49

@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 <[email protected]>
Date:   Fri Dec 18 12:50:05 2020 -0500

    [dev-http] Strip secure cookies

    Signed-off-by: Greg Haskins <[email protected]>

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"

ghaskins22:12:18

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

thheller22:12:41

looks fine to me just rather hard to test

wilkerlucio23:12:05

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

3
wilkerlucio00:12:53

(shadow/browser-repl {:devtools {:repl-timeout 3000000}})

ghaskins23:12:44

> 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