shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
zimablue 2021-05-04T04:47:01.219700Z

Hi, what is the recommended way if any to build something intended for a (node + typescript) consumption? I think the issue is that you need to do :keep-native-requires for node to work, but :keep-native requires leaves as you'd imagine, the requirement as "require" whereas typescript seems to hate that, throwing this error: WARNING in ../node_modules/datahike/datahike.js 112:12-19 vs-sprot-mm: Critical dependency: require function is used in a way in which dependencies cannot be statically extracted

thheller 2021-05-04T07:03:41.220500Z

@zhuxun2 no, that is not supported and probably never will be

thheller 2021-05-04T07:05:14.221800Z

@zimablue don't know what that error is about, would need to see some code. don't know what :keep-native-requires has to do with anything? when you are using node anyways you absolutely should not be using :js-provider :shadow?

zimablue 2021-05-04T07:06:46.222300Z

I did not know that I should not be using that js-provider, sorry. In fact that is the one thign I never tried varying

zimablue 2021-05-04T07:06:53.222500Z

what should I be using?

zimablue 2021-05-04T07:07:22.222800Z

I pulled the first configuration that I tried from this thread: https://github.com/thheller/shadow-cljs/issues/290

thheller 2021-05-04T07:07:49.223400Z

well, I need to know more about what you are building to answer

zimablue 2021-05-04T07:08:24.224100Z

trying to compile datascript (cljs library) so that it works through an application that uses typescript to target a node runtime

zimablue 2021-05-04T07:08:45.224400Z

in fact it's datahike, which is a fork

thheller 2021-05-04T07:08:50.224500Z

so you use :target :node-library?

zimablue 2021-05-04T07:09:10.225Z

yes, although I've tried others in my scattershot attempts

thheller 2021-05-04T07:10:42.225900Z

well, it sounds like :node-library would do what you need. if you describe what the problem with that was I can maybe help further

thheller 2021-05-04T07:11:04.226300Z

completely basic config, no :js-options config whatsoever

zimablue 2021-05-04T07:12:18.226800Z

I will strip out all the config and then come back

zimablue 2021-05-04T07:12:28.227200Z

you recommend to use "release" right, not compile

zimablue 2021-05-04T07:12:54.227600Z

does infer-externs matter? it is on auto currently

thheller 2021-05-04T07:13:38.228500Z

you must use release if you intend to release the actual library to be used in projects. compile or watch will only work on the machine it was compiled on in the directory it was compiled in

thheller 2021-05-04T07:14:14.228900Z

matter for what? it only affects the warnings you'll see for your code. nothing else

zimablue 2021-05-04T07:14:29.229300Z

for working when consumed as a module by typescript I guess

zimablue 2021-05-04T07:14:40.229800Z

I'll leave as-if and follow your advice

zimablue 2021-05-04T07:14:51.230100Z

I think I will have already tried that combination, but it will at least give us the relevant error

thheller 2021-05-04T07:15:08.230400Z

you don't need to set it at all, auto is the default nowadays (unless you are on a really old version)

zimablue 2021-05-04T07:15:43.230700Z

I will set it just to let it know I'm serious

thheller 2021-05-04T07:16:16.231100Z

it does not affect the code that is generated in any way so I'm unsure what you think it does

zimablue 2021-05-04T07:33:24.231300Z

sorry, it was a stupid joke

thheller 2021-05-04T07:37:57.232600Z

just wanted to be clear that it doesn't affect the generated code πŸ˜› it really only controls whether you see the warnings or not

zimablue 2021-05-04T07:57:20.233500Z

with the settings that you suggested, the runtime error is this: $environ$core$fs$$.$existsSync$ is not a function. When I look at the code, it's trying to do existsSync on ".lein-env". I'm actually trying to run it in a vscode extension and now wondering whether vscode blocks raw node calls so I'm checking on that also

thheller 2021-05-04T08:00:37.234100Z

that looks like you are maybe doing (def fs node-fs) with (:require ["fs" :as node-fs]) or something like that?

thheller 2021-05-04T08:01:58.234600Z

oh no ... worse the library is doing that https://github.com/weavejester/environ/blob/master/environ/src/environ/core.cljc#L11

