Fork me on GitHub
#clojurescript
<
2022-02-20
>
alex18:02:29

Hi there, I'm using server-side hiccup and would like to embed some inline JS into a <script /> tag to set a variable on the window object. Something that gets rendered as

<script>window.hello = '{:simple 1}'</script>
and then use cljs.reader/read-string to convert back into EDN. I'm having trouble figuring out how to achieve the above. Does anyone have any pointers?
[:script (str "window.hello = '" {:simple 1} "'"]
;; <script>&#x27;{:simple 1}&#x27;</script>

[:script (str "window.hello = \"" {:simple 1} "\"")] 
;; <script>window.hello = &quot;{:simple 1}&quot;</script>

p-himik19:02:39

Don't use window. Instead, assign an ID to that tag and set a custom script type. E.g. I use transit for such things and I set the type to application/transit+json, although it's not really important because the browser just ignores it.

alex19:02:19

Thanks for the suggestion! I'll give that a try For my own understanding, is there a benefit to extracting the content from the tag vs. setting it on window? I guess it's nice to not pollute the global window , but I was also planning to delete window.hello once I've accessed the data. Also for future reference - what is the way to get window.hello = "{:simple 1}" like I was trying to do above? Seems to be getting html escaped

p-himik19:02:37

It's not just polluting - it's also potential clashes. A custom script tag will be available from anywhere, without any need to delete it. Regarding escaping - no clue, to be honest. There's probably a flag for there somewhere or something else that allows it.

🙌 1
lilactown19:02:48

if you're using reagent to do SSR you ought to use :dangerously-set-inner-html to avoid escaping

lilactown19:02:03

other libs should have other mechanisms

alex20:02:48

thanks! completely forgot about dangerouslySetInnerHTML

scaturr20:02:15

I am having some trouble with advanced compilation. I have compile options of {:pseudo-names true :pretty-print true} and the error I am receiving is this:

main.js:12203 Uncaught TypeError: Cannot read properties of undefined (reading '$addModule$')
With output:
return $context$jscomp$1$$.$audioWorklet$.$addModule$($url$jscomp$58$$).then(function() {  // remainder truncated
The ClojureScript source this is derived from
(defn init-transport
  [ch context media-stream]
  (let [url     (processor-url)
        *module (-> context .-audioWorklet (.addModule url))]
    (-> *module
        (.then #(put! ch [true (create-transport context media-stream)]))
        (.catch #(put! ch [false %])))))
The context here is a native AudioContext type created via (js/AudioContext.) - Am I doing something incorrectly? Should this be an issue with advanced compilation and a native API?

p-himik20:02:56

^js in front of context in the function arg vector should fix it. I think what's going on is that GCC has an extern for -audioWorklet but doesn't have an extern for addModule and CLJS doesn't know that the result of (.-audioWorklet context) is a JS value.

scaturr20:02:20

🙇 I’ll give it a whirl. Thank you!

scaturr20:02:14

I tried the following:

(defn init-transport
  [ch ^js context media-stream]
  (let [url     (processor-url)
        *module (-> context .-audioWorklet (.addModule url))]
    (-> *module
        (.then #(put! ch [true (create-transport context media-stream)]))
        (.catch #(put! ch [false %])))))

scaturr20:02:22

The error appears to be there still

scaturr20:02:10

It seems covered there, is this just an issue of clojurescript using an older version of gcc?

p-himik20:02:11

It could be, although I was fully expecting ^js to work there. Hmm. Does anything change if you extract (.-audioWorklet context) as a separate binding and mark its name with ^js instead?

scaturr20:02:06

I’ve gone nuclear with this:

(defn init-transport
  [ch ^js context media-stream]
  (.log js/console "init transport")
  (let [url     (processor-url)
        ^js worklet (.-audioWorklet context)
        *module (.addModule worklet url)]
    (-> *module
        (.then #(put! ch [true (create-transport context media-stream)]))
        (.catch #(put! ch [false %])))))

scaturr20:02:24

And the error persists

p-himik21:02:39

That is bizarre. Are you sure it's this exact function?

scaturr21:02:40

function $blah$impl$init_transport$$($ch$jscomp$63$$, $context$jscomp$1$$, $media_stream$jscomp$1$$) {
  console.log("init transport");
  var $url$jscomp$58$$ = URL.createObjectURL(new Blob(["class WorkletProcessor extends AudioWorkletProcessor {\n      process (inputs, outputs, params) {\n        const input \x3d inputs[0];\n    \n        let frames \x3d [];\n        for (let ch \x3d 0; ch \x3c input.length; ch++) {\n          const samples \x3d input[ch];\n          frames[ch] \x3d samples;\n        }\n    \n        this.port.postMessage(frames);\n        \n        return true;\n      }\n    }\n\n    registerProcessor('worklet', WorkletProcessor);"], 
  {type:"application/javascript"}));
  return $context$jscomp$1$$.$audioWorklet$.$addModule$($url$jscomp$58$$).then(function() {
    var $JSCompiler_temp_const$jscomp$151$$ = $cljs$core$PersistentVector$EMPTY_NODE$$, $node$jscomp$inline_1099$$ = new AudioWorkletNode($context$jscomp$1$$, "worklet"), $source$jscomp$inline_1100$$ = $context$jscomp$1$$.createMediaStreamSource($media_stream$jscomp$1$$);
    return $cljs$core$async$put_BANG_$cljs$0core$0IFn$0_invoke$0arity$02$$($ch$jscomp$63$$, new $cljs$core$PersistentVector$$(null, 2, 5, $JSCompiler_temp_const$jscomp$151$$, [!0, new $cljs$core$PersistentArrayMap$$(null, 4, [$cljs$core$cst$0kw$0node$$, $node$jscomp$inline_1099$$, $cljs$core$cst$0kw$0source$$, $source$jscomp$inline_1100$$, $cljs$core$cst$0kw$0context$$, $context$jscomp$1$$, $cljs$core$cst$0kw$0media_DASH_stream$$, $media_stream$jscomp$1$$], null)], null));
  }).catch(function($p1__3208_SHARP_$$) {
    return $cljs$core$async$put_BANG_$cljs$0core$0IFn$0_invoke$0arity$02$$($ch$jscomp$63$$, new $cljs$core$PersistentVector$$(null, 2, 5, $cljs$core$PersistentVector$EMPTY_NODE$$, [!1, $p1__3208_SHARP_$$], null));
  });
}

scaturr21:02:34

The error is occurring at the return there. I added the logging as well just to be sure

scaturr21:02:43

Ok. I just upgraded ClojureScript to 1.11.4 and the error is gone

scaturr21:02:58

I should have started there facepalm

scaturr21:02:03

Thank you so much for all the help 🙇

p-himik21:02:15

Also, the compiled output looks suspiciously different from the CLJS code above... With createObjectURL and stuff. Note that there's also async in there - just in case, using go blocks will also invalidate ^js. It's a known problem, not sure whether it's fixed in 1.11.4.

scaturr21:02:39

It seems ^js is not necessary in 1.11.4

p-himik21:02:10

In that location - probably, because it shouldn't be. But in general, there are still places where ^js is needed.

scaturr21:02:25

Yeah, definitely a handy tool to have. Thanks a lot

👍 1
lilactown20:02:19

try annotating the context as ^js

lilactown20:02:59

it looks like the property and method are being renamed with optimizations

alex21:02:01

Hi there, I'm using transit to serialize my application state (for SSR), send the state down with html, then deserialize on the client. The transit encoding seems to be failing right now, but the error I'm getting is not that helpful.

Error: Cannot write Interpreter
Since the app state is pretty large, I'd like to hone in on which piece is failing. Do you have any tips to get better debugging info from this?

p-himik22:02:45

Somewhere in your data structure that you're attempting to serialize, you have an instance of class Interpreter. You can walk the data structure and check where it is.

alex23:02:42

Thanks Eugene! Found it

👍 1