Fork me on GitHub
#clojurescript
<
2022-03-09
>
Oliver Marks08:03:38

anyone aware on any good resources on using the newer build tools focused on clojurescript and npm fancy giving it a go but there i not a great deal of information thats not focused at building jar's ?

p-himik08:03:52

> the newer build tools What exactly do you have in mind? Shadow-cljs is great when it comes to NPM and has great documentation.

jumar08:03:28

figwheel-main is also good (given my very limited exposure to clojurescript in the past few years)

Oliver Marks08:03:03

I have used both, I prefer figwheel but pulling in npm I find often does not go with out pain It also means you need npm installed which complicates ci builds ass you know need a container with clj and npm, build tools supports using npm with out these so thought I would give it a try. https://clojurescript.org/reference/compiler-options#npm-deps

Oliver Marks08:03:10

it also seems that is more official tooling going forward but i could be mistaken on that front

p-himik08:03:56

Doesn't that option itself require NPM? The :deps-cmd option suggests so. I would definitely recommend forgetting about getting rid of NPM itself, even if some tool does support it somehow. JS packages live in the JS ecosystem. Anything that wants to use JS packages correctly absolutely needs to use that ecosystem - otherwise, it will be a constant chase, especially given how much churn there still is in the JS wold. The "official" is not a good metric IMO. You use packages from people outside of Cognitect, and that's exactly the same thing. Some packages are better suited for your task than others. And shadow-cljs in particular has a tremendous support, Thomas is very responsive. One small thing, just in case - figwheel and figwheel-main are different things. If you have to choose between the two, the latter should be used nowadays.

p-himik08:03:49

Just checked the implementation - :npm-deps does indeed shell out to either npm or yarn, so you still have to have one of those installed. Which is a good thing, given the current state of affairs.

Oliver Marks08:03:15

yeah figwheel-main is often my tool of choice I also tend to used cljsjs libs to avoid npm but thats not always an option

p-himik08:03:06

Do not use CLJSJS. :) It's incomparably easier and simpler in the long run to learn and get comfortable with NPM than to keep on using CLJSJS.

Oliver Marks08:03:31

thats good to know, I was hoping that was not the case I often get hit by wierd issues along the lines of react not available in the browser when i try to use npm and its never clear why, usually wastes lots of time debugging

Oliver Marks08:03:20

I am used to npm from JS just integrating it never goes smoothly so i was hoping for a better option,

p-himik08:03:20

> react not available in the browser You mean (:require ["react"]) not working or js/React not being available?

Oliver Marks08:03:48

require is one of the bugs i often see

Oliver Marks08:03:53

Uncaught Error: Bad dependency path or symbol: react so thats the current error I am diagnosing

Oliver Marks08:03:27

using cljsjs it just works, I have react and react dom in packages.json nd have ran install to make sure they are there locally

p-himik08:03:53

Errors without stacktrace are hardly useful. Can you provide one?

Oliver Marks08:03:15

Uncaught Error: Bad dependency path or symbol: react
    visit 
    visit 
    visit 
    visit 
    load_ 
    require 
    <anonymous> 
base.js:2532:17
    visit 
    visit 
    visit 
    visit 
    load_ 
    require 
    <anonymous> 
No problem I was not planning to do a debug session now I was looking at other options 😛

p-himik08:03:49

Ah, seems that it comes from goog - found in the sources myself. :) So something probably uses (:require [react]) but can't find it. It means that your build tool does not handle node_modules correctly.

Oliver Marks08:03:13

No such namespace: react, could not locate react.cljs, react.cljc, or JavaScript source providing "react" in file resources/public/cljs-out/reagent/impl/component.cljs

  1  (ns reagent.impl.component
  2    (:require [goog.object :as gobj]
  3              [react :as react]
                  ^---
  4              [reagent.impl.util :as util]
  5              [reagent.impl.batching :as batch]
  6              [reagent.impl.protocols :as p]
  7              [reagent.ratom :as ratom]
  8              [reagent.debug :refer-macros [dev? warn error warn-unless assert-callable]]))
I also get this when launching figwheel-main

p-himik08:03:34

Or your node_modules is badly screwed and react is somehow not there. You can easily check by confirming that the directory is there and it has contents.

Oliver Marks08:03:39

I have changed this a lot so ccould have introduced it trying to resolve the issu with require

Oliver Marks08:03:04

yeah I have removed it a few times to let it pull them again

p-himik08:03:10

I have never seen such issues with shadow-cljs, not a single time. Well, apart from legit instances where I have simply forgotten to install the package.

Oliver Marks08:03:50

I found shadow jack in never worked as well for me which is one of the reason i have avoided it

p-himik08:03:04

That's exactly the point of shadow-cljs (well, one of) - you don't have to treat NPM dependencies as if they are a strange beast. Well, they are, in a way, but you just install them and just require them. That's it. 95% of the time you don't need to tinker with anything.

