Fork me on GitHub
#shadow-cljs
<
2018-06-06
>
richiardiandrea00:06:08

so in order to bundle in node, which target should I use? I am adding the preamble so I need I thing either :node-library or :npm-module

richiardiandrea01:06:01

because :node-script prepends a #! and webpack barfs 😄

claudiu05:06:33

Hi, trying to setup and inspect my production build found release-snapshot really usefull ( https://clojureverse.org/t/help-wanted-release-bundle-size-visualization/871/11). Could not find in the user guide release-snapshot any reason why it's not there ?

thheller07:06:24

@richiardiandrea if you want to use webpack use :npm-module

👍 4
thheller07:06:55

@claudiu yeah I still need to mention that. It is a bit unfinished thats why it is not mentioned yet.

claudiu09:06:06

Cool 🙂 Playing with react-semantic-ui, it really helped a lot to understand why my bundle-size grew so much. Are there any optimizations that I can opt-in to get better build sizes with shadow-cljs (ex: change the js output to es6, ie11+) ?

kwladyka12:06:21

I asked on #clojurescript about issue with https://github.com/venantius/accountant . But I would like to be sure: is it shadow-cljs issue or accountant issue? Looks like accountant, but who knows.

hlolli12:06:52

@kwladyka how's your :devtools in shadow-cljs.edn config? You define correct http-root?

kwladyka12:06:22

@hlolli

{:http-root "public"
                           :http-port 8020}

kwladyka12:06:02

Oh I just discovered without accountant I have the same issue, so it is about shadow-cljs

kwladyka12:06:12

When run http://localhost:8020/foo/bar/baz but app works with http://localhost:8020/foo (which doesn’t exist too)

kwladyka12:06:01

and of course it works with http://localhost:8020 🙂

kwladyka12:06:15

So everything is fine when use 1 level url, but when use more I have this issue

wilkerlucio12:06:57

@kwladyka what your :asset-path look like (in the build config)?

wilkerlucio13:06:10

that looks like the issue to me, try /js instead

kwladyka13:06:37

🍺 thank you

wilkerlucio13:06:03

no worries, this is the base path for js requires, so if you have it relative it only works on the root

kwladyka13:06:15

You saved my day 🙂

wilkerlucio13:06:34

glad to help 🙂

wilkerlucio13:06:03

@thheller hey, this might be something stupid I'm doing, but I'm getting some warnings that I didn't expect in shadow, I create a new namespace, both clj and cljs separated files (clj for a macro), I did :require-macros on my cljs file, but when I use the macro shadow is warning me that I'm using an undefined symbol, but my macro is a def-like macro, so I don't understand why I'm getting these warnings

wilkerlucio13:06:10

this is my macro code:

wilkerlucio13:06:11

(defmacro defcard [sym settings]
  (let [fqsym (if (namespace sym)
                sym
                (symbol (name (ns-name *ns*)) (name sym)))]
    `(init-card ~fqsym ~settings)))

wilkerlucio13:06:25

(ws/defcard sample-card
  {::ws/node-props
   {:className ""}

   ::ws/render
   (fn [node]
     (gobj/set node "innerHTML" "Hello World"))})

wilkerlucio13:06:39

5 | (ws/defcard sample-card
-------^------------------------------------------------------------------------
Use of undeclared Var my.ns/sample-card

wilkerlucio13:06:11

am I missing something here?

kwladyka13:06:02

@wilkerlucio Is it possible to require macro in clj in cljs file?

wilkerlucio13:06:33

thats how you have to do it, macros in cljs only exists in clj space, since they run at compilation time

kwladyka13:06:18

Oh I see. I didn’t write macro for cljs. I expected macro for cljs need to be in cljs files.

wilkerlucio13:06:35

no, they must be in .clj or .cljc files

👍 4
mhuebert13:06:43

@wilkerlucio is init-card itself a macro which expands to (def ~the-name ...)? I don’t see a def form in the macro so I don’t know where that var is being defined

wilkerlucio13:06:29

I said def-like just in the sense of syntax, init-card is just a function

wilkerlucio13:06:55

I don't actually def anything, the macro is just a sugar to expand the symbol

mhuebert13:06:41

Maybe you want to quote that symbol ?

mhuebert13:06:15

Now it is just expanding to a fully qualified symbol which hasn’t been defined anywhere so you are seeing that warning

mhuebert13:06:23

Most def-style macros use a real def behind the scenes to create a var which can be referenced like any other. (Not all of course.)

wilkerlucio13:06:24

fulcro for example has the defmutation macro, it doesn't output anything by default, also don't give warnings

wilkerlucio13:06:43

I'm pretty sure that's is possible to do, and shouldn't trigger a warning, my guess is that I'm just missing something stupid

mhuebert13:06:22

How do you want to reference “sample-card” later?

wilkerlucio13:06:40

I'm registering it on an atom for later usage

mhuebert13:06:03

Then maybe just quote the symbol. Won’t get a warning then

mhuebert13:06:06

Or (quote ~fqsym)

wilkerlucio13:06:07

yes! that's the stupid thing I was missing, thanks 🙂

p-himik15:06:09

When I start shadow-cljs, it prints:

shadow-cljs - Using IP "10.83.10.6" from Interface "tun0"
Jun 06, 2018 1:56:37 AM shadow.cljs.devtools.server invoke
INFO: Found multiple IPs, might be using the wrong one. Please report all interfaces should the chosen one be incorrect.
Jun 06, 2018 1:56:37 AM shadow.cljs.devtools.server invoke
INFO: Found IP:10.83.10.6 Interface:tun0
Jun 06, 2018 1:56:37 AM shadow.cljs.devtools.server invoke
INFO: Found IP:192.168.1.220 Interface:wlan0
Jun 06, 2018 1:56:37 AM org.xnio.Xnio <clinit>
INFO: XNIO version 3.3.8.Final
Jun 06, 2018 1:56:37 AM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.3.8.Final
shadow-cljs - server version: 2.3.23
shadow-cljs - server running at 
The problem here is that it uses tun0 interface, which is a VPN interface in my case. I casually switch VPN throughout the day, and when I do that, I also have to restart shadow-cljs. Maybe it shouldn't use tun interfaces? Is there anything I can do on my setup to make it always use localhost?

lwhorton16:06:40

heya guys, i’m looking for a way to build a release version of my app using shadow that replaces just a few namespaces with “mock” implementations. is there support for this somewhere? i know I can use clojure.defines via the normal compiler config options.. but i wonder if there’s a better approach, or if this is crazy. the intent is to replace just a few functions that do side-effectey/networking things with stubs so that I can run some functional tests without touching the network

kwladyka17:06:06

@lwhorton generally to mock something in Clojure just use https://clojuredocs.org/clojure.core/with-redefs

kwladyka17:06:40

For example:

(deftest wfirma
  (with-redefs [wfirma.api/request-api (constantly (read-string (slurp "test/bind-input/products-wfirma.edn")))]
    (let [products-wfirma (db-products/get-products :wfirma)]
      (testing "wfirma -> products"
        (is (every? nil? (map (partial s/explain-data ::sp/product) products-wfirma))
            "spec")
        (is (= "00014" (:code (first products-wfirma)))
            "parse")))))
or
(deftest estore->db
  (with-redefs [atomstore.soap/connection (constantly nil)
                atomstore.soap/get-products (constantly (slurp "test/bind-input/products-all.xml"))]
    (testing "atomstore->products"
      (is (= (:body (core/app (mock/request :get "/shops/hc/db/products/refresh")))
             "done")))))

kwladyka17:06:19

Simple as that 🙂

kwladyka17:06:31

No extra modules etc. Clear Clojure 🙂

kwladyka17:06:54

So you save in some files reposne from server and later use this files to bind reposne from server

lwhorton17:06:03

yea I wish I could, but my contexts are not great for with-redefs: i have a clj runtime executing webdriver ui tests, so I can’t really with-redef some cljs code to stub out implementations. like I said I think I have to pre-build the cljs component with a “global redef” and then use the clj webdriver to interact for testing

kwladyka17:06:16

hmm I remember in one project we were starting webdrive ui tests from ClojureScript code, so then it should be possible to do with-redef. I didn’t have exactly this issue before, so I don’t have solution for that.

kwladyka17:06:38

We solved that on infrastructure level

kwladyka17:06:55

for all sevices

richiardiandrea18:06:48

I still see errors when I compile with deps.edn, but this time also an error

richiardiandrea18:06:55

Failed reading cache for cljs.core: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: expected close marker for Array (start marker at [Source: java.io.FileInputStream@c0ed4f0; line: 1, column: 1893745])
 at [Source: java.io.FileInputStream@c0ed4f0; line: 1, column: 1899511]
Failed reading cache for cljs.spec.alpha: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: expected close marker for Array (start marker at [Source: java.io.FileInputStream@5aaab369; line: 1, column: 494770])
 at [Source: java.io.FileInputStream@5aaab369; line: 1, column: 501773]
Failed reading cache for cljs.core.async: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: expected close marker for Array (start marker at [Source: java.io.FileInputStream@5b8c485b; line: 1, column: 451425])
 at [Source: java.io.FileInputStream@5b8c485b; line: 1, column: 455003]
Failed reading cache for ep-cloud.util: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: expected close marker for Array (start marker at [Source: java.io.FileInputStream@1e9fc7bc; line: 1, column: 59073])
 at [Source: java.io.FileInputStream@1e9fc7bc; line: 1, column: 66261]
NullPointerException: 
	clojure.lang.Reflector.invokeNoArgInstanceMember (Reflector.java:301)
	shadow.build.output/flush-dev-js-modules (output.clj:469)
	shadow.build.output/flush-dev-js-modules (output.clj:465)
	shadow.build.targets.npm-module/process (npm_module.clj:89)
	shadow.build.targets.npm-module/process (npm_module.clj:77)
	clojure.lang.Var.invoke (Var.java:381)
	shadow.build/process-stage/fn--15264 (build.clj:140)
	shadow.build/process-stage (build.clj:137)

thheller19:06:26

@richiardiandrea can you please confirm that you are absolutely 100% certain that there is only ONE instance of shadow-cljs running at any given time for the project? not some process running a background racing another process in the foreground or anything like that? there can only be one process active at any given time for a build. I have seen the above error when 2 processes were active and tried to write the cache at the same time. that produced garbage JSON and could never be read again

thheller19:06:20

the NPE is probably from a missing :output-dir. the validation for that is missing.

richiardiandrea19:06:32

ps -ef | grep java
arichia+ 23173 22953  0 12:22 pts/1    00:00:00 grep --color=auto java

richiardiandrea19:06:51

when it runs it is:

arichia+ 23272 23266  0 12:23 pts/1    00:00:00 bash /home/arichiardi/.local/bin/clojure -J-Djava.util.logging.config.file=/home/arichiardi/git/laputa/lambda-cqrs/.shadow-cljs/logging.properties -Sdeps {:aliases {:shadow-cljs-inject {:extra-deps {thheller/shadow-cljs {:mvn/version "2.3.35"}}}}} -A:cljs-jvm:shadow-cljs-inject -m shadow.cljs.devtools.cli --npm compile init-store
arichia+ 23285 23272 99 12:23 pts/1    00:00:30 /usr/bin/java -Djava.util.... <- shadow?

thheller19:06:41

looks good and you get the above errors for every compile call?

richiardiandrea19:06:01

should I delete some folder?

thheller19:06:15

no please don't.

thheller19:06:57

please send me the .shadow-cljs/builds/init-store/dev/ana/cljs/core/async.cljs.cache.transit.json file

thheller19:06:07

want to see whats up with that and why it fails to parse

thheller19:06:02

and a clj -Stree would help although deps shouldn't play a role here. doubt there is the JSON impl that writes invalid JSON and then complains about it when trying to read it

p-himik20:06:10

@thheller Could you please check my message above about tun devices and constant IP changes? Thanks!

thheller20:06:53

@p-himik yes I'll switch the default back to localhost. detecting the IP is way too unreliable https://github.com/thheller/shadow-cljs/issues/296

richiardiandrea20:06:38

other q: is there a way to export a function as default export? I am trying to achieve this: https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#exporting-a-function

thheller20:06:48

thats currently "buggy" but you can {:target :node-library :exports some.ns/some-fn} (defn some-fn [] the-exported-fn)

thheller20:06:08

it basically ends up as module.exports = some.ns.some_fn();

thheller20:06:26

so the result of the function call ends up as the result

thheller20:06:37

shouldn't actually be the function call though

thheller20:06:43

dunno why I did it like that

richiardiandrea20:06:19

ok let me try that and then I can try to see if I can help with some fix or something..

justinlee20:06:16

@thheller just out of curiosity could shadow have an issue with the “use strict” issue that they were talking about in #cljs-dev

justinlee20:06:25

or do you do something different

thheller20:06:51

probably not since it does the same as webpack and others, ie. wrapping in a function

justinlee20:06:30

ah yea that would fix it. i wonder why dnolen doesn’t want to do that. it seems not hard to do and much safer

thheller20:06:48

well you can't do it easily with cljsjs

thheller20:06:13

the code is not processed in any way and just blindly prepended

thheller20:06:56

if you wrap that code in a functions some global it is supposed to create might not end up getting created maybe?

justinlee21:06:45

well i’ve never really understood how webpack knows what its supposed to export. you have to manually export every symbol through the iife

thheller21:06:47

I didn't follow the discussion though. not sure which problems this causes exactly.

justinlee21:06:21

the issue is that if you do blind concatenation and a script has a global “use strict”, that will break other parts of code that are not strict compliant

justinlee21:06:56

it’s likely that simply removing “use strict” will be okay, though technically you can write code that breaks without it (though not very realistic code, to be fair)

thheller21:06:13

well replacing use strict looks like band-aid rather than an actual fix

justinlee21:06:50

yes. i agree. clearly wrapping each module in an IIFE with a function-local “use strict” is much more robust

richiardiandrea21:06:31

so @thheller the exports above does not work for :npm-module it seems

thheller21:06:57

@richiardiandrea thats why I included :target :node-library explicitely when mentioning it

thheller21:06:06

it is not possible with :npm-module

thheller21:06:41

well ... it is possible

thheller21:06:59

:target :npm-module :output-dir "foo"

thheller21:06:38

index.js module.exports = require("./foo/your.ns").foo; and (defn ^:export foo [...] ...)

thheller21:06:00

just need to create the index.js manually and use that as your main "entry"

richiardiandrea21:06:13

so what is the difference between library and module ?

thheller21:06:26

:node-library creates a single file

thheller21:06:55

:npm-module creates commonjs files to they behave like any other commonjs

thheller21:06:04

so you can import namespaces individually and stuff

richiardiandrea21:06:06

oh ok that's is what I need then

richiardiandrea21:06:16

sorry I mean :node-library

thheller21:06:38

:npm-module is mostly intended to be processed by other tools, ie. including cljs output in a webpack build

thheller21:06:04

don't mistake "single file" for the single file you are after though

thheller21:06:15

single file as in .jar not uberjar

richiardiandrea21:06:14

I can basically pass one file with the exported default and give that to webpack can't I? then it will bundle node_modules + mine

thheller21:06:43

if you post-process in any way :npm-module is the way to go

thheller21:06:02

but yes :node-library will also work. its just way less flexible.

richiardiandrea21:06:26

I am at the "whatever" is faster kind of point 😄

thheller21:06:48

but does the amazon cloud stuff seriously not support installing packages via package.json?

thheller21:06:59

or azure rather?

richiardiandrea21:06:00

well, I am on azure now ......

richiardiandrea21:06:14

yeah you can but you have to have one package.json per function

richiardiandrea21:06:40

I want to produce one js per function from one cljs project

thheller21:06:21

sorry that sentence doesn't compute

thheller21:06:04

is there a full azure JS example? no idea what function means in this sense

richiardiandrea21:06:15

I know it is weird, but azure wants

fn1
  - index.js
  - node_modules
fn2
  -

fnn

richiardiandrea21:06:32

and I want to produce that from a unique clojure project

thheller21:06:06

you mean you have a clojure project that should output many azure fns?

richiardiandrea21:06:30

why? because they will all run in a REPL

richiardiandrea21:06:40

and emulate the cloud

richiardiandrea21:06:01

ok cool :node-library works

richiardiandrea21:06:10

$ node init-store/unbundled.js 
Hello World

thheller21:06:41

so what I would probably do is create a fn1 directory. put a package.json into it.

thheller21:06:15

:builds {:fn1 {:target :node-library :exports your.fn1/foo :output-to "fn1/index.js"}}

thheller21:06:21

repeat that for every fn

richiardiandrea21:06:26

yep that's what I am doing 😉

richiardiandrea21:06:00

took a bit of questioning about shadow's options

richiardiandrea21:06:10

thanks for your answer btw

thheller21:06:56

never written a azure fn but could add a :target :azure-fn if it needs some custom processing or config options

thheller21:06:29

won't get much shorter than :node-library probably

thheller21:06:49

no idea what that file is about though

richiardiandrea21:06:29

I think that bundling node in shadow would already improve things phenomenally. So that you get js + node-modules without using webpack

thheller21:06:01

(defn my-handler
  {:azure/bindings
   [{:authLevel "function"
     ...}]}
  [context req]
  ...)

thheller21:06:22

just abusing metadata on defn and the target could read that to generate the function.json

richiardiandrea21:06:25

Opened an issue for that 👼

richiardiandrea21:06:37

Ah yeah that of course is better ;)

richiardiandrea21:06:45

Also more work :)))

thheller21:06:01

5 lines of code 😉

richiardiandrea21:06:34

function.json contains a lot more

richiardiandrea21:06:46

Because a function can bind to many things not just http

thheller21:06:10

yeah but EDN can express anything that JSON can express

thheller21:06:49

but no idea about the purpose of those files and how "static" they are

richiardiandrea21:06:15

They are static yeah...but then shadow would need to know about azure functions...dunno up to you :)

thheller21:06:34

shadow doesn't need to know anything. the target does 😉

richiardiandrea21:06:38

I think the bundling is a good compromise for me ;)

thheller21:06:07

the target could technically be a library. although its not documented at all so I don't expect anyone to be able to write one.

thheller21:06:23

I'm curious now however and just created an azure account to play around 😉

richiardiandrea22:06:34

@thheller so build hooks are always clojure only right? they are executed by the jvm ?

richiardiandrea22:06:19

sorry yes, the answer is yes

richiardiandrea23:06:42

too bad the hook is not triggered here for some reason

thheller06:06:09

not triggered?

richiardiandrea15:06:11

Yeah I wanted to launch webpack on flush but that's ik. Can use bash for now, don't have really time to debug it

thheller16:06:33

maybe you forgot the {:shadow.build/stage :flush}?

thheller16:06:45

> At least one configured stage is required since the hook otherwise would never do anything.

richiardiandrea16:06:28

I copied the example in the doc basically

richiardiandrea18:06:09

The file I have in my dev folder is:

(ns ep-cloud.shadow)

(defn hook
  {:shadow.build/stage :flush}
  [build-state & args]
  (prn [:hello-world args])
  build-state)

richiardiandrea18:06:24

which is :source-paths

richiardiandrea18:06:43

and I have :build-hooks [(ep-cloud.shadow/hook 1 2 3)]

thheller18:06:09

which version are you on? it is a pretty recent addition?

spieden23:06:31

anyone know the require form and symbol to access Button.Group below via shadow-cljs?

import React from 'react'
import { Button } from 'semantic-ui-react'

const ButtonExampleGroup = () => (
  <Button.Group>
from: https://react.semantic-ui.com/elements/button#groups-group

spieden23:06:36

can’t figure it out

smnplk23:06:35

Hi guys. First time shadow-cljs user here. I just created a project with reagent, but I get the folowing error when building "The required namespace "react" is not available, it was required by "reagent/core.cljs".

spieden23:06:02

@smnplk you may just need to do npm install react

spieden23:06:32

shadow ignores the js components brought in by jars i think

wilkerlucio23:06:52

no foreign-libs in shadow, so cljsjs is ignored

smnplk23:06:22

@spieden thanks, didn't know that. Now I get a different error, The required namespace "create-react-class" is not available, it was required by "reagent/impl/component.cljs". Do i just :exclude create-react-class when requiring reagent.core ?

spieden23:06:00

same fix i believe =)

spieden23:06:13

npm install create-react-class

spieden23:06:29

i think that’s some kind of react 15 -> 16 backwards compatibility shim

smnplk23:06:49

@spieden, thank you. And thanks for the docs, I don't know how I missed these beutiful docs. Maybe I'm blind.

spieden23:06:25

sure just switching over myself

wilkerlucio23:06:42

welcome to the npm-enabled cljs world 🙂

smnplk23:06:45

Thank you guys 🙂 I see the link to docs is on github, but I overlooked because of the tempting beginners guide below.