Fork me on GitHub
#clojurescript
<
2016-04-11
>
vincentdm00:04:42

@danielcompton: I didn't know about its existence. I'm looking into it and it looks promising. Thanks!

vincentdm02:04:38

Quick question: I want to include translations in my code, based on the goog.LOCALE compiler setting. However, when I use an if-expression in my code to select the right translation file, both language files get compiled in the output (despite :optimizations :advanced).

vincentdm02:04:46

So is there a compile-time flag I can use in my ClojureScript code to exclude code branches?

danielcompton03:04:40

@vincentdm: I think you need to use ^boolean on your if expression to hint to allow the compiler to get enough information to only compile one branch

danielcompton03:04:17

e.g. (when ^boolean js/goog.DEBUG (do a thing))

viebel03:04:28

You can see how ^boolean works live here (with KLIPSE): http://blog.klipse.tech/clojure/2016/04/02/truth-in-cljs.html

slester04:04:50

hi there! anyone familiar with using secretary and the HTML 5 history API?

clumsyjedi05:04:16

I am building a node.js/cljs thing on the command line. I am having trouble running node /path/to/my.cljs when my CWD is not the dir where my.cljs is stored. I'm getting the error, Error: Cannot find module /some/dir/im/working/in/out/goog/bootstrap/nodejs.js

clumsyjedi05:04:38

I suspect the problem is this line in the generated my.js

clumsyjedi05:04:41

require(path.join(path.resolve("."),"out","goog","bootstrap","nodejs.js"));

clumsyjedi05:04:15

I think the dot in that line probably tells the node binary to resolve the “out” dir relative to the CWD, but I have no idea how I might change that behaviour

danielcompton07:04:11

@clumsyjedi: I’m not too familiar with node on cljs, but is https://github.com/clojure/clojurescript/wiki/Compiler-Options#asset-path helpful?

clumsyjedi07:04:09

looks promising, thanks danielcompton

vincentdm08:04:47

Thanks @danielcompton. It's not ideal for a locale setting but it provides a workaround where I could set a boolean for each language in each build profile.

danielcompton08:04:28

a case statement might work too? Not sure which ones closure can optimise away?

danielcompton08:04:25

probably worth looking to see how Google do it, I imagine they probably do per language builds too

vincentdm08:04:52

Are their closure-based projects also open source?

danielcompton08:04:11

not AFAIK, but there’s probably some example code around

vincentdm08:04:51

ok, I'll hunt for it simple_smile

sivakumargsk08:04:05

Hey, I got a problem with a checkbox in reagent-forms. For old version it works fine [reagent-forms "0.5.21"] but for new version [reagent-forms "0.5.22"] it doesn't work well. The problem is the checkbox is not turned into unchecked when I click on the checkbox. But my atom is changed. This is my code (defn home-page [] (let [doc (atom {:name true})] (fn [] [:div [:p (str @doc)] [bind-fields [:input {:field :checkbox :id :name}] doc] [:button.btn.btn-default {:on-click #(reset! doc nil)} "clear"]])))

vincentdm08:04:51

@danielcompton: type hinting with ^string didn't work, so I opted for this workaround:

vincentdm08:04:52

