Fork me on GitHub
#shadow-cljs
<
2021-05-13
>
zimablue04:05:15

ah ignore me I found a link in this chat somewhere

Endre Bakken Stovner08:05:34

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?

mbertheau08:05:26

@UT770EY2K Why do you use :js-provider :require? This is option isn't intended for code that should run in the browser.

Endre Bakken Stovner08:05:08

Ah, I want to use some npm libraries that do not compile with the regular settings.

mbertheau08:05:25

It seems like :js-provider :require isn't the right solution for that. What error do you get with the regular settings?

Endre Bakken Stovner09:05:00

[: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

Endre Bakken Stovner09:05:33

With :require it compiles (but does not work in the browser)

mbertheau09:05:59

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.

mbertheau09:05:40

You might alternatively get away with an older version of d3-array

mbertheau09:05:05

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

Endre Bakken Stovner09:05:39

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 :)

mbertheau09:05:58

Maybe :js-provider :shadow works. It could be the default already, I'm not sure, but that's something you could try easily.

thheller09:05:53

@UT770EY2K set :compiler-options {:output-feature-set :es6} not :js-provider

thheller09:05:21

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

thheller09:05:37

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

thheller09:05:23

:js-provider :shadow is the default for :browser builds, do not change it unless you know what you are doing.

thheller09:05:03

do not use :resolve either, that is not relevant here.

mbertheau10:05:48

Interesting. So Google Closure is apparently quite good in supporting newer JS features. https://shadow-cljs.github.io/docs/UsersGuide.html#_output_language_options

thheller10:05:49

yes, not super bleeding edge but quite good. usually when there is a standard there is support.

thheller10:05:38

I might bump the default to :es6. really doesn't make sense to have :es5 still.

mbertheau10:05:16

If you want support for IE11 you need to set that back to :es5 then, right?

thheller10:05:35

I just bumped the default. really should have done that a year ago 😛

thheller10:05:46

yeah .. doesn't matter. closure keeps changing the names of those. in shadow thats just an alias for ecmascript-2015, same option

👍 3
Endre Bakken Stovner11:05:55

Thanks for all the help 🙂 It seems to be working fine now.

zimablue13:05:11

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

thheller14:05:26

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

thheller14:05:40

the one in package.json then only controls the version of the shadow-cljs command line tools

Franklin14:05:14

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

Franklin14:05:59

I have commented out ;; :dev-http {3000 "public"} in my shadow-cljs.edn file because my server is running on the same port

Franklin14:05:22

I wonder what I might be missing?

Franklin14:05:13

error messages also sometimes, on the browser console don't seem to pinpoint exactly where the error is.

thheller14:05:34

shadow-cljs cljs-repl app will give you the REPL

thheller14:05:00

or use your editor to connect

Franklin15:05:36

thanks, that worked

haywood16:05:39

using shadow.loader/load but the XHR request it makes has this undefined segment in the url <correct shadow-cljs.edn asset path> and I’m not sure why

haywood16:05:14

have to look into this = goog.module.ModuleManager.getInstance();

thheller16:05:25

might be calling it too early? before it is initialized?

thheller16:05:28

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

thheller16:05:54

if you called shadow.loader/init without an argument that might be the undefined?

thheller16:05:40

needs to get one argument for the prefix it is supposed to use, just an empty string for no prefix

haywood16:05:48

oh I was looking into what this was doing .execOnLoad(id, cb)

haywood16:05:34

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

haywood16:05:49

but if I go to another route first that isn’t a separate module, and then go to async route it loads correctly

thheller16:05:36

what do you want execOnLoad for? doubt anyone ever used that

thheller16:05:56

I don't even know what its supposed to do 😛

haywood16:05:25

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);
};

thheller16:05:39

but why not just use load?

thheller16:05:06

if you intent to call something when the code is loaded use :init-fn in the module config

haywood16:05:06

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

haywood16:05:11

ahh that is probably exactly it

haywood16:05:25

["blog"
    {:name :,
     :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, bingo

Stuart19:05:04

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 
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?

Stuart19:05:04

I'm running karma from the root folder of my app, in teh same folder as karma-conf.js

thheller19:05:38

hard to say. you omitted several important details. like which version is this? where is the actual test file?

Stuart19:05:15

sorry, the test files are in "src/test" folder off the root of my project.

Stuart19:05:05

Karma version is 6.3.2

thheller19:05:18

shadow-cljs version? do you use project.clj or deps.edn?

Stuart19:05:51

I'm using shadow-cljs via commands like

npx shadow-cljs watch app
npx shadow-cljs release app
etc

Stuart19:05:55

how do I make it show me the version ?

Stuart19:05:54

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

thheller19:05:13

do you use project.clj or deps.edn? is there a :lein or :deps key in your shadow-cljs.edn?

Stuart19:05:37

I only have a shadow-cljs.edn

Stuart19:05:56

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 }}
                  :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 }}
                      :compiler-options {:silence-optimizations-warning true
                                         :optimizations :advanced}}
            
            :test {:target :karma
                   :ns-regexp "-test$"
                   :output-to  "target/ci.js"}}}

thheller19:05:46

looks fine. don't really need the :release build but thats not relevant to the test

thheller19:05:56

I assume you have actual deftest in your test file? with actual is assertions?

Stuart19:05:04

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"))))

thheller19:05:32

don't know where you get :silence-optimizations-warning from but that config option does not exist

thheller19:05:39

those are not valid filesnames

thheller19:05:09

(ns exfn.parser-test ... needs to be in src/test/exfn/parser_test.cljs

Stuart19:05:31

ah okay! I didn't know that, let me move them and try

thheller19:05:35

you configured :ns-regexp "-test$" which does not match parser-tests

Stuart19:05:55

I thought that was parsing on the namespace, its parsing on the file?

thheller19:05:24

it is looking for the namespace, but that is derived from the filename

Stuart19:05:24

ok, cool. I'll move those files and try again.Thanks for your time and help!

macrobartfast20:05:46

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!

macrobartfast20:05:52

I created my app with create-cljs-app so that’s the structure.

thheller20:05:01

I'd recommend using whatever you prefer for writing CLJ apps

thheller20:05:22

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

👍 3
Stuart20:05:06

@thheller thank you! It works now and runs my tests. Fantastic 🙂

thheller20:05:45

just pushed me to finish posting this 😉 might help a little in understanding why those names/paths matter

Stuart20:05:04

Nice, I have been confused about all the paths in clojure(script)

macrobartfast21:05:28

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 ""
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url ""}
  :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).

thheller21:05:32

I really can't guide you through building a CLJ server sorry

thheller21:05:29

maybe follow some tutorial first and then integrate the files into actual project later

macrobartfast21:05:55

I totally understand! And thanks for all the help… you’ve got me going in the right direction.