p-himik08:03:35

> shadow jack in A Calva thing, right? Seems to have worked for me just fine, maybe a #calva question.

Oliver Marks08:03:15

na cider, I can get around it by launching at command line then using connect, but I cant just jack in like i can with figwheel

Oliver Marks08:03:21

perhaps i will report back with more info later, got to get some work done now 😕

👍 1
p-himik08:03:06

I'm not an expert here but feels like figuring out how to fix the jack-in process is also better in the long run. It needs to be done once, whereas tinkering with NPM dependencies using something that's not shadow-cljs (at least, to the best of my knowledge) will have to be done at least once per project.

Oliver Marks09:03:37

yeah fair enough one of the reason i want to look at toolls build is i noticed the config was similar to figwheel at least teh build.edn key values looked similar, but perhaps people arer not doing using that currently

Oliver Marks11:03:36

out of intrest is there a container with npm / yarn included for clojurescript project building ?

jumar12:03:16

@U02DXJUS5JA I recently migrated a legacy app from lein-figwheel to fighweel-main so I might be able to help you with some errors. Let's get in touch in #figwheel-main if you are interested.

Oliver Marks16:03:56

so how do you include your js bundles since including npm I get a warning saying I need to use a module so i use <script src="main.js" type="module"> but that then produces this error Uncaught SyntaxError: The requested module './npm_deps.js' does not provide an export named 'npmDeps' I am including in the body tag at the bottom currently, could be module is correct and that I have he above issue.

p-himik16:03:09

You can probably already guess what my recommendation would be. 😄 > since including npm I get a warning saying I need to use a module What exactly gives this warning? How does it look?

p-himik16:03:59

I meant the warning that says that you need to use a module. This warning doesn't say that.

Oliver Marks16:03:08

I made the change following the browsers recommendation to use modules since i have tried using npm

Oliver Marks16:03:22

oh i get you one sec will have to undo

Oliver Marks16:03:55

Uncaught SyntaxError: import declarations may only appear at top level of a module

Oliver Marks16:03:18

rereading that I am not sure if that was quite the error I encountered before

Oliver Marks16:03:50

not sure why I now get that one, this is all on a prod build its actually working locally now

p-himik16:03:26

It seems that your CLJS compiler setup didn't transpile the imports in a correct way. So what was import stuff from "stuff" was left that way. If that's the case, I have no clue how to fix it. Perhaps the flag to limit feature set to ES5 will help, or maybe you have to tinker with :foreign-libs as per this page https://clojurescript.org/reference/javascript-module-support.

p-himik16:03:08

Ah, but since you're using figwheel-main, it might have a different option for that.

p-himik16:03:48

In the end, if all is configured properly, you should have a single <script src="main.js"> in your HTML, without type="module".

Oliver Marks16:03:56

I actually have shadow and figwheel working locally but still using figwheel on prod for now

Oliver Marks16:03:23

perhaps I will try and do a prod shadow build later and see if that works, and give the above a try as well

Oliver Marks16:03:14

thanks for the tips though, spent so much time on this instead of working on the application 😛

👍 1
zhuxun216:03:11

Has anyone tried using timbre in a WebWorker? Seems that all objects are shown as [Object object] in the browser console. Meanwhile, js/console.log shows an expandable object as expected.

p-himik16:03:27

In your last statement, do you mean that js/console.log is also being executed in a web worker?

zhuxun216:03:50

Yes, in the exact same context.

p-himik16:03:47

And timbre outside of a web worker, in the main context, works just fine, with all the objects being expandable?

zhuxun216:03:30

Yes, even just literally before the message was sent to the WebWorker the logged object is expandable

p-himik16:03:56

Are you sure you haven't configured custom timbre log output formatters somewhere in the main context? I just tried using taoensso.timbre/info in an empty project, and it did give me [object Object]. It's the default behavior that can be overridden with a custom :output-fn.

zhuxun216:03:10

What's even stranger is that a Cljs map sent from the main context to the web worker can no longer be looked up using keywords. So (fn [event] (-> event .-data :foo)) on the WebWorker gives TypeError: o.cljs$core$ILookup$_lookup$arity$2 is not a function

p-himik16:03:41

How did you send the data?

p-himik16:03:12

Browsers don't know about CLJS data structures, so they can't be transferred as is, they must be encoded, sent, received, and then decoded back.

p-himik16:03:36

Same with plain old JS objects - you can't just send them as is.

zhuxun216:03:58

That's my guess too. Something in the CLJS map is not serializable by the message protocol. I'm curious to know exactly what though -- the object certainly looks intact:

zhuxun216:03:00

I know that browers use the Structured Clone algorithm for encoding/decoding messages, which seems to cover most plain data types. Perhaps it's because functions are not covered which resulted in the inability to use a method embedded in that CLJS map https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm

p-himik16:03:10

