Fork me on GitHub
#clojurescript
<
2019-08-20
>
Silenced Ego05:08:59

@thheller When using :target npm-module and wanting to use a repl via cider, I know I have to start a node process for the repl to work, but given that npm-module outputs so many files, which one do I need to run with node to get the repl to work? Or does the repl not work with this target?

thheller09:08:54

the REPL in :npm-module works but it kind of limited since everything can be done at the REPL when you are running code through webpack for example

thheller09:08:28

you can make it run by including :runtime :browser in your build config and require("./app/shadow.cljs.devtools.client.browser") in your JS

thheller09:08:13

you'll probably want to hide that in if (process.env.NODE_ENV === "development") { require(...); } so it isn't included in release builds

thheller09:08:40

need to do this in your JS manually since :npm-module doesn't have clearly defined entries

stathissideris09:08:20

hello, I’m trying to eval using (in a Chrome extension):

(defonce env-state (cljs.js/empty-state))
(defn eval-str [s]
  (cljs.js/eval env-state
                (reader/read-string s)
                {:eval       cljs.js/js-eval
                 :source-map true
                 :context    :expr}
                (fn [result] result)))
(eval-str "(+ 1 1)" works, but (eval-str "(def a 1)" fails with TypeError: Cannot set property 'a' of undefined. Could anyone think of why?

thheller09:08:05

likely that the current ns wasn't created properly. eg. trying to run cljs.user.a = 1; when cljs.user is not defined properly.

stathissideris09:08:30

@thheller thanks, that’s a useful pointer

thheller09:08:20

chrome extensions have very weird scoping rules so could be that things are just eval'd in the wrong scope

stathissideris09:08:19

I’m in uncharted waters (for me!) because I’m learning about cljs.js and chrome extensions at the same time

Lone Ranger10:08:10

I'm not sure if this is really a "#clojurescript" question or more of a general web dev question, but does anyone have a good way to invalidate browser cache when you push out a new recompiled app.js to production? Right now I've been putting version names, aka, app-v1.1.1.js, app-v1.1.2.js, etc, to get browser to DL new code, but it's pretty embarrassing when I forget to bump the version.

Roman Liutikov10:08:14

@goomba usually you’d append a hash to the file name

Lone Ranger10:08:06

you mean that in the literal sense, yes? like app.<hash-value>.js?

Lone Ranger10:08:15

Gotcha. I really need to figure out my CI/CD better >.<

Roman Liutikov10:08:51

there’s actually compiler option to include hash in the name of out file :fingerprint true

Lone Ranger10:08:32

interesting. I don't suppose you also have a neat trick for updating the HTML without having to manually change the name over? 😛

Lone Ranger10:08:08

(I'm sure I could figure it out ... some combination of directory scanning + templating, but curious if there's a better way)

Roman Liutikov11:08:42

Yeah this would require fiddling with html

herald11:08:26

I use this, which is also pretty hacky

;; Use fingerprinted (cache-busting) app.js when created for production builds.
(let [js-str "resources/public/js/compiled/app.js"
      subm (some->> "public/js/compiled/manifest.edn"
                    io/resource
                    slurp
                    edn/read-string)]
  (def js-path (-> (cond-> js-str (map? subm) subm)
                   (s/replace #"resources/public/" ""))))

herald11:08:04

basically, manifest.edn will have the data on the specific hash used

Roman Liutikov11:08:19

Since it’s for production build only, you can add hash manually and update the html as well

Roman Liutikov11:08:34

slurp js bundle -> hash -> rename js bundle -> update html

Roman Liutikov11:08:05

but this really depends on your pipeline and how you serve a page

johanatan21:08:27

given someone adept with secretary for managing routes as of circa ~2 yrs ago, is there any innovation/development in CLJS land which would warrant switching to some other framework for managing routes?

johanatan21:08:39

[assuming a greenfield project]

johanatan21:08:14

or should one in that situation merely proceed with secretary?

hkjels06:08:02

If you just need front-end routing, than secretary is just fine. I prefer reitit, but you can achieve pretty much the same with secretary if your scope is clojurescript only

oconn21:08:21

I haven’t used this but have heard great things about it https://www.metosin.fi/blog/reitit/

👍 8
oconn21:08:14

I use https://github.com/juxt/bidi for all my cljs routing and it has been meeting all our needs so far.

jsa-aerial22:08:51

Another question about self hosted CLJS and 'ambient' name spaces. Let's say we have 3 such namespaces A, B, C. Further, they have their caches loaded at init time. Now, we try to evaluate "(ns my.test (:require [A] [B] [C]))". This throws an error about *load-fn* not being set (true, it is not being set by the code). Despite already having A,B,C cache loaded in the compiler state it appears that ns forms with requires need the *load-fn* set to do something. For things like A,B,C (and core things), would this basically be a NoOp?? @mfikes

mfikes23:08:17

@jsa-aerial Yes, to create a NoOp *load-fn* have it call back with {:lang :js, :source ""}.

mfikes23:08:35

You may also be able to avoid attempts to load things by priming cljs.js/*loaded*

mfikes23:08:51

Specifically in your case @jsa-aerial you might be able to get away with doing this at init time: (swap! cljs.js/*loaded* into '[A B C])

jsa-aerial23:08:09

@mfikes Many thanks for the information. Now, just to take the other extreme - if D is not ambient but is required, then the *load-fn* needs to be able to resolve the actual source for this and hand it off, correct?

jsa-aerial23:08:25

OK, I think I am finally getting the idea how this stuff works 😬

jsa-aerial23:08:12

In that last case (assuming cljs) it should callback with {:lang :cljs, :source the-resolved-and-fetched-source)}, ccrrect?

mfikes23:08:29

The :lang would actually be :clj (even though it is the ClojureScript dialect 🙂 ) And the-resolved-and-fetched-source would be something like "(ns D) ,,,"

jsa-aerial23:08:24

Ah, OK. So the source is basically the "typical" name space at top source file for D

mfikes23:08:48

Nah, sorry, that's not what I meant by that example.

mfikes23:08:19

Perhaps a better example would be "(ns D) (def x 3)". In other words, the entire source file.

mfikes23:08:03

When you feed back that source, the self-hosted compiler is going to march through it, compiling each form.

jsa-aerial23:08:21

OK, right - that I think is still what I'm thinking - it's just that that string would be fetched (from a url, say)

jsa-aerial23:08:42

Further - anything D requires would also need to be so resolved?

mfikes23:08:12

The self-hosted compiler will take care of that as well, calling *load-fn* again when needed.

jsa-aerial23:08:06

Right - but the *load-fn* would need to be able to fetch the source for those things just like for D (assuming it isn't an ambient already cached)

mfikes23:08:45

Right, it is up to *load-fn* to somehow produce the value for :source

jsa-aerial23:08:46

Thanks so much @mfikes - this has helped a lot. Still a fair amount of futzing to do, but at least I think I know what the futzing is!!

jsa-aerial23:08:52

If you are at all interested in where / what this is all about, you might check out https://clojurians.zulipchat.com/#narrow/stream/197746-datavis-gatherings/topic/hanami.2Bsaite.20meeting

jsa-aerial23:08:31

@mfikes Wow 😮 - Works! 😂