This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-01
Channels
- # aleph (2)
- # beginners (137)
- # boot (4)
- # cider (10)
- # clara (29)
- # cljs-dev (71)
- # cljsrn (7)
- # clojure (105)
- # clojure-bangladesh (1)
- # clojure-france (2)
- # clojure-italy (4)
- # clojure-nl (3)
- # clojure-russia (1)
- # clojure-spec (30)
- # clojure-sweden (5)
- # clojure-uk (71)
- # clojurescript (217)
- # cursive (36)
- # data-science (1)
- # datomic (11)
- # duct (53)
- # fulcro (2)
- # garden (3)
- # jobs (1)
- # lein-figwheel (23)
- # luminus (3)
- # lumo (7)
- # mount (13)
- # off-topic (88)
- # pedestal (3)
- # re-frame (63)
- # reagent (85)
- # remote-jobs (1)
- # ring-swagger (3)
- # shadow-cljs (81)
- # spacemacs (5)
- # tools-deps (16)
- # yada (2)
I'm trying to port a big app to use shadow, I'm trying to start by using the lein profile, but when I try to compile I'm getting:
Exception in thread "main" java.io.FileNotFoundException: Could not locate cljs/externs__init.class or cljs/externs.clj on classpath., compiling:(shadow/build/cljs_bridge.clj:1:1)
at clojure.lang.Compiler.load(Compiler.java:7526)
at clojure.lang.RT.loadResourceScript(RT.java:379)
at clojure.lang.RT.loadResourceScript(RT.java:370)
at clojure.lang.RT.load(RT.java:460)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:2793)
at shadow.build.classpath$eval17191$loading__6434__auto____17192.invoke(classpath.clj:1)
at shadow.build.classpath$eval17191.invokeStatic(classpath.clj:1)
at shadow.build.classpath$eval17191.invoke(classpath.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:7062)
any idea what that can be?
I tried moving the deps and source-paths directly to shadow-cljs.edn
, it works there, so it's something around lein integration
@wilkerlucio probably a dependency pulling in an old CLJS version. when using shadow-cljs it adds :exclusions [org.clojure/clojurescript]
automatically for every dep to avoid that
@kwladyka this is a problem due to loading goog.History
. It uses document.write
to insert an iframe dynamically.
(defn do-route [token]
(->> token
(bidi/match-route route)
(handler)))
(defn hook-browser-navigation! []
(doto (History.)
(goog-events/listen
EventType/NAVIGATE
(fn [event]
(do-route (.-token event))))
(.setEnabled true)))
(defn dev-setup []
(when config/debug?
(println "dev mode")))
(defn ^:dev/after-load mount-root []
(re-frame/clear-subscription-cache!)
(reagent/render [views/page]
(.getElementById js/document "app")))
(defn ^:export init []
(re-frame/dispatch-sync [::events/initialize-db])
(dev-setup)
(mount-root)
(hook-browser-navigation!))
this should work. basically you must avoid constructing a History
object twice. so the above calls it in init
once and not in start
which is called for each live-reload.
@tony.kay I use react
v16. a React
global only exists when you use cljsjs.react
since by default there will be no React
global exported?
https://github.com/thheller/shadow-cljsjs/blob/master/src/main/cljsjs/react.cljs#L4 this creates the global
@thheller ah thank you. I don’t know how I was checking it yesterday. Maybe because it was after midnight 🙂
What is your personal opinion about using such solution to let users copy & past URLs? Do you know something better? What do you use?
what do you mean? using urls to route application state? that is pretty much considered best practice and good.
although I probably recommend using goog.history.Html5History
instead since that uses normal paths instead of append #/...
the idea is the same, use the url to construct the initial state of your application. either the url can be /foo/bar
or url#/foo/bar
. the first requires server support while the second doesn't. but beyond that they pretty much work the same
yeah the server must be aware of all the urls you may be constructing client side. with url#
it just needs one
Will it work with shadow-cljs? When I will have localhost:8020/foo/bar/baz
and click refresh?
that is commonly known as pushState
routing. the shadow-cljs server will serve the index.html
by default for all urls that don't exist otherwise
if one wants to add spec instrumentation during dev: that's done with build-hooks, right?
oh, hooks are clojure functions? - need plain cljs functions to instrument only during dev. Will check docs again 😛
@kurt-o-sys We had a lot of trouble adding spec-instrumentation, if you get it working correctly we would be interested in how you did that
@thheller Well, it is a fulcro project, and Fulcro works fine with React 16. In fact, this project has worked in release mode before, it just started breaking. I tried backing out to an older versino of the compiler, but that does not fix it. I suspect perhaps some new dependency was added that perhaps confused things. If I compile in dev mode it is fine. If I do release with any level of optimization it breaks, but differently based on which optimization level I choose. At whitespace it crashes on a line that is trying to set goog.debug.Error= something (debug isn't defined). At simple and above it is React.
@thheller You are right: removing the preloads breaks it…so it must be that react isn’t being pulled in correctly
Ah, I think it was Fulcro…I was missing a require of cljsjs.react in one of the files, which confuses the dep order. Trying a fix
@mitchelkuijpers I'm not 100% sure if it works as it should. I get too many validation errors, unless it's justified I get them 🙂 - still analyzing that part. However, this is what I did:
(ns ui-app.core
(:require-macros [secretary.core :refer [defroute]])
(:import goog.History)
(:require ...
[orchestra-cljs.spec.test :as st]
...))
...
(defn ^:dev/after-load start
[]
(println "starting...")
(let [...
dev ...
...]
(when dev
(println "instrumenting...")
(st/instrument))
...))
...
in another namespace:
(ns ...
(:require ...
[orchestra.core :refer-macros [defn-spec]]
...))
(defn-spec some-fun #(repeatedly true)
[arg (s/cat :arg #(repeatedly true))]
...)
(the repeatedly true works fine :)
I thinks our problem was that it would only instrument directly required namespaces
it seems to instrument this, but changing #(repeatedly true)
to anything else seems to make the specs fail for now
well, it's working... just had wrong specs 🙂
so I have a super bizarre problem / use-case that I'm wondering if anyone has ideas for
I'm currently server-rendering my pages using reagent on Node.js, as well as building client-side code with the same codebase - all via shadow-cljs
what I'd like to do is use module-splitting to split up some of the heavier parts of my client-side bundle, and conditionally load them if a certain component is server-rendered
e.g. I have a feature-container
component that is conditionally rendered by the server, and when rendered it could put some code on the page that would dynamically load the feature
client-side module
right now I basically have the client-side entry point look for a specific ID and if so, render that part of the page - so I could make that load the module.
but I'd like to move that behavior into the component itself instead of having to modify the entry point every time I add a new feature
@lilactown in my setup I just collect which modules should be loaded and then emit that info into the HTML
I have helpers in my server code that emit stuff like (cljs 'some.app.entry 1 2 3)
which basically calls (some.app/entry 1 2 3)
and figures out which module some.app
is in so ensures that the module is loaded first
but that stuff is currently only used in an internal CMS admin app so can't share that part
nice. so if I'm understanding, (cljs 'some.app.entry 1 2 3)
gets translated to some JS that gets put on the page that will call (some.app/entry 1 2 3)
?
https://code.thheller.com/blog/web/2014/12/20/better-javascript-html-integration.html
I think I can use that exact strategy with shadow.loader/load
to do what I want 😄 yeah?
yep that works. I just track is on the server and directly emit <script>
tags for the required modules
I'm just not sure how I would determine which file to load. I guess that's what the manifest.edn
is for?
without you first download the base module, wait for parse and eval, and then trigger download of the additional modules
:thinking_face: OK so I would parse manifest.edn, and add the file according to the module ns passed in.
but it does necessitate then that I have to have some custom way to know when the module has been loaded (like what your blog has with (ns-ready)
)
yeah shadow.api
+ ns-ready
you still need to do in all your :entries
that have these exported methods basically