Fork me on GitHub
#shadow-cljs
<
2022-11-04
>
prnc15:11:09

Hello 👋 I’m trying to use react-pdf-viewer w/ pdfjs and seeing this compilation error:

Failed to inspect file
  <elided>/node_modules/pdfjs-dist/build/pdf.js

it was required from
  <elided>/node_modules/@react-pdf-viewer/core/lib/cjs/core.min.js

Errors encountered while trying to parse file
  <elided>/node_modules/pdfjs-dist/build/pdf.js
  {:line 2118, :column 9, :message "Semi-colon expected"}
Might just be an actual problem with this version of pdfjs, but posting here in case it has something to do with compilation iteself --- has anyone seen this type of error during compilation? Thank you 🙏

thheller17:11:53

@prnc unfortunately this is an error in the closure compiler. usually code it doesn't support. nothing I can do on the shadow-cljs side about it. only option is using a different bundler for JS as described here https://code.thheller.com/blog/shadow-cljs/2020/05/08/how-about-webpack-now.html#option-2-js-provider-external

☝️ 1
prnc17:11:34

No worries @thheller — I was afraid that was the case, thank you so much for confirming!

zalky19:11:51

Hi all: I'm trying to figure out how to use a custom middleware list with a shadow-cljs nREPL (cljs). The default cider stack contains one piece of middleware, wrap-out that redirects all std out to the cider REPL, which I personally find a bit of a pain to work with. Normally I would just remove it from the stack, but I haven't been able to figure out how to provide shadow with a custom middleware list. I've tried both ~/.nrepl/nrepl.edn and using the .shadow-cljs.edn {:nrepl {:middleware ...} option, which the docs say are supported, but neither seems to have the desired effect. In fact, the shadow nREPL server does not seem to want to recognize "ls-middleware" operation so I can verify what middleware is being loaded:

({:id "1a43aa3c-2865-4513-9a2b-51c1166e2e40",
  :op "ls-middleware",
  :session "8dc66073-fd36-4cf1-a6b0-936d59c1993b",
  :status ["done" "unknown-op" "error"]})
When I start up the same version of nREPL server and Cider outside of shadow, the above :op return the full list of middleware being loaded by the server, as expected. Am I doing something wrong? Any suggestions where I can go from here?

dpsutton19:11:37

I believe you can tell cider to just not subscribe to out

dpsutton19:11:54

I’m about to get on a plane so can’t find it but there’s a way to not invoke that middle ware

dpsutton19:11:21

You don’t need to exclude it from your middleware stack. Just not call the op “subscribe-out”

zalky19:11:34

Ok, much appreciated! I'm myself just about to get in a car, but that sounds like a promising alternative to the workflow I've been using all this time (custom middleware list with just that one missing). I'll give it a shot next week.

👍 1
thheller19:11:50

just use your own nrepl server and add the shadow-cljs middleware

thheller19:11:19

:nrepl {:middleware ...} should be fine but it is only additive. it'll not override or remove defaults

zalky19:11:09

Ah, I see, that's why it was having no effect.

zalky19:11:07

Thanks for the quick response! I'll try your suggestion.

Sam Ritchie21:11:35

double checking my understanding here.. I am depending on an NPM library called “mathlive”. is it therefore not possible to use mathlive in my clojure namespace paths? I have a namespace mathlive.core , which compiles great. But if I do this:

(ns mathlive.core
  (:require ["mathlive" :as ml]))

(defn Mathfield [!state] [:div "testing"])
then I see this error:
TypeError: Cannot set properties of undefined (setting 'Mathfield')
triggered from this compiled js:
mathlive.core.Mathfield = (function mathlive$core$Mathfield(_BANG_state){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Keyword(null,"div","div",1057191632),"test"], null);
});
of course this restriction would make sense, for some reason I thought when this came up for the “mathbox” library I had decided that I WAS able to use namespaces like mathbox.core etc

Sam Ritchie21:11:37

it doesn’t seem to be a problem for a few of my namespaces to be mathlive.something; just this one, maybe since it is the first namespace to require the js “mathlive” dependency?

thheller03:11:47

not sure why this wouldn't work? should be fine

Sam Ritchie04:11:15

Mathlive.Core is null, very weird. I will see if I can repro it with a smaller build

thheller04:11:28

does this lib maybe forcefully export a global mathlive JS variable? that would indeed clash with and destroy the CLJS namespace

