Fork me on GitHub
#clojurescript
<
2018-09-14
>
Garrett Hopper01:09:13

@dnolen, I am assigning to global in the :foreign-libs :file/bundle, whenever I try to use something from the provided namespace, I get a cannot read property ... of undefined. My assumption was that :global-exports had a reliance on window or something.

Garrett Hopper01:09:00

Ah, and presumably that switches to global in nodejs just fine?

mfikes01:09:09

:global-exports works with Node, FWIW

mfikes01:09:06

There is a tiny repro in this ticket (really meant to illustrate an issue for the browser REPL), but it illustrates a very simple setup that works in Node https://dev.clojure.org/jira/browse/CLJS-2854

Garrett Hopper01:09:04

Hmm, interesting. I had global.myLib = { abc: 3 }, since I was doing window.myLib for my browser bundles.

Garrett Hopper01:09:34

@mfikes, maybe I'm just missing something: # Files ├── build.edn

{:target        :nodejs
 :optimizations :simple
 :foreign-libs  [{:file           "bundle.js"
                  :provides       ["example"]
                  :global-exports {example EXAMPLE}}]}
├── bundle.js
EXAMPLE = {identity: function(x) {return x;}};
└── src └── example └── core.cljs
(ns example.core
  (:require
   [example]))

(js/console.log (example/identity "test"))
# CLI clj -A:cljs -co build.edn -re node -m example.core # Error
Exception in thread "main" clojure.lang.ExceptionInfo: repl:1
console.log(example.core.global$module$example.identity.call(null,"test"));
                                               ^