Ah, I'm wrong about plain old JS objects then - I was thinking about transferable objects here, which plain JS objects are not.

p-himik16:03:29

Also I vaguely remember people reporting that in many cases a JSON.stringify + JSON.parse roundtrip was faster than the built-in structuredClone() - got confused by this one on top of the above. :)

Stuart20:03:48

I want to use a react number picker component in a clojurescript project. Is this the current way to do this ? https://gist.github.com/ducky427/10551a3346695db6a5f0

p-himik21:03:40

If you're using Reagent, then it is one of the ways, yes. Another way would be to use :> instead of reagent/adapt-react-class - it's documented somewhere in Reagent repo, could probably find by looking up "react features" there.

p-himik21:03:34

A couple of semi-related things: • Don't use stuff from js/window (like with js/FixedDataTable) unless there's just no other way • Don't use CLJSJS

Stuart21:03:33

thanks, i am using reagent, I wasn't going to use cljsjs, taht example gist isn't my code, Ive just been trying to google react with clojurescript and came across that

p-himik21:03:15

Reagent has pretty much all use cases well documented.

👍 1
zimablue22:03:46

Hi, I had an idea which I'm thinking probably already exists. Has anyone abstracted out client-server architecture in cljs-in-browser<-> cljs-on-nodejs using something like a #?(:cljs macro but for distinguishing runtime environments? Basically because the actual logic is like (something happens on server, then something on browser, then something on server) but reading the code that flow is totally scattered, ideally you'd just write it all in one function and "macro-out" the environment-switching? Explicitly piping things from browser->server->browser->server and handling it with subscriptions/channels adds a lot of noise, but then the server/client even in an electron app have different capabilities, it seems like one could write a macro that let you write what has to happen in the server and the client in one place and then just compile-out dispatching of the actions. The difference with #?(:cljs/clj would be that that reader just elides depending on environment so you end up with JUST cljs+cljc or JUST clj+cljc, whereas here you would want to behind-the-scenes wire up the IPC/REST/communication and serialization and even the errro handling maybe

zimablue22:03:54

I'm not experienced with clojurescript frameworks, do any do this? I feel like more clojure is (java server) -> (javascript frontend) and in that situation maybe the idea makes less sense

p-himik22:03:49

How would you handle errors, timeouts, out-of-order responses? There have been a lot of effort spent to abstract away the network. And if I understand your intentions correctly, you simply cannot do that. It might work for simple projects, but it will fail spectacularly in anything reasonably complex.

zimablue22:03:22

I understand your point, but for my app (electron+cljs) the "network" really is more of an architectural hangover (although the time spend to serialize/deserialize/communicate is still relevant). You'd definitely need to handle errors/timeouts as part of your solution, do you think it wouldn't be possible to have some reasonable default (delegate to nearest error handler on timeout) and also leave space for more specific handling?

zimablue22:03:39

one way to find out is just to try and write it, I was just wondering whether someone already did in cljs

p-himik22:03:30

My bet is that nobody has done it exactly because it's impractical, even though it sounds good on the surface. :) If you're interested in a deeper dive on the "why" part, "A Note on Distributed Computing" (SMLI TR-94-29) is a good paper. It would probably be useful to see how other people tackle this problem. I'm pretty sure that Logseq is an Electron app written in CLJS. There are likely to be others.

zimablue22:03:52

Athens also I believe

zimablue22:03:09

thanks for your thoughtful responses

👍 1
kraf07:03:44

@U2FRKM4TW the way I understand this, network in this case would always be localhost. Do all the complexities still apply? I think that even the browser process is strongly tied to the server process, but i don't know Electron very well.

p-himik08:03:08

Perhaps they do not apply, perhaps only some of them do - I don't know enough about how localhost works on different systems to be able to tell.

p-himik08:03:48

It's definitely different from just calling a function though, that much I can tell.

dgb2310:03:11

If you can drive everything with plain data, then pouchdb might be worth looking at. It does the sync part really well. It wouldn’t be as comprehensive as you describe, but it might solve some of the plumbing issues you describe. Have a look at master-master replication and what that means in terms of CAP.

zimablue15:03:31

@UE72GJS7J hyperfiddle does sound like they're trying to do something similar

zimablue15:03:59

in fact it seems more ambitious or as @U2FRKM4TW suggested maybe this is the minimal level of ambition to be useful

✔️ 1
Dustin Getz18:03:58

https://twitter.com/dustingetz/status/1474050461745528839 The reason it doesn't exist prior to us is because it took several team-years of full time work to make it good enough. no commercial business would fund it and capital allocators don't like funding risk. The world is filled with unrealized technology that was never funded

zimablue20:03:34

do you have an eventual monetization plan?

dgb2317:03:43

@U09K620SG this is very ambitious R&D and very impressive. You guys must be just the right amount of crazy to even attempt it. kudos

🙂 1