Fork me on GitHub
#shadow-cljs
<
2021-01-05
>
13tales00:01:02

Hey there. I’m a relative newbie just getting to grips with Clojurescript and shadow-cljs, and have a quick workflow/REPL question: I’m running/hot-reloading my application with shadow-cljs watch, and connecting to the REPL with Cider. When I add a new dependency to shadow-cljs.edn, do I need to stop and restart the watch command in order to be able to use it, or is there something I can do via the REPL to install it and make it available right away?

13tales00:01:01

Okay, found the answer to my own question: it looks like adding/changing dependencies does always require restarting the server, if I’m understanding the docs correctly. > Once the server is running however you only have to restart it whenever your :dependencies change and everything else can be done via the REPL. https://shadow-cljs.github.io/docs/UsersGuide.html#_server_mode

13tales00:01:25

Would still appreciate some clarity on this, actually: If I’m developing with shadow-cljs watch, what should I do when I add a dependency? Trying to restart the server by running shadow-cljs restart in another terminal seemed to break the connection with the browser and REPL.

thheller10:01:12

just ctrl+c the watch and start it again

Alexis Vincent13:01:40

Yes for clojure dep, no for npm dep

13tales22:01:53

@thheller Thanks. Still new to the ecosystem, and wanted to make sure there wasn’t some galaxy-brain clojure-wizard I-never-leave-my-REPL way of updating the dependencies that I was missing 😅

dpsutton01:01:49

Just kill the process and restart the watch

👍 3
Gustavo Aguiar04:01:53