TypeError: Cannot read property 'identity' of undefined
    at repl:1:48
    at ContextifyScript.Script.runInThisContext (vm.js:50:33)
    at Object.runInThisContext (vm.js:139:38)
    at Domain.<anonymous> ([stdin]:76:38)
    at Domain.run (domain.js:242:14)
    at Socket.<anonymous> ([stdin]:73:29)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at addChunk (_stream_readable.js:263:12)
    at readableAddChunk (_stream_readable.js:246:13) {:type :js-eval-exception, :error {:status :exception, :value "repl:1\nconsole.log(example.core.global$module$example.identity.call(null,\"test\"));\n                                               ^\n\nTypeError: Cannot read property 'identity' of undefined\n    at repl:1:48\n    at ContextifyScript.Script.runInThisContext (vm.js:50:33)\n    at Object.runInThisContext (vm.js:139:38)\n    at Domain.<anonymous> ([stdin]:76:38)\n    at Domain.run (domain.js:242:14)\n    at Socket.<anonymous> ([stdin]:73:29)\n    at emitOne (events.js:116:13)\n    at Socket.emit (events.js:211:7)\n    at addChunk (_stream_readable.js:263:12)\n    at readableAddChunk (_stream_readable.js:246:13)"}, :repl-env #cljs.repl.node.NodeEnv{:host "localhost", :port 56100, :path nil, :socket #object[clojure.lang.Atom 0x55d58825 {:status :ready, :val {:socket #object[java.net.Socket 0x512575e9 "localhost/127.0.0.1,port=56100,localport=40480]"], :in #object[java.io.BufferedReader 0x6f1a16fe "java.io.BufferedReader@6f1a16fe"], :out #object[java.io.BufferedWriter 0x2373ad99 "java.io.BufferedWriter@2373ad99"]}}], :proc #object[clojure.lang.Atom 0x19a64eae {:status :ready, :val #object[java.lang.UNIXProcess 0x33634f04 "java.lang.UNIXProcess@33634f04"]}], :state #object[clojure.lang.Atom 0x29a98d9f {:status :ready, :val {:listeners 0}}], :debug-port nil}, :form (js/console.log (example/identity "test")), :js "console.log(example.core.global$module$example.identity.call(null,\"test\"));\n"}

Garrett Hopper01:09:31

No combination of changes to the bundle.js seems to work.

Garrett Hopper01:09:51

(`global.EXAMPLE`, etc.)

Garrett Hopper01:09:25

(= js/goog.global.EXAMPLE nil)

Garrett Hopper02:09:23

@mfikes, Hmm, this.EXAMPLE = {identity: function(x) {return x;}}; seems to work.

mfikes02:09:51

I'd log a JIRA. Perhaps this stuff was only tested for Node under :none?

mfikes02:09:14

It is failing on master as well, and I don't recall a JIRA for this case.

Garrett Hopper02:09:23

Alright, I'll go ahead and create one.

Garrett Hopper02:09:46

I'm not sure how :none is different exactly, but this this makes sense, since the compiler just puts the raw bundle in the output and then afterwards: goog.global=this.

Garrett Hopper02:09:39

Hmm, it looks like :none ends up with goog.global=global instead of this. This seems like a completely different issue.

Garrett Hopper02:09:58

Perhaps a Closure issue though?

ampersanda11:09:38

Excuse me, I want to create a login system with re-frame, is anyone has reference/article/short explain about that? Thank you

hlolli11:09:33

@ampersanda are you using Clojure for the server side?

ampersanda11:09:41

@hlolli: currently I am not yet using server, but I will using Clojure also as a server side

hlolli11:09:50

If a login system means protecting data from public, then you'd want to look at cemerick's friend or funcool's buddy. Also yada and plenty of options, you can use a session cookie or json webtoken based authorizations, depending on the library you choose.

ampersanda11:09:02

@hlolli: thank you so much, I'll check those.

Stephens12:09:46

any thought on how to accomplish this looking for a way to be able to create a SPA Shell application that would consume a REST Service that would tell it the location and name of the component that it was to render. The SPA would then simply load the componet in and display it based on a common interface the basic components would implement. However I do not want the need to include the references in the SPA as these componet will be built over time and shared across many systems. So for Example Team A is be responsible for the display of the main page of the applicaiton and it general flow, Team B is responsible for the sub component B and the parts that make it up, and finally Team C is responsible for the sub component C. Team A application is provide that it needs to render components B and C at run time within their SPA. and in the future Component D might come along and need to be render and simply by adding it to the call return the SPA starts to show with out the need to change or bind to the component Conceptually the site might look like these Web Site A – Host the SPA Application, Team A hosting application lives here. Web Site B (CDN) – Host the individual web components that SPA would Use, On the client SPA would make calls out to the CDN to pull in the latest version of the components that are published to Web Site B The issue I have been coming up against is the apparent need to pre-link the libraries into the SPA. is there an example or white paper somewhere that might describe an approach to accomplish this.

dnolen12:09:34

I think it’s very uncommon to structure things in this way due to network latency

dnolen12:09:33

certainly it’s not recommended as web best practice and tooling like Google Closure (which Google uses on all their major JS properties) are specifically designed in opposition to such designs

dnolen12:09:27

@ghopper AWS Lambda? Curious why you need need something other than :none

Stephens12:09:34

The ideal is that we are creating web components for each vertical slices that each team will be responsible for and the need to not have team B require team A to do a recompile and deploy to get their changes migrated. but the component might be accessed by a couple different applications so the dependencies increase, desire is that once team b publishes there tested changes they start to show up in all the app that reference the component.

Stephens12:09:13

But if it is not possible just attempting to confirm and we can explore other options to remove this dependency

dnolen13:09:19

not so much as not possible as not recommended - but you can maybe make that design work with goog.module? Not sure since I haven’t ever used it, and this approach isn’t that popular among users

Garrett Hopper13:09:21

@dnolen Yeah, AWS Lambda. I'm building the foreign libs with browserify.

Stephens13:09:43

@dnolen Seems this is just be a more advanced form of Code Splitting, the best practices do make me want ta second look at approach but just curious how do you see this crossing a line that code splitting is not.

dnolen13:09:34

sure but that’s one kind of code splitting

dnolen13:09:46

Closure’s kind is different - whole program - requires recompilation if stuff changes

john14:09:41

Maybe if you had a compiler service that had a constantly running incremental build. Then different teams could push code the the compile folder and it'd push out splits all using the same artifacts. Complicated though.

pvillegas1214:09:00

I want (-> "ns/hello" (clojure.string/split #"\/") last) to work in cljs but apparently the reader is erroring out when it finds the / in split

pvillegas1214:09:49

Any workaround?

pvillegas1214:09:02

reload-failed SyntaxError: Invalid regular expression flags @john

john14:09:26

hmm, I'm not getting that

pvillegas1214:09:23

@john totally works! thanks 🙂 I did not remove a previous invocation of it

👍 4
dnolen14:09:02

@jeff.stephens the friction about what you’re suggesting is that Closure simply does not support independent builds

dnolen14:09:21

that said I’m just not convinced about the benefits of the approach you are suggesting

dnolen14:09:36

recompile + fingerprint - I don’t see how you can run into problems

idiomancy15:09:41

so, I'm trying to figure when and how subscriptions in re-frame are recalculated and I'm pretty confused by the results I'm seeing..

(rf/reg-sub
  :get-account-balance
  (fn [db _]
    (js/console.log "recalculating GET")
    (:account/balance db)))

(comment
  @re-frame.db/app-db
=> #:account{:balance 800}
  @(rf/subscribe [:get-account-balance]))
when I eval that subscribe repeatedly in the repl, it's printing the console.log over and over again.. I would have expected it to only print once and cache the results since the app-db hasn't changed and there are no inputs 😕

idiomancy15:09:10

is there something I'm missing?

kwladyka15:09:56

import Grid from "@material-ui/core/Grid"; with webpack (:require [grid]) in ns (def grid (r/adapt-react-class grid)) in ns Uncaught Error: Assert failed: Component must not be nil <- Why? The “same” code work with shadow-cljs.

kwladyka16:09:22

I solved it, I have to do [grid :as grid2]

thheller15:09:46

(:require [grid])? that wouldn't work in shadow-cljs either?

kwladyka15:09:02

this code is with webpack solution

kwladyka15:09:21

Yes, I mean in shadow I use ["@material-ui/core/Grid" :default Grid] instead

kwladyka15:09:19

Trying to learn this webpack things with cljs

rkiouak15:09:45

apologies for cross post, but the cljsjs channel seems a bit quiet: could anyone help with beginner cljsjs & externs use question here: https://clojurians.slack.com/archives/C0E66E1H7/p1536937815000100

kwladyka15:09:50

Did you try (js/ReactChartjs2.Pie. (clj->js {:data data)}?

kwladyka15:09:54

but probably it is not solution of your issue

rkiouak15:09:23

ah figured it out -- needed to call js/React.createElement and pass the js/ReactChartjs2.Pie class

rkiouak15:09:14

ah figured it out -- needed to call js/React.createElement and pass the js/ReactChartjs2.Pie class

kwladyka16:09:36

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
  index_bundle.js (303 KiB)
Can I optimise this things with cljs and webpack?

kwladyka16:09:33

This file will be bigger and bigger. Can I split it in some way?

kwladyka16:09:46

Do whatever to optimise it

thheller16:09:14

did you compile with webpack -p?

thheller16:09:42

then probably not no

kwladyka16:09:08

hmm no good practice to split it to load when it is needed?

kwladyka16:09:22

Like I don’t need every deps on every pages

thheller16:09:32

it is. but good luck getting that to work 😉

kwladyka16:09:34

At least not when loading page

thheller16:09:58

its definitely easier in shadow-cljs and part of the reason why shadow-cljs doens't use webpack to begin with

kwladyka16:09:25

I was reading it, but I didn’t get the point of main reason

thheller16:09:46

point is that code splitting works differently in webpack and is not easily combined with how code splitting is done in closure

thheller16:09:17

I couldn't get it to work ... and that might tell you something about how complicated it is.

kwladyka16:09:40

yes, you are definitely more experience than I about js

kwladyka16:09:08

So how shadow-cljs do it? It load deps only when needed?

kwladyka16:09:40

Ech sometimes I think cljs is a hell of js 🙂

kwladyka16:09:00

or hell cljs in hell js 🙂

kwladyka16:09:42

I have to go to help wife carry things from bus 🙂 brb

johnj16:09:44

does the closure library has utilities for validating forms?

kwladyka17:09:21

I did opensource, but I don’t have time to publish it as library… I will try in next week

kwladyka17:09:40

My solution work with fn and spec

johnj20:09:36

yeah, looks like spec is the way to go

sb19:09:22

I would like to use macros in Clojurescript. I found this article… http://blog.fikesfarm.com/posts/2016-01-05-clojurescript-macros-calling-functions.html .. what is the best way use macros in cljs? or is that bad idea?

enforser19:09:52

it is fine to use macros in cljs! You just need to define them in clj files and require them differently. https://clojurescript.org/about/differences#_macros

mfikes20:09:43

@sb Here is another resource regarding macros and ns-form considerations: https://clojurescript.org/guides/ns-forms

sb20:09:17

@mfikes thanks! could you help, why isn’t work for me

(defmacro add
  [a b]
  `(foo.core/add* ~a ~b))
when call a function, then not works.. I tried with same ns and different ns plus without foo.core .. but not helps. I got #object[TypeError TypeError: Cannot read property 'call' of undefined]

sb20:09:51

or #object[TypeError TypeError: Cannot read property 'add*' of undefined]

mfikes20:09:21

Is foo.core/add* in a ClojureScript namespace that has been requried?

sb20:09:06

(:require-macros [chart.macro :as my])

sb20:09:19

I tested with that, chart.macro is foo.core

mfikes20:09:20

To be honest, I'd set up a core.cljs and core.clj as described here http://blog.fikesfarm.com/posts/2018-08-12-two-file-clojurescript-namespace-pattern.html This post describes a common pattern.

mfikes20:09:34

Hmm... do you have a link to your source?

sb20:09:05

One moment.

mfikes20:09:23

Thanks. Even a minimal gist is useful.

sb20:09:06

(ns gchart.else)

(defn addide
  [a b]
  (+ a b)) 

(defmacro add-now
  [a b]
  (addide a b)) ;ok

(defmacro add
  [a b]
  `(addide ~a ~b)) ;fail

(defmacro ooio
  [string]
  `(prn ~string)) ;ok 

sb20:09:27

(ns gchart.macro
  (:require-macros [gchart.else :as my])
  (:require [reagent.core :as reagent :refer [atom]]))




(my/add 1 2)

sb20:09:37

I copied here, because that is really small.

mfikes20:09:11

Yeah. The problem is that addide is defined in Clojure, but the macro expands to call it at runtime, so addide needs to instead be defined in ClojureScript.

mfikes20:09:40

For add-now, addide is called during macroexpansion, so in that case it is fine.

sb20:09:46

ok!! I understand. Sorry!! :face_with_rolling_eyes:

sb20:09:07

Thanks!! 🍻

mfikes20:09:53

@sb if you create a else.cljs file, you could put your addide in there and then furthermore if you have that ClojureScript namespace :require-macros on gchart.else, then when you go to consume it you won't have to use :requrie-macros and you can instead consume it just like you would in Clojure. (That's the subject of that "Two-File" post referenced above.)

mfikes20:09:39

In that post inverse* is analogous to your addide.

sb20:09:23

works! thx

sb20:09:09

Thank you ver much! I read now. That is very helpful. 👍 I test now!

dpsutton22:09:01

is there a commonly used benchmarking solution like criterium but for clojurescript?

dpsutton22:09:52

Thanks Mike

puppybits22:09:10

I just spent over a week getting re-natal setup with Circle CI, Fastlane and upgrading to React Native v0.57. I posted a gist with all the details incase anyone has the same issues. https://gist.github.com/puppybits/95183d5ff74098edf5998abdc4ffdadc

👍 12