thheller 2021-05-04T08:02:31.235100Z

for that you'll need to add manual externs I guess

thheller 2021-05-04T08:03:28.235700Z

or just get rid of that entire library. it doesn't seem to be doing all that much πŸ˜›

Aron 2021-05-04T08:04:31.235800Z

this is such an evergreen advice. I love libraries, because of this :)

thheller 2021-05-04T08:06:21.236Z

yes, maybe but unfortunately very many libraries are designed for CLJ and then someone just adds support for CLJS later as an afterthought

thheller 2021-05-04T08:07:28.236200Z

that doesn't always work out well

Aron 2021-05-04T08:09:36.236400Z

I remember the first time I realized how far cljs and clj are from each other. I almost broke down crying. πŸ™‚

Aron 2021-05-04T08:10:52.236600Z

although, in this situation it seems to me there might be other assumptions going on that could be breaking https://imgur.com/a/rZzPfWl

zimablue 2021-05-04T08:12:31.237600Z

yes, :require "fs" as fs is happening, both seemingly in that dependency and also in the library main

zimablue 2021-05-04T08:12:58.238400Z

the problem is when this all gets pushed through a typescript=>node-electron thing though, it all works fine in shadow-cls node-repl

thheller 2021-05-04T08:13:27.239200Z

@zimablue the problem is the library uses js/require so externs inference is "hindered" a little. that is why you are seeing the existsSync (and likely the others) getting renamed

zimablue 2021-05-04T08:13:48.240Z

so it's expected that it works in node-repl but not when compiled and pushed through typescript?

thheller 2021-05-04T08:13:51.240100Z

if that were (:require ["fs" :as fs]) externs inference would be much smarter and generate the proper externs

zimablue 2021-05-04T08:14:12.241200Z

ah, so it might just be the dependencies having that requirement that's the problem, not the project "main"?

thheller 2021-05-04T08:14:13.241400Z

please take a second to understand what externs are

Aron 2021-05-04T08:14:20.241900Z

js requires explicit exports, which is not kept without all this being in place

zimablue 2021-05-04T08:14:21.242200Z

but "manual externs" should work?

thheller 2021-05-04T08:14:36.242800Z

they ONLY prevent the renaming of stuff. when you run node-repl NOTHING is getting renamed since it does not run through :advanced compilation

zimablue 2021-05-04T08:14:38.243Z

I have taken a second before, it's taken me longer than that definitely xD from memory "variables which should not be renamed"

thheller 2021-05-04T08:14:46.243300Z

when you run release things will get named and minified

zimablue 2021-05-04T08:14:47.243400Z

ah, I see

thheller 2021-05-04T08:14:55.243700Z

so with externs you prevent those renames

thheller 2021-05-04T08:15:32.244400Z

externs-inference is meant to do this automatically for you but it can only do so when the code is written appropriately. which this library is not. so you need to help it along manually

Aron 2021-05-04T08:15:51.244700Z

appropriate is es6 import/export?

Aron 2021-05-04T08:16:00.244900Z

or some cljs convention

thheller 2021-05-04T08:16:13.245300Z

there is no such thing as es6 import/export in CLJS, but lets please stay on topic here

thheller 2021-05-04T08:16:50.246100Z

@zimablue what you need is a externs/your-build-id.txt and just one line for existsSync (and maybe more lines for other stuff getting renamed)

thheller 2021-05-04T08:17:17.246500Z

that will make it work fine in release and typescript

thheller 2021-05-04T08:18:11.247200Z

normally this should be fixed directly in the code but since it is a library you can't easily do that. unless you are ok with forking it

thheller 2021-05-04T08:22:28.247300Z