(def messages (cond ^boolean (= js/goog.LOCALE "fr") http://i18n.fr/messages ^boolean (= js/goog.LOCALE "nl") http://i18n.nl/messages))

vincentdm09:04:13

I checked the compiled output and it excludes the branches correctly

vincentdm09:04:15

yeah, but it is only in 1 point in my code, so I'm willing to live with it. I tried using a macro to do the conditional before compilation to JS, but didn't manage to get the goog.LOCALE working there. But thanks for your help anyway

danielcompton09:04:40

np simple_smile nasty hacks are sometimes ok simple_smile

mfikes11:04:44

@vincentdm: The ^boolean hints in the cond form above shouldn't be necessary—this is because = has a hinted return value.

dnolen12:04:07

@vincentdm: using case may be a more succinct way to write that - case compiles down to switch

dnolen12:04:56

and yes don’t add ^boolean type hint unless you really know why.

vincentdm12:04:10

@mfikes @dnolen Unfortunately my approach didn't work after all. I was checking a stale build and it turned out that the closure compiler always includes the code in both branches. I have tried a lot of approaches to exclude it (including a macro which I tried to run before closure compilation) but nothing worked, so I accepted defeat and am now taking an approach of loading translations in a separate http request during runtime.

vincentdm12:04:38

To be clear: executing the right branch works, but the other code is also present in my :advanced build, which needlessly increases the size

mfikes12:04:13

@vincentdm: from a high level, it looks like you want to statically optimize for a given fixed locale … but the locale is dynamic, right?

vincentdm12:04:38

no it can be totallly fixed. I have a separate cljsbuild profile for each language

vincentdm12:04:56

users switching language is such a rare event that I am willing to let them re-download the entire app bundle when they do it

mfikes12:04:36

Ahh. Understand… hmm. So, I wonder if there is an analog if the goog DEBUG stuff for this situation.

vincentdm12:04:56

So what I expected was that branching according to the goog.LOCALE from profile's :closure-defines would also eliminate the code in the other brancges

mfikes12:04:28

One heavy-handed approach is to introduce an additional source path that varies per locale.

mfikes12:04:33

Then, say in the "en" path it can statically include only those resources

vincentdm12:04:34

By te way, I also discovered the same problem with boolean branching according to the goog.DEBUG :closure-define: even when debug is set to false, the code inside the dev branches is included in the compiled file. It is not executed, but it is present.

vincentdm12:04:52

That's something I didn't consider yet... that would work yeah

mfikes12:04:08

Coarse-grained DCE :)

vincentdm12:04:42

But I'm surprised about how little I can find about i18n in clojurescript SPA's

vincentdm13:04:47

Thanks @mfikes ! Your approach worked!!

mfikes13:04:45

I suspect i18n is one of those mundane things which, once solved, people don’t feel compelled to write about it—leading to a dearth of info on it. 😞

dnolen13:04:15

@vincentdm: which is why I suggested case

dnolen13:04:27

I recall testing this before and it working

dnolen13:04:41

GCC will DCE switch statements and cascading if/else

dnolen13:04:20

you don’t want = for this though, use identical? instead if you’re using nested ifs

dnolen13:04:25

GCC doesn’t know anything about Clojure’s notion of equality

plexus14:04:33

I'm having trouble using Figwheel on a non-root URL, because it's injecting <script> tags with relative urls. Is there any way around this?

plexus14:04:33

e.g. on it's creating a <script src="js/compiled/out/goog/base.js"></script>, which resolves to /foo/js/compiled/... instead of /js/compiled/...

rauh14:04:02

@plexus: Change your :asset-path in your compiler opts. Ie add a / at the beginning

plexus14:04:30

@rauh: thanks, I'll give that a try

slester16:04:18

Does anyone have Secretary + the goog.history API experience? Things route correctly if I go to, say, localhost:3449/#/page/subpage, but links on that page won't change the URL bar. They follow and load correctly, but they don't seem to be editing the URL/location bar at all. Insights or things to look for much appreciated! I'm following @yogthos 's guide http://yogthos.net/posts/2014-08-14-Routing-With-Secretary.html pretty closely but no dice.

roberto16:04:17

Secretary doesn’t change the url for you.

roberto16:04:00

you would have to manually do it, or add a function that is triggered everytime by the route that does that

jonathandale17:04:40

@slester: Pushy is a cljs lib for html5 pushstate: I’ve used it successfully with secretary: https://github.com/kibu-australia/pushy

slester17:04:11

Ah, OK. That seems strange to me, but it explains a lot! Thanks @roberto + @jonathandale -- I'll check that out

lwhorton17:04:29

I’m having a really weird problem with the compiler’s foreign-libs, can someone point out what I’m doing wrong here?

lwhorton17:04:52

(using boot, but it shouldnt matter because it does nothing with the foreign-libs option) 1) in build.boot declare :compiler-options {:foreign-libs [entry] where an entry looks like {:file “main/index.js” :provides [“theThing”] :module-type :commonjs } 2) place /main/index.js underneather src/js/ 3) index.js looks like a simple module.exports = function theThing(args) { console.log(arg) } 4) from another cljs module (ns main.core (:require [theThing])

lwhorton17:04:19

I’ve tried not using :module-type and getting rid of module.exports (doesnt work). I’ve also tried moving the js source around to different places (resources vs src) and updating the env :source-paths and :resource-paths, but just nothing works.

lwhorton17:04:33

The error is always No such namespace: theThing, could not locate theThing.cljs, theThing.cljc, or Closure namespace "theThing" in file

lwhorton17:04:37

I checked with the boot guys over in #C053K90BR, but it’s not specific to their tool

jr17:04:18

@lwhorton: not sure if it helps but I declare foreign libs in src/cljs/deps.cljs

jr17:04:04

where the content is a map

{:foreign-libs [{:file “main/index.js"
                         :provides [“theThing”]}

lwhorton17:04:05

hmm, just tried that out and I get the same namespace issue 😕

vincentdm18:04:49

@dnolen: thanks for the tip, but the switch statement doesn't solve it. It results in a JS switch statement with obvious dead trees, but still they are included.

vincentdm18:04:51

(def message (case js/goog.LOCALE "nl" http://tools.nl/message "fr" http://tools.fr/message "nl"))

vincentdm18:04:35

function(){switch("nl"){case "nl":return"Dutch";case "fr":return"French";default:return"Dutch"}}();

vincentdm18:04:55

I would have expected the Closure compiler to catch this and remove the dead branches

vincentdm18:04:57

I realize that this is an issue of the Closure compiler and not of CLJS, but I guess I'll have to accept it? 😕

jetzajac18:04:59

is it still impossible to resolve vars in runtime in cljs?

jetzajac18:04:17

I really want to store symbols in db, send by wire etc.

dnolen18:04:29

@jetzajac: it will never be possible in general because of advanced compilation

jetzajac18:04:32

@dnolen: I see, I still can use externs, it’s ok if it is my responsibility to care about that..

jetzajac18:04:28

is it impossible as well in hosted version?

dnolen18:04:32

sure if you export or use externs, then yes you can resolve things at runtime but you don’t really need ClojureScript to help you in that case

dnolen18:04:49

in self-hosted ClojureScript we need to be able to resolve vars - so it works there.

dnolen18:04:21

so OK for apps - I wouldn’t do it in libraries intended to be shared with other people since that won’t compile under advanced

jetzajac18:04:05

could you give me idea how to do that? How do I lookup into ns?

jetzajac18:04:44

it’s just a normal js objs, right? how do I get an instance?

jetzajac18:04:57

@dnolen: oh I got it, thanks!

vincentdm18:04:42

@dnolen: I opened an issue at the Google Closure repo, for what it's worth. I'll continu with using separate source-paths for now, but hopefully they will get better at this in the future. Thanks for your help anyway. It's amazing how supportive the CLJ(S) community is. Three weeks into the Clojure world I'm still amazed.

dnolen18:04:09

@vincentdm: ok then I misrememberd you wanted nested JS if/else. cond + identical? should work in this case

dnolen18:04:17

or condp + identical? for less verbosity

vincentdm18:04:59

So you think this has a chance of making the compiler eliminate the code?

dnolen18:04:29

@vincentdm: I just thought switch worked - I know if/else does

vincentdm18:04:56

the condp doesn't work either. Well, to be clear: the code runs correctly (it always has), it's just that the unreachable branches are also included in the minified output.

vincentdm18:04:07

I tried if-else yesterday, and it was the same.

vincentdm18:04:30

Maybe this only works when directly comparing a goog flag as boolean?

dnolen18:04:31

@vincentdm: doesn’t work is less informative then a gist showing what you tried

dnolen18:04:45

the ClojureScript code and the generated output please

slipset18:04:16

I’m working on a port of data.csv to clojurescript

vincentdm18:04:32

But the problem seems to be the Closure Compiler, since the flags are properly parsed when cljsbuild generates the javascript.

vincentdm18:04:44

And closure doesn't recognize the dead branches

vincentdm18:04:55

I'm making an empty project to replicate my steps

dnolen18:04:58

@vincentdm: just gist the ClojureScript and the generated code

slipset18:04:00

I’ve got it all working under lein, but I can’t get the tests to run under mvn test, which is needed for the CI stuff.

dnolen18:04:03

no need for a project

dnolen18:04:16

I’ve stared enough at the generated JS to know what will happen

dnolen18:04:38

@vincentdm: simple optimization + pretty-print will suffice for the generated output

slipset18:04:57

Exception in thread "main" java.io.FileNotFoundException: Could not locate clojure/data/test_runner__init.class or clojure/data/test_runner.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(/var/folders/ps/3v9y4vt15r1083hq6ymj0q980000gn/T/run-test521275451258951945.clj:21:1)

slipset18:04:16

test_runner is a cljs file.

vincentdm19:04:44

@dnolen: I tried to replicate my problem in a simple folder using the cljs.jar compiler with three source files but there it works correctly. The condp identical? branching is transformed into a scalar in the output. So it must be something about the config of my project (cljsbuild project with latest clojurescript version as a dependency). But I'm glad that it is in fact possible to eliminate branches based on the goog.LOCALE setting. I'll just have to find out what difference is causing this...

vincentdm19:04:22

@dnolen: turns out my test was wrong and the problem does exist. I made a gist like you asked: https://gist.github.com/vincent-dm/30701e1dbd5d13beb30b8e5e856e6fda

dnolen19:04:17

@vincent: let’s stop staying a problem exists for now

dnolen19:04:30

nothing you’ve said points to anything specific

dnolen19:04:43

wrt. to whether DCE actually works or not

dnolen19:04:22

@vincent: it appears condp introduces locals and for some reason doesn’t propagate the boolean return when assigning the predicate fn to a local

dnolen19:04:34

@vincent: so just try with verbose cond + identical?

vincentdm19:04:06

I'll refer to it as my problem then 😉

vincentdm19:04:09

I'll try the cond

vincentdm19:04:58

@dnolen: it seems the cond + identical works, but given my previous jumping to conclusions, I'm going to try a few variants. Thanks for the pointer, as I could never have guessed that such subtleties would have such impact on the compilation.

dnolen19:04:21

@vincentdm: the subtleties are really an illusion

dnolen19:04:41

Google Closure DCE’s if/else + == or ===

ronald19:04:44

I have quick question. I have js file i load that contains a function handleSomething(args). How do i call that directly in my cljs file. (js/handleSomething args) doesn’t do the trick. Any ideas?

dnolen19:04:57

I said that several times - the problem is whether the ClojureScript you’re writing produces that identical JavaScript

dnolen19:04:13

there’s no guarantee of course that it should since you’re not writing JavaScript

dnolen19:04:35

whether various combinations you try work or don’t work are completely inrrelevant

dnolen19:04:46

i.e. fixing condp doesn’t address the fundmental problem

vincentdm19:04:18

I can see that now. But I guess a lot of people are wrongly assuming that any conditional based on a goog.* compiler option would lead to DCE. For example, the template I based my project on uses (def debug? ^boolean js/goog.DEBUG), and it turns out that branches based on that debug var are still included (not executed though).

vincentdm19:04:44

So I'm not saying that anything is broken or should be changed, but maybe we can add a pointer in the docs about it?

dnolen19:04:40

sure it’s probably worth mentioning in the places where we talk about Closure Defines

vincentdm19:04:45

I can make a pull request

dnolen19:04:03

@vincentdm: no PRs needed for the wiki just change it

dnolen19:04:18

just say use if or cond + identical?

dnolen19:04:31

note that case nor condp will work if you want DCE

ronald19:04:45

@dnolen I have quick question. I have js file i load that contains a function handleSomething(args). How do i call that directly in my cljs file. (js/handleSomething args) doesn’t do the trick. Any ideas?

dnolen19:04:59

@ronald: there’s no need to direct questions at me

ronald19:04:21

alright sorry about that

dnolen19:04:01

that said, you haven’t provided enough information to know what your problem is

dnolen19:04:15

if that js file declared a global thing - yes that will work

dnolen19:04:46

assuming you either aren’t using advanced compilation - if you are you must supply an extern for that fn

ronald19:04:13

thanks … That makes sense.

vincentdm19:04:35

Thanks again for your help, I hope I'll be able to pay forward one day

dnolen19:04:50

@vincentdm: thanks much! I tweaked the formatting a bit - but otherwise looks great

mksenzov20:04:23

Hi all, I have a perhaps very naive question: I see that CLJS -> JS compiler seem to generate a number of document.write operations, making it hard to use that sort of scripts with “async” or “defer” keywords in the script tag. Is there some known workaround for this (aside of not using async)?

dnolen20:04:29

@mksenzov: that’s only for dev, not for production - so it doesn’t actually matter in practice

mksenzov20:04:27

@dnolen: thank you, that make sense. So when you refer to the ‘production’ mode - is this something enabled by one of the multiple optimization modes in CLJS?

dnolen20:04:51

yes - ClojureScript is designed around Google Closure Compiler advanced optimizations

dnolen20:04:01

a single final production file - (which can be code split if you like)

mksenzov20:04:34

got it, thank you!

viebel21:04:50

A question related to extend-type for IFn protocol

viebel21:04:39

Why the transpiled code contains implementation for call, apply and also cljs$core$IFn$_invoke$arity$1?

viebel21:04:23

In my understanding, the code for cljs$core$IFn$_invoke$arity$1 is not required

dnolen22:04:07

@viebel compiler questions are probably best to direct at #C07UQ678E not here