thheller04:11:51

some js libs just set window.mathlive = whatever; or global.mathlive = whatever.

Sam Ritchie04:11:27

digging a bit, that makes sense

Sam Ritchie04:11:44

@thheller probably out of luck here, yeah?

Sam Ritchie21:11:59

should I be calling the library something like mathlive-cljs to fix this?

jaide23:11:11

Just released my first production cljs frontend app https://www.crunchydata.com/pricing/calculator

👍 2
🍾 1
🎉 3
🙌 1
Lone Ranger23:11:42

That’s great! The calculator part or the whole site?

jaide23:11:28

Just the calculator part. Rest of site is remix + TS for now

Lone Ranger23:11:20

Will be interested in hearing your thoughts on it if you ever have time, not sure the size of it but with larger more complex cljs apps I’m starting to struggle a little. Of course never done anything big in TS so maybe the browser is just a tough environment

jaide23:11:13

The web is vast and nebulous for sure. What parts are you struggling with?

Lone Ranger00:11:05

Keeping the code base understandable and maintainable with runtime sprawl

Lone Ranger00:11:41

webworkers, service workers, web workers and service workers but user disallows cookies, no web workers or service workers allowed but still need to run with gracefully degraded performance, etc.

Lone Ranger00:11:06

not to mention cloud functions, nodejs, blah blah

Lone Ranger00:11:51

and of course I’m trying to be a good dev and not write if statements everywhere, trying to write exstensible data types underlying a core layer of business logic that should remain essentially unchanged regardless of runtime

Lone Ranger00:11:14

And I never thought I’d ever say this but lack of inheritance is kind of becoming a problem

Lone Ranger00:11:31

And I know the answer is “just use maps”… and that’s how it started of course

Lone Ranger00:11:41

but the browser is too permissive, it doesn’t crash, errors just start to accumulate and it’s not obvious at first

Lone Ranger00:11:50

nils being both logically false AND the default return value of a function that crashes AND a missing key is kind of a rough overlap

Lone Ranger00:11:38

Anyway all these things have answers and those answers are called macros but as a result my code base is starting to look less and less like recognizable earthling cljs and more Martian

Lone Ranger00:11:00

Shadow cljs has been pretty clutch tho, thanks @thheller , super grateful

jaide00:11:05

I think it comes down to two key things: Either coming up with an architecture that can be adapted to as many use cases as possible, where you can model most if not all problems in a similar way. My goto is using event-streams with Bacon.js and reagent atoms. Alternatively, it's ok to start out rough and refine as you go along. The first version of the price calc I had implemented almost all in one file, then when I got inspiration for a better design and architecture that fit my needs, I refactored. Because I started loose, I also had early progress to show stakeholders.

jaide00:11:10

nil doesn't have to be the missing key return. When I need distinction I use (get a-map :my-key ::not-found) or (:my-key a-map ::not-found)

Lone Ranger00:11:42

that’s true, but ::not-found is logically true except by convention. And then you’ve started on the slippery slope. Because then you need a class of predicates that treats ::not-found as false. And the long tail of that is a cascade of issues. However I do think that what you said about showing early rapid progress to stakeholders is incredibly important

Lone Ranger00:11:36

I’ve found the sweet spot for cljs in one-off internal tools that need to be made quickly and high quality but don’t need a lot of coordination to make

jaide00:11:15

I haven't ran into that with my medium sized internal prototypes or the side projects I've taken on. The only time I find myself having to use conditionals is when I am trying to express behavioral optionality, have not had to use them for safety

jaide00:11:13

It does the calculations reactively and if something results in nil it doesn't break anything

jaide00:11:19

Added more of the UI

Lone Ranger01:11:18

Awesome! Thank you for sharing. And great work. I think cljs is very challenging and a lot of respect for anyone that does it commercially

jaide01:11:56

It can be, it did take me about 3 attempts to learn clojure before it clicked, but once I spent a year learning functional programming in js, clojure really clicked and have been really enjoying it ever since but I think it depends on the team. For example, the backend team wrote an article on why they chose Ruby in 2022. It's because it was familiar, they liked the repl experience for dealing with production issues, the team had experience with it, and they were interested in learning how to make the most of it warts and all. https://www.crunchydata.com/blog/crunchy-bridges-ruby-backend-sorbet-tapioca-and-parlour-generated-type-stubs