ah ignore me I found a link in this chat somewhere
https://shadow-cljs.github.io/docs/UsersGuide.html#failed-to-load
When using the {:js-options {:js-provider :require}}
the luminus landing page tells me that the javascript has not compiled and I get these errors in the developer console:
app.js:1672 An error occurred when loading shadow.js.shim.module$react.js
env.evalLoad @ app.js:1672
app.js:1673 ReferenceError: require is not defined
at eval (:3000/js/cljs-runtime/shadow.js.shim.module$react.js:3)
at eval (<anonymous>)
at Object.goog.globalEval (app.js:577)
at Object.env.evalLoad (app.js:1670)
at app.js:1773
env.evalLoad @ app.js:1673
app.js:1672 An error occurred when loading shadow.js.shim.module$react_dom.js
env.evalLoad @ app.js:1672
app.js:1673 ReferenceError: require is not defined
at eval (:3000/js/cljs-runtime/shadow.js.shim.module$react_dom.js:3)
at eval (<anonymous>)
at Object.goog.globalEval (app.js:577)
at Object.env.evalLoad (app.js:1670)
at app.js:1811
env.evalLoad @ app.js:1673
util.cljs:187 Installing CLJS DevTools 1.0.3 and enabling features :formatters :hints :async
app.js:1672 An error occurred when loading everclear.app.js
env.evalLoad @ app.js:1672
app.js:1673 TypeError: Cannot read property 'prototype' of undefined
at Object.reagent$impl$component$create_class [as create_class] (component.cljs:323)
at Object.reagent$impl$component$fn_to_class [as fn_to_class] (component.cljs:373)
at Object.reagent$impl$component$as_class [as as_class] (component.cljs:379)
at reagent$impl$template$reag_element (template.cljs:159)
at Object.reagent$impl$template$vec_to_elem [as vec_to_elem] (template.cljs:284)
at Object.reagent$impl$template$as_element [as as_element] (template.cljs:288)
at Object.eval [as reagent$impl$protocols$Compiler$as_element$arity$2] (template.cljs:305)
at Object.reagent$impl$protocols$as_element [as as_element] (protocols.cljs:5)
at f (dom.cljs:47)
at Object.reagent$dom$render_comp [as render_comp] (dom.cljs:19)
env.evalLoad @ app.js:1673
This happens even though lein shadow watch app
builds and compiles just fine. Any hints for how to debug it?@endrebak85 Why do you use :js-provider :require? This is option isn't intended for code that should run in the browser.
Ah, I want to use some npm libraries that do not compile with the regular settings.
It seems like :js-provider :require isn't the right solution for that. What error do you get with the regular settings?
[:app] Compiling ...
[:app] Build failure:
Closure compilation failed with 2 errors
--- node_modules/d3-array/dist/d3-array.js:280
This code cannot be converted from ES6. extending native class: Map
--- node_modules/d3-array/dist/d3-array.js:300
This code cannot be converted from ES6. extending native class: Set
With :require
it compiles (but does not work in the browser)
I am a complete JS-n00b, but I tried to follow the guide https://shadow-cljs.github.io/docs/UsersGuide.html#_using_npm_packages.
Well, the JS ecosystem is a mess 🙂 JS is constantly extended with new language features, and the Google Closure compiler doesn't understand all of them. The library d3-array apparently uses features that the Google Closure compiler doesn't understand. What I would try is to load d3-array separately in the browser and use :js-options {:resolve {"d3-array" {:target :global }}} https://shadow-cljs.github.io/docs/UsersGuide.html#js-resolve-global. You'll probably have to process d3-array for the browser as well. Usually people use Babel for that.
You might alternatively get away with an older version of d3-array
Notably d3-array also appears here as an example for a JS module that tends to need special treatment for the browser: https://github.com/babel/babel-loader#some-files-in-my-node_modules-are-not-transpiled-for-ie-11
Hmmm, d3-array is a dependency of some other library, so trying to choose a specific library version manually sounds like it might easily lead to problems. Thanks for the pointers. I will try to understand them now :)
Maybe :js-provider :shadow works. It could be the default already, I'm not sure, but that's something you could try easily.
https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider
@endrebak85 set :compiler-options {:output-feature-set :es6}
not :js-provider
if you set :js-provider :require
shadow-cljs will NOT process any JS dependencies and instead expect a separate tool to do that. this is not what you want
the default :output-feature-set
is :es5
but as the error is telling you the d3 code cannot be converted "down". so by setting a "higher" feature set that problem goes away
:js-provider :shadow
is the default for :browser
builds, do not change it unless you know what you are doing.
do not use :resolve
either, that is not relevant here.
Interesting. So Google Closure is apparently quite good in supporting newer JS features. https://shadow-cljs.github.io/docs/UsersGuide.html#_output_language_options
yes, not super bleeding edge but quite good. usually when there is a standard there is support.
I might bump the default to :es6
. really doesn't make sense to have :es5
still.
If you want support for IE11 you need to set that back to :es5
then, right?
yes
I just bumped the default. really should have done that a year ago 😛
@thheller https://cljs.github.io/api/compiler-options/language-out doesn't mention :ecmascript6
. Is that correct?
yeah .. doesn't matter. closure keeps changing the names of those. in shadow thats just an alias for ecmascript-2015, same option
Thanks for all the help 🙂 It seems to be working fine now.
This is a question where I seem to have found a workaround, so please ignore if busy.
shadow-cljs release node
wasn't working, even though
shadow-cljs compile node
was.
Following advice in the troubleshooting guide, I compared versions of the major dependent libraries across working and non-working projects and noticed that the com.google.javascript/closure-compiler
version was different, someone had pinned it in the deps.edn
with a note about "enable for node", I also noted that there is a specified shadow-cljs version in the deps.edn
it eventually worked only when I both installed the specified version of shadow-cljs (through npm, how I'd originally installed), and unpinned the versions of
com.google.javascript/closure-compiler
and org.clojure/google-closure-library
which had both been pinned under a note.
The things I remain confused about:
do aliases like:
:aliases {:cljs {:extra-deps {thheller/shadow-cljs {:mvn/version "2.10.21"}
enforce shadow-cljs version? From my troubleshooting, I guess not if you install via npm, therefore I should be installing via lein?
Does anyone have an idea why these libraries have to be pinned, and shadow-cljs has to be an older version? the errors I got with the newer version were like this:
No matching field found: getSourceName for class com.google.javascript.jscomp.JSError
and
The result of a goog.define call must be assigned as an isolated statement.
one for pinned and one for unpinned closure compiler versions
I have set up shadow-cljs to compile my cljs
to a specific folder from where I'm serving them with a different HTTP server. Everything seems to work ok... code compiles on save and hot reloads on the browser 😃. However, I do not get a browser repl after the code is compiled when I run shadow-cljs watch app
I have commented out ;; :dev-http {3000 "public"}
in my shadow-cljs.edn file because my server is running on the same port
I wonder what I might be missing?
error messages also sometimes, on the browser console don't seem to pinpoint exactly where the error is.
if you use deps.edn
and have a true-ish :deps
key in shadow-cljs.edn
then ONLY deps.edn
controls the version for shadow-cljs you get
the one in package.json
then only controls the version of the shadow-cljs
command line tools
shadow-cljs cljs-repl app
will give you the REPL
or use your editor to connect
thanks, that worked
using shadow.loader/load
but the XHR request it makes has this undefined
segment in the url <http://localhost:3000/undefined/><correct shadow-cljs.edn asset path>
and I’m not sure why
have to look into this <http://shadow.loader.mm|shadow.loader.mm> = goog.module.ModuleManager.getInstance();
might be calling it too early? before it is initialized?
don't know why you posted the mm line? if that didn't exist you'd never get an URL from anything, it would error out differently
if you called shadow.loader/init
without an argument that might be the undefined
?
needs to get one argument for the prefix it is supposed to use, just an empty string for no prefix
oh I was looking into what this was doing <http://shadow.loader.mm|shadow.loader.mm>.execOnLoad(id, cb)
I think it’s a user error that I need to sort out because I’m only getting the issue when I load the async route (in my app) directly
but if I go to another route first that isn’t a separate module, and then go to async route it loads correctly
what do you want execOnLoad for? doubt anyone ever used that
I don't even know what its supposed to do 😛
oh… lol uhh I thought I was following the code for shadow.loader/load
shadow.loader.load = function(id, cb) {
shadow.loader.ensureInitWasCalled();
id = shadow.loader.string_id(id);
if (cb) {
shadow.loader.mm.execOnLoad(id, cb);
}
return shadow.loader.mm.load(id);
};
https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/loader.js#L115
https://shadow-cljs.github.io/docs/UsersGuide.html#_loading_code_dynamically
but why not just use load?
if you intent to call something when the code is loaded use :init-fn
in the module config
hmm, interesting question. I’m trying to work the async module loading into my app’s router which is represented as data in state, so like, when the ‘on-navigate’ event fires I load the new page’s module and call it’s render function. I’m sure it could be improved like how you suggested, I’m trying to get a poc working
maybe you want something like shadow.lazy
or the example from here https://code.thheller.com/blog/shadow-cljs/2019/03/03/code-splitting-clojurescript.html
ahh that is probably exactly it
the lazy-component util is using shadow.lazy https://github.com/thheller/code-splitting-clojurescript/blob/master/src/main/demo/util.cljs
["blog"
{:name :<http://deli.pages.blog|deli.pages.blog>,
:weight 5,
:view #'deli-pages-blog/render,
:label "blog",
:controllers
[{:identity
(clojure.core/juxt :parameters :path-params :query-params),
:start #(rf/dispatch [:fetch-blog])}]}]
the only reason it’s all bundled together is for importing the namespace and passing it to that :view
keyword, so if I can just lazy reference that, bingothanks @thheller!!
Any idea what I'm doing here. My shadow-cljs.edn
:source-paths ["src/main" "src/test"]
:builds {
:test {:target :karma
:output-to "target/ci.js"}}
$ npx shadow-cljs compile test
shadow-cljs - config: /home/stuart/Source/cljs/cljs-asm/shadow-cljs.edn
shadow-cljs - connected to server
[:test] Compiling ...
[:test] Build completed. (62 files, 1 compiled, 0 warnings, 0.45s)
This puts a file ci.js
in a folder named target
I have a karma.conf.js
module.exports = function (config) {
config.set({
browsers: ['ChromeHeadless'],
// The directory where the output file lives
basePath: 'target',
// The file itself
files: ['ci.js'],
frameworks: ['cljs-test'],
plugins: ['karma-cljs-test', 'karma-chrome-launcher'],
colors: true,
logLevel: config.LOG_INFO,
client: {
args: ["shadow.test.karma.init"],
singleRun: true
}
})
};
When I run karma start --single-run
I see this:
13 05 2021 20:11:24.219:INFO [karma-server]: Karma v6.3.2 server started at <http://localhost:9876/>
13 05 2021 20:11:24.222:INFO [launcher]: Launching browsers ChromeHeadless with concurrency unlimited
13 05 2021 20:11:24.230:INFO [launcher]: Starting browser ChromeHeadless
13 05 2021 20:11:24.539:INFO [Chrome Headless 90.0.4430.212 (Linux x86_64)]: Connected on socket 63Mi3R7buKBGnu2WAAAB with id 43705700
Chrome Headless 90.0.4430.212 (Linux x86_64): Executed 0 of 0 SUCCESS (0.003 secs / 0 secs)
TOTAL: 0 SUCCESS
My tests are namespaced like this
(ns exfn.parser-test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
anyone any ideas why its not finding my tests?I'm running karma from the root folder of my app, in teh same folder as karma-conf.js
hard to say. you omitted several important details. like which version is this? where is the actual test file?
sorry, the test files are in "src/test" folder off the root of my project.
Karma version is 6.3.2
shadow-cljs version? do you use project.clj or deps.edn?
yes
I'm using shadow-cljs via commands like
npx shadow-cljs watch app
npx shadow-cljs release app
etchow do I make it show me the version ?
shadow-cljs - config: /home/stuart/Source/cljs/cljs-asm/shadow-cljs.edn
=== Version
jar: 2.11.22
cli: 2.11.22
deps: 1.3.2
config-version: 2.11.22
do you use project.clj or deps.edn? is there a :lein
or :deps
key in your shadow-cljs.edn
?
I only have a shadow-cljs.edn
My whole shadow-cljs.edn
;; shadow-cljs configuration
{:source-paths
["src/main"
"src/test"]
:dependencies
[[binaryage/devtools "0.9.10"]
[reagent "1.0.0"]
[re-frame "1.2.0"]
[day8.re-frame/re-frame-10x "1.0.1"]
[org.clojars.ertucetin/re-frame-flow "0.1.1"]
[bidi "2.1.6"]
[com.rpl/specter "1.1.3"]]
:nrepl {:port 3333}
:dev-http {8080 "public"}
:builds {:app {:target :browser
:output-dir "public/js"
:modules {:main {:init-fn <http://exfn.app/init|exfn.app/init>}}
:dev {:compiler-options {:closure-defines {re-frame.trace/trace-enabled? true
day8.re-frame.tracing/trace-enabled? true}}}
:devtools {:http-root "public"
:http-port 3000
:preloads [day8.re-frame-10x.preload
re-frame-flow.preload]}
:compiler-options {:closure-defines {re-frame.trace.trace-enabled? true}
:silence-optimizations-warning true
;; in production so you can do an :advanced compile.
:optimizations :simple}
:release {:build-options {:ns-aliases {day8.re-frame.tracing day8.re-frame.tracing-stubs}}}}
:release {:target :browser
:output-dir "release/js"
:modules {:main {:init-fn <http://exfn.app/init|exfn.app/init>}}
:compiler-options {:silence-optimizations-warning true
:optimizations :advanced}}
:test {:target :karma
:ns-regexp "-test$"
:output-to "target/ci.js"}}}
looks fine. don't really need the :release
build but thats not relevant to the test
I assume you have actual deftest
in your test file? with actual is
assertions?
yeah, so i have a bunch of tests over 2 files. The tests are
src/test/interpreter-tests.cljs
src/test/parser-tests.cljs
A test looks like
(deftest is-register-tests?
(is (true? (is-register? ":x")))
(is (false? (is-register? "5")))
(is (false? (is-register? "foo")))
(is (false? (is-register? "b_010101"))))
don't know where you get :silence-optimizations-warning
from but that config option does not exist
those are not valid filesnames
(ns exfn.parser-test ...
needs to be in src/test/exfn/parser_test.cljs
ah okay! I didn't know that, let me move them and try
you configured :ns-regexp "-test$"
which does not match parser-tests
I thought that was parsing on the namespace, its parsing on the file?
it is looking for the namespace, but that is derived from the filename
ok, cool. I'll move those files and try again.Thanks for your time and help!
I am adding a server to my shadow project to handle endpoints and Crux. I would normally add Ring and Compojure to do that. Do I add these deps to shadow-cljs.edn or somewhere else? Are some of them already included… if so where are they pulled in? Thanks!
I created my app with create-cljs-app
so that’s the structure.
I'd recommend using whatever you prefer for writing CLJ apps
I use lein
for all my CLJ needs so I'll have a project.clj
for that with the proper dependencies. so I'll have a shadow-cljs.edn
for everything CLJS related and a project.clj
for CLJ stuff
@thheller thank you! It works now and runs my tests. Fantastic 🙂
https://code.thheller.com/blog/shadow-cljs/2021/05/13/paths-paths-paths.html
just pushed me to finish posting this 😉 might help a little in understanding why those names/paths matter
Nice, I have been confused about all the paths in clojure(script)
in terms of adding a project.clj to a shadow project (next to a shadow-cljs.edn), I have (from lein new app server
(defproject server "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "<http://example.com/FIXME>"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "<https://www.eclipse.org/legal/epl-2.0/>"}
:dependencies [[org.clojure/clojure "1.10.1"]]
:main ^:skip-aot server.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
how much of this is relevant pr meeds to be changed? (thanks for the hand holding).I really can't guide you through building a CLJ server sorry
maybe follow some tutorial first and then integrate the files into actual project later
I totally understand! And thanks for all the help… you’ve got me going in the right direction.