Hi all, I'm learning Clojure(Script) and for that I'm doing a little project. In this little project I setup a JNI with Rust, which made me use lein so that I can correctly compile the Java file I had in my project. I'm also the kind of person who likes to write to learn, and I'm writing about the project setup. But to truly write something good I have to understand why I had to use lein (I honestly don't know, a friend simply said it would work if I did, and it worked). Is there any resource where I can understand if shadow-cljs can compile .java files, and if not, why it can't?

saitouena05:01:39

As far as I know, shadow-cljs cannot compile .java files because compiling .java files is not the purpose of shadow-cljs. I think reading the official documentation would help you. lein: https://github.com/technomancy/leiningen > Leiningen is for automating Clojure projects without setting your hair on fire. lein is a kind of build tool for clojure(script). shadow-cljs: https://shadow-cljs.github.io/docs/UsersGuide.html#_introduction the purpose of shadow-cljs is compiling cljs code into javascrpt codes with ease.

thheller10:01:13

shadow-cljs is for compiling clojurescript and at most some .js files. it does not deal with any .java or JVM related things

thheller10:01:36

I personally use lein for JVM related clj/java things

Gustavo Aguiar12:01:30

Thanks for the explanation 😊

zendevil.eth12:01:25

I’m running a shadow watch

zendevil.eth12:01:34

but am getting the following error:

zendevil.eth12:01:59

The required namespace “appname.core” is not available.

zendevil.eth12:01:30

even though the app name exists in the src/appname/core.cljs folder

zendevil.eth12:01:36

with the ns as appname.core

zendevil.eth12:01:16

here’s my shadow-cljs.edn file

zendevil.eth12:01:17

{:paths [“src”] :dependencies [[reagent “0.10.0"] [re-frame “0.12.0”] [re-frame-steroid “0.1.1"] [rn-shadow-steroid “0.2.1”] [re-frisk-remote “1.3.3"]] :builds {:dev {:target :react-native :init-fn appname.core/init :output-dir “app” :compiler-options {:closure-defines {“re_frame.trace.trace_enabled_QMARK_” true}} :devtools {:after-load steroid.rn.core/reload :build-notify steroid.rn.core/build-notify :preloads [re-frisk-remote.preload]}}}}

thheller12:01:39

@ps does appname maybe contain a -? Then the folder would need to be app_name

zendevil.eth12:01:02

it doesn’t contain a hyphen

zendevil.eth12:01:45

the folder and the namespace have the same name and contain only the alphabet characters

thheller12:01:46

ah now I see it. it is :source-paths not :paths

zendevil.eth12:01:50

for some reason following these steps to compile to react native target isn’t working: https://morioh.com/p/ac368dc1fceb

zendevil.eth12:01:55

when I empty the index.js to just

import './app/index.js';
I get the error that it’s not registered

zendevil.eth12:01:19

actually I’m getting the error:

zendevil.eth12:01:30

element type is invalid: expected a string

zendevil.eth12:01:36

but got object

zendevil.eth12:01:52

you likely forgot to export the component from the file it is defined in

zendevil.eth13:01:00

is registerComponent required in ./index.js or does it come with the register-reload-comp?

thheller13:01:22

sorry don't know what register-reload-comp is

thheller13:01:11

the index.js is just supposed to load the CLJS output, it shouldn't do anything else. at least in the examples I set up.

zendevil.eth13:01:04

that’s exactly what I do

zendevil.eth13:01:16

import ‘./app/index.js’;

zendevil.eth13:01:39

but that doesn’t register the app

thheller13:01:51

element type is invalid: expected a string usually means that some component you are using was nil

thheller13:01:02

its your job to register the app

thheller13:01:04

yes but the error you are getting doesn't necessarily have anything to do with the root component

thheller13:01:20

[:> something {:foo "bar"}] when something is nil you'll get this error

zendevil.eth13:01:15

I’m not getting the expected string error when ./index.js just contains the import

thheller13:01:44

do you use expo?

Michaël Salihi13:01:21

What's your init defn (code snippet)?

zendevil.eth13:01:00

(defn init [] (rn/register-reload-comp {:name “Something”} root-comp))

zendevil.eth13:01:26

also tried (defn init [] (AppRegistry {:name “Something”} root-comp))

zendevil.eth13:01:40

by doing [“react-native” :refer [AppRegistry SafeAreaView]]

zendevil.eth13:01:40

I meant, also tried this (defn init [] (. AppRegistry registerComponent {:name “Something”} root-comp))

zendevil.eth13:01:41

compiles successfully but Appname isn’t registered

thheller13:01:57

this is CLJS {:name “Something”} maybe you want #js {:name “Something”}

zendevil.eth13:01:34

still registration problem 😞

Michaël Salihi13:01:58

Try like this:

(defn init []
  (rn/register-reload-comp "Something" root-comp))

zendevil.eth13:01:57

not registered

zendevil.eth13:01:36

why does it say that registerComponent wasn’t called when it was called?

thheller13:01:19

hard to say without all the code

zendevil.eth13:01:10

(ns appname.core
  (:require [steroid.rn.core :as rn]
            ["react-native" :refer (View AppRegistry SafeAreaView)]))

(defn root-comp []
  [:> View "view"]
  #_[rn/view
    [rn/text "Hello CLojure! from CLJS"]])

(defn init []
  (. AppRegistry registerComponent #js {:name "Something"} root-comp))

zendevil.eth13:01:57

and ./index.js is

import './app/index.js';

zendevil.eth13:01:25

shadow-cljs.edn is

{:source-paths ["src"]

 :dependencies [[reagent "0.10.0"]
                [re-frame "0.12.0"]
                [re-frame-steroid "0.1.1"]
                [rn-shadow-steroid "0.2.1"]
                [re-frisk-remote "1.3.3"]]

 :builds       {:dev
                {:target     :react-native
                 :init-fn    appname.core/init
                 :output-dir "app"
                 :compiler-options {:closure-defines
                                    {"re_frame.trace.trace_enabled_qmark_" true}}
                 :devtools   {:after-load steroid.rn.core/reload
                              :build-notify steroid.rn.core/build-notify
                              :preloads [re-frisk-remote.preload]}}}}

thheller13:01:45

dont call register component like that

zendevil.eth13:01:16

how to call it instead?

thheller13:01:56

like the example does

zendevil.eth13:01:37

I couldn’t search for registerComponent call in this repo

zendevil.eth14:01:38

I now have my code as the example but I’m still getting the not registered error:

zendevil.eth14:01:40

(ns appname.core (:require [steroid.rn.core :as rn] [shadow.react-native :refer (render-root)] [reagent.core :as r] [“react-native” :refer (Text SafeAreaView View AppRegistry SafeAreaView)])) (defn root-comp [] [:> SafeAreaView [:> View [:> Text “Some Text”]]]) (defn init [] (render-root “Root” (r/as-element [root-comp])))

thheller14:01:07

is Root the name of your app? it needs to match whatever you have in app.json or so

zendevil.eth14:01:36

Okay now it works!

thheller14:01:54

I don't really do react-native myself so I'm just guessing with all of this 😛

zendevil.eth14:01:35

Do you work with reagent web?

thheller14:01:57

no. not using react at all anymore.

zendevil.eth14:01:09

what do you use instead>

thheller14:01:25

not something anybody else should use yet but I like experimenting with new stuff 🙂

💡 3
zendevil.eth14:01:56

Thanks so much!

flowthing14:01:50

Don't know if this more of a ClojureScript or a shadow-cljs issue, but I guess I'll try my luck here first: I'm working on integrating Playwright (https://playwright.dev) into one of my projects. I have a macro like this:

(defmacro test-page
  [browser-types page-sym & body]
  `(cljs.test/async done#
     (cljs.core.async/go
       (doseq [browser-type# ~browser-types]
         (let [browser# (cljs.core.async.interop/<p! (.launch browser-type#))
               page# (cljs.core.async.interop/<p! (.newPage browser#))
               ~page-sym page#]
           ~@body
           (done#))))))
And I call it like this:
(deftest smoke
  (test-page [chromium] page
    (<p! (.goto page ""))
    (is (= "Nope" (<p! (.innerText page ".navbar__title"))))))
It works well, but I get a lot of inference warnings like this:
10 |   (test-page [chromium] page
---------^----------------------------------------------------------------------
 Cannot infer target type in expression (. inst_47307 (newPage))
I'm not sure how to fix those warnings. Any ideas?

Jakub Holý (HolyJak)14:01:42

Hello folks! What is the best practice for using JS libraries for the browser distributed via CDN? Simply add <script ...> to the html and use it via js/exportedThing ? Thank you!

thheller14:01:48

core.async loses ^js typehint information unfortunately so its kinda hard to typehint that stuff properly

thheller14:01:37

@flowthing you can turn off the warnings via :compiler-options {:infer-externs true} (not :auto). that way you only get warnings if you (set! *warn-on-infer* true) in the ns

flowthing14:01:19

@thheller Thanks! Will give that a try. Works great! 🙇:skin-tone-2:

mkvlr15:01:34

has anyone tried to let closure handle modules generated by typescript?

Alexis Vincent15:01:38

Yeah. Worked fine from my memory

Alexis Vincent15:01:52

No, no experience with that. but thats probably the way to go to get optimisations. I just compiled to js and used shadow’s js integration

Alexis Vincent15:01:45

certainly wasnt an optimised experience. Was just for convinience pasting ts/js code into a file and using from cljs

mkvlr15:01:54

ah oh, so using it like a normal node module

Alexis Vincent15:01:52

exactly. I used the option on the ts compiler to keep directory structure. Then added the output to the classpath.

Alexis Vincent15:01:24

So i had the ts files sitting alongside the cljs files.

Alexis Vincent15:01:06

and a ./x.js in cljs land worked because the directory structure was persisted

thheller16:01:22

if the code is ESM you will get full advanced optimizations when included via https://shadow-cljs.github.io/docs/UsersGuide.html#classpath-js

thheller16:01:17

only trouble is externs inference doesn't work for the JS code so if that code uses a lot of npm code you might need manual externs

Alexis Vincent16:01:07

@thheller You might find the conversation I just had with @dnolen on #clojurescript interesting.

thheller16:01:12

I've been thinking about writing a cljs compiler that outputs only modern ESM code directly for a while now

thheller16:01:28

but a whole lot of effort for little gain currently

lilactown20:01:00

I went down the route of tsickle for a lib awhile back but IIRC the goog.module output it produces wasn't amenable for use with CLJS

lilactown20:01:14

I had to hand-modify the files after compilation to use the old module system