FWIW if you use the proper (:require ["fs" :as fs]) then shadow-cljs will automatically add externs for whereever fs/* is used. with (js/require ...) this is not done. basically since you are never supposed to use that ...

Aron 2021-05-04T08:27:09.247500Z

thanks for getting back on this, sorry for causing confusion :/

Aron 2021-05-04T08:28:45.248400Z

I can see why js/require is not helpful

thheller 2021-05-04T08:30:28.249800Z

well often it is used as a "hack" to get a dynamic require sort of behavior. like that library does. from a build tool perspective this pattern is horrible but I understand why it is done.

thheller 2021-05-04T08:30:42.250200Z

a simple ^js hint would also fix problems with this but the lib doesn't have it

pez 2021-05-04T08:31:59.251200Z

@zimablue have a look at the Clover extension and see how things are done there. iirc it uses shadow-cljs as the central part of the toolchain. I can also recommend using the #vscode channel for getting some pointers and help from others fighting a similar battle. πŸ˜ƒ

thheller 2021-05-04T08:36:46.252200Z

I'd honestly just replace that library. Unless you actually want your electron app to be configurable via a .lein-env file?

zimablue 2021-05-04T08:52:54.253Z

It's not my personal project to pull libraries out of, I'll follow the explanation you gave, applied to this project and see where I get to

zimablue 2021-05-04T08:53:12.253400Z

@pez, thanks for that advice I will take a look

Adam Kalisz 2021-05-04T14:32:21.258100Z

@thheller it has been more than a month. I couldn't load my dev-environment in Chromium on Debian Linux and had to resort to working in Firefox without some of the useful tools. The loading of the project was so slow, it basically was just hanging. The issue seems to have been with :devtools {:loader-mode :script} which was there for some (maybe already obsolete) issue. Switching to {:loader-mode :eval} seems to fix the problem. Everything is snappy again

Adam Kalisz 2021-05-04T14:34:07.259200Z

I don't know any details, my colleague found it to fix some of his performance issues and it helped me even more.

Prabu Rajan 2021-05-04T14:52:52.260600Z

Hi, How do I import a react library component in a shadow-cljs / re-frame app? Below isn’t working

//JS version
import { Button } from "@chakra-ui/react";
import { ChakraProvider } from "@chakra-ui/react";

class App extends Component {
  render() {
    return (
      <ChakraProvider>
        <Button
                px="3"
                py="2"
                bg="green.200"
                rounded="md"
                _hover={{ bg: "green.300" }}>
            Click me
        </Button>
        <h1>Hello World</h1>
      </ChakraProvider>
    );
  }
}

//cljs version

(ns todo.views
  (:require
   [re-frame.core :as re-frame]
   [todo.events :as events]
   ["@chakra-ui/react" :refer (ChakraProvider)]
   ["@chakra-ui/react" :refer (Button)]
   [todo.subs :as subs]))

(defn button-panel []
  [:div {:id "button-panel"}
   [:> Button {:px 10 :py 5 :bg "green.200" :on-click
     #(re-frame/dispatch [::events/update-counter 1])} "+"]
   [:> Button {:px 10 :py 5 :bg "green.200" :on-click
     #(re-frame/dispatch [::events/update-counter -1])} "-"]])

(defn main-panel []
  (let [counter (re-frame/subscribe [::subs/counter])]
    [:> ChakraProvider
     [:div
     [:h1 @counter]
     (button-panel)]]))

Prabu Rajan 2021-05-04T15:03:04.260700Z

I was able to fix it like this

(ns todo.views
  (:require
   [re-frame.core :as re-frame]
   [todo.events :as events]
   ["@chakra-ui/react" :as cui]
   [todo.subs :as subs]))

(defn button-panel []
  [:div {:id "button-panel"}
   [:> cui/Button {:mr 1 :bg "green.200" :on-click
     #(re-frame/dispatch [::events/update-counter 1])} "+"]
   [:> cui/Button {:bg "green.200" :on-click
     #(re-frame/dispatch [::events/update-counter -1])} "-"]])

thheller 2021-05-04T16:07:54.260900Z

["@chakra-ui/react" :refer (ChakraProvider Button)] would be ok too

Prabu Rajan 2021-05-04T17:14:35.261200Z

Cool, works too, not sure what was missing earlier

thheller 2021-05-04T17:22:37.261400Z

there seems to be a bug. you had the "@chakra-ui/react" require twice and the second one replaced the first one instead of adding to it

Prabu Rajan 2021-05-04T17:56:08.261600Z

Yes, thats right. Thanks for pointing it out. You mean its a bug with shadow-cljs or the code above?

thheller 2021-05-04T17:56:25.261800Z

bug in shadow

Prabu Rajan 2021-05-04T18:01:03.262800Z

Thanks, raised this issue - https://github.com/thheller/shadow-cljs/issues/879

πŸ‘ 1
2021-05-04T18:01:27.263500Z

anyone had any luck getting react-pdf or generally pdfjs working nicely with shadow? feel like I’m mashing a square peg into a round hole, mostly because I’m not super familiar with pdfjs

2021-05-04T18:15:26.267500Z

Hi all: when using :js-provider :external , is it required to have a node_modules installed before compiling with shadow? I'm getting an error without it:

The required namespace "react" is not available, it was required by "reagent/core.cljs".
I'm getting my js bundle via another source (not npm), and wondering if there's still some way to make it work with shadow.

thheller 2021-05-04T18:30:42.268Z

well the problem there is that reagent.core does (:require [react ...]) as in a symbol

thheller 2021-05-04T18:31:14.268700Z

the only way to know that this symbol is referring to an actual npm library it needs to be in node_modules

thheller 2021-05-04T18:31:39.269400Z

if that was (:require ["react" ...]) that check is not necessary since we know that strings are reserved for JS libs

thheller 2021-05-04T18:32:21.269900Z

currently there is no way to tell it manually that certain symbols should be treated as a npm lib, well besides installing the actual npm lib

thheller 2021-05-04T18:33:24.271Z

I tried advocating for enforcing strings for JS requires but that feedback was ignored so we have this problem unfortunately

2021-05-04T18:39:55.272700Z

Gotcha, the string require does make a lot of sense, it's basically js interop, no sense hiding it. I guess just assuming every missing dependency is externally provided is not feasible?

2021-05-04T18:42:01.273100Z

I suppose not since you still have to check the cljs ones.

2021-05-04T18:46:00.274400Z

It wouldn't make sense to turn it into a warning, would it? "This is missing, better be provided externally" something along those lines?

thheller 2021-05-04T18:52:45.275Z

I won't just make every symbol valid assuming its a npm dependency. there could be typos and stuff

πŸ‘ 1
thheller 2021-05-04T18:53:21.275600Z

I'd be open to adding a config option to treat certain symbols as npm requires without requiring their presence

thheller 2021-05-04T18:54:00.276300Z

maybe I could also just use the :npm-deps from deps.cljs for that

lispers-anonymous 2021-05-04T20:44:06.278500Z

Does shadow-cljs have a tool built in for printing out a graph of namespace requires? I am trying to figure out why cljs.pprint is being included in my production bundle, which I learned using the shadow-cljs.build-report tool.

dpsutton 2021-05-04T20:48:42.279100Z

i don't remember where i heard/read it, but i have a memory that if you use the equivalent of format it will drag pprint in

lispers-anonymous 2021-05-04T20:53:34.279300Z

I don't believe we are using any functions called format . Do you know what namespace that lives in?

dpsutton 2021-05-04T20:54:40.279500Z

it had been a while. i looked it up and its cljs.pprint/cl-format so probably not the insight i remembered it to have been πŸ™‚

lispers-anonymous 2021-05-04T20:56:23.279700Z

Yeah definitely not using that lol, I appreciate the thought though. I feel like exhausted all my options for finding the culprit

nivekuil 2021-05-04T20:56:26.279900Z

expound, maybe from guardrails? if you use fulcro at all it'll get pulled in

lispers-anonymous 2021-05-04T20:57:20.280300Z

Expound may be it actually. looking

lispers-anonymous 2021-05-04T20:59:05.280500Z

Yeah that's it. I'm not using fulcro or guardrails, but we do have one usage of expound. This must be it. Thank you!

πŸ‘ 1
thheller 2021-05-04T21:14:15.281Z

@dannyfreeman that graph does not currently exist no. requires a bit of manual digging currently to find it. do you use fulcro?

thheller 2021-05-04T21:15:39.281500Z

ah nvm thread. yeah expound is one source

lispers-anonymous 2021-05-04T21:17:21.281600Z

Yeah that was the only culprit thankfully. I can happily code split on the namespace where I use expound and get cljs.pprint out of my main bundle.