shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
mauricio.szabo 2020-11-06T12:52:29.351900Z

Hello there! Is there a way to get how a specific dependency is being pulled on shadow-cljs? Specifically, something like lein deps :tree or similar

thheller 2020-11-06T12:53:38.352200Z

there is a rough version in shadow-cljs info

mauricio.szabo 2020-11-06T13:00:53.352700Z

Ah, ok, thanks. Turns out Pathom was being pulled by shadow-cljs itself 🙂.

🩜 1
thheller 2020-11-06T13:03:38.352900Z

indeed

Clément Ronzon 2020-11-06T18:41:22.359300Z

Hi guys, I am developping a SPA using re-frame and I have a question about shadow-cljs + karma + coverage. In my edn file I have a :karma-test under :build which is like this:

:karma-test   {:target    :karma
              :ns-regexp "-test$"
              :output-to "target/karma-test.js"}
What I understand is that Shadow is going to compile all my cljs files, from src/ and test/ into that target/karma-test.js file. I'd like to report test coverage using karma's coverage plugin but for that, I need to have the sources and the test in separate files, right? If I add this to my karma config file, it runs into a loop:
preprocessors: {
            'target/karma-test.js': ['coverage']
        },
Was anyone successful at running coverage report? (FYI I'm quite new at using clojure/clojurescript/shadow-cljs)

Clément Ronzon 2020-11-06T18:44:00.359400Z

Here is the output of the "loop" I mentioned:

<--- Last few GCs --->

[743:0x2e177e0]    27020 ms: Scavenge 1365.5 (1423.5) -> 1364.7 (1424.0) MB, 2.0 / 0.0 ms  (average mu = 0.300, current mu = 0.273) allocation failure 
[743:0x2e177e0]    28513 ms: Mark-sweep 1365.6 (1424.0) -> 1362.4 (1423.5) MB, 1490.8 / 0.0 ms  (average mu = 0.392, current mu = 0.459) allocation failure scavenge might not succeed
[743:0x2e177e0]    28518 ms: Scavenge 1363.3 (1423.5) -> 1362.5 (1424.0) MB, 2.6 / 0.0 ms  (average mu = 0.392, current mu = 0.459) allocation failure 


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x1246665bf1d]
    1: StubFrame [pc: 0x1246661b535]
Security context: 0x0e367139e6c1 <JSObject>
    2: builder(aka builder) [0x3a525ca3dcf1] [/app/node_modules/@babel/types/lib/builders/builder.js:~16] [pc=0x12466a63ad1](this=0x287b09c026f1 <undefined>,/* anonymous */=0x3841126a8a69 <String[14]: ObjectProperty>)
    3: arguments adaptor frame: 3->1
    4: valueToNode(aka valueToNode) [0x358fe6fb6809] [/app/node_modul...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x8fb090 node::Abort() [node]
 2: 0x8fb0dc  [node]
 3: 0xb031be v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xb033f4 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
 5: 0xef7452  [node]
 6: 0xef7558 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [node]
 7: 0xf03632 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [node]
 8: 0xf03f64 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node]
 9: 0xf06bd1 v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [node]
10: 0xed0054 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [node]
11: 0x117012e v8::internal::Runtime_AllocateInNewSpace(int, v8::internal::Object**, v8::internal::Isolate*) [node]
12: 0x1246665bf1d 
Aborted (core dumped)

thheller 2020-11-06T19:46:16.359900Z

sorry, don't know anything about karma/coverage stuff/

Clément Ronzon 2020-11-16T22:45:01.047900Z

Hi @thheller, I've spent a good amount of days trying and searching for alternatives, in vain. How feasible would it be to have the :browser-test target generating 2 js files? - one with only the namespaces from the sources - one with the tests and all the rest Having this, it would be extremely easy to run test coverage.

thheller 2020-11-17T10:17:41.051500Z

sorry I don't understand what that would accomplish

Clément Ronzon 2020-11-17T16:28:39.052500Z

No worries, let me explain: The code that needs to be analysed, in terms of coverage, has to be in a separate file from the rest of the code (tests, libraries etc.) so we can specify it in Karma's configuration (`preprocessors: 'path/to/code/to/analyse/*.js': ['coverage']`) (see https://karma-runner.github.io/0.8/config/coverage.html). This way Karma's coverage "knows" what js files are to analyse v.s. what js files are testing that code. Currently, the :karma target dumps all the js code into a single file which makes it impossible to run the coverage module with any accuracy.

thheller 2020-11-17T16:31:46.052800Z

I don't understand the last argument

thheller 2020-11-17T16:32:10.053Z

how does it get more accurate with multiple files? I presume it uses source map to map the code which will point back to the original sources?

thheller 2020-11-17T16:32:22.053200Z

why does it matter that there multiple and not one file?

thheller 2020-11-17T16:32:35.053400Z

please point me to technical docs explaining why if there are any?

thheller 2020-11-17T16:33:57.053600Z

I simply do not know enough about karma to make any technical decisions but what you are asking does not make sense to me in a build sense. I told you before to use :npm-module if you want one file per namespace. that is the best I can offer?

thheller 2020-11-17T16:34:30.053800Z

you can create a reproducible example repo with something that doesn't work so I can take a look

thheller 2020-11-17T16:34:43.054Z

but so far I don't have enough information to make more suggestsions

Clément Ronzon 2020-11-17T16:35:17.054200Z

https://karma-runner.github.io/0.8/config/coverage.html

Clément Ronzon 2020-11-17T16:35:25.054400Z

In the section "Preprocessor"

Clément Ronzon 2020-11-17T16:35:40.054600Z

There is a BAD example

Clément Ronzon 2020-11-17T16:35:45.054800Z

> In this example also JASMINE and JASMINE_ADAPTER get included but they shouldn't as these file are only for the test setup used and not for your program.

Clément Ronzon 2020-11-17T16:36:03.055Z

> If you include these files there can occur side effects like the following, > - a part of the code coverage report will be output in the installation directory of Karma. > - the code coverage rate is reduced unfairly.

Clément Ronzon 2020-11-17T16:38:08.055500Z

I understand you must have bigger fish to fry and I'd love to be able to propose a PR.

Clément Ronzon 2020-11-17T16:38:49.055700Z

I cloned your repo locally but I hadn't enough time to put myself in the code in order to understand where to tweak it.

Clément Ronzon 2020-11-17T16:39:12.055900Z

Please, if you could point me into the right direction I would appreciate it!

thheller 2020-11-17T16:39:17.056100Z

the only thing I can say is that I need a reproducible repo to actually see what is happening before making any decicions

thheller 2020-11-17T16:39:49.056300Z

the JASMINE line makes so sense to me since that is not something shadow-cljs uses or includes

Clément Ronzon 2020-11-17T16:40:26.056500Z

I took it as an example, it's valid with any non-functional/production code

thheller 2020-11-17T16:40:36.056700Z

I can't point you in any direction since I still don't have the slightest clue which problem you are actually trying to solve

Clément Ronzon 2020-11-17T16:41:01.057Z

OK. Let me create a repo to illustrate the issue

Clément Ronzon 2020-11-17T16:41:13.057200Z

I'll get back to you in a few days

Clément Ronzon 2020-11-17T17:46:48.057400Z

It was faster to demonstrate than I thought: https://github.com/ClemRz/shadow-cljs-karma-coverage-issue Let me know if I can help on anything 🙂

thheller 2020-11-17T19:44:12.057800Z

ok from what I can gather you are expecting to get 100% coverage from running one simple test?

thheller 2020-11-17T19:45:01.058Z

but since the code includes all of cljs.core and so on that skews your numbers and you only want coverage for you actual ns

thheller 2020-11-17T19:47:39.058200Z

can't think of a decent way to make that happen

thheller 2020-11-17T19:53:03.058700Z

thats the code controlling the output. so you can try and modify it to match your needs.

Clément Ronzon 2020-11-17T19:55:26.058900Z

Thank you Thomas! I'll look into it.

Clément Ronzon 2020-11-17T23:50:57.059100Z

Ok, I found a way to make it work! I know it is a bit ugly... 😁 I created a remediation branch on the repo to show how I made it work (https://github.com/ClemRz/shadow-cljs-karma-coverage-issue/tree/remediation). @thheller I'd be very happy to see this change included in the next release of shadow-cljs, if possible. Please let me know how can I help with that.

thheller 2020-11-18T09:14:14.060900Z

you can rename the karma.clj to karma2.clj or move it to an entirely different namespace

thheller 2020-11-18T09:14:21.061100Z

you can then publish it as a separate library

thheller 2020-11-18T09:21:53.061300Z

as a quick test I made

----------------------|---------|----------|---------|---------|--------------------
File                  | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------------|---------|----------|---------|---------|--------------------
All files             |   71.43 |     62.5 |      50 |      72 |                   
 coverage.app.js      |     100 |      100 |     100 |     100 |                   
 coverage.app_test.js |   65.22 |       50 |   33.33 |      65 | 3,9,14-15,22,26-27
----------------------|---------|----------|---------|---------|--------------------

thheller 2020-11-18T09:22:18.061500Z

that seems more along the lines of what you want? actually split by ns? but for some reason it just reports coverage and no longer failing tests

thheller 2020-11-18T09:23:03.061700Z

anyways I don't really use karma myself so someone that does should really work on this more

Clément Ronzon 2020-11-18T16:45:31.076300Z

Good morning Thomas. TY for looking into it. For your test: have you pulled the remediation branch or did you just put the override of karma.clj? (I'm asking because it looks more like a configuration thing)

Clément Ronzon 2020-11-18T16:46:23.076700Z

https://clojurians.slack.com/archives/C6N245JGG/p1605690861061100?thread_ts=1604691976.359900&cid=C6N245JGG do you have an example of a separate library that I could use please?

thheller 2020-11-18T16:47:37.078300Z

basically the idea was to generate a files.json file so karma knows how to load the separate files in order

thheller 2020-11-18T16:47:49.078900Z

so the files are truly seperate

thheller 2020-11-18T16:48:01.079200Z

seems to work but probably requires tuning a lot more

Clément Ronzon 2020-11-18T16:50:41.080400Z

TY, I like this approach. I'll dig into it and let you know if I can tune it.

Clément Ronzon 2020-11-18T16:53:39.080600Z

Would it be a good idea to reference karma.clj's function that hasn't been changed instead of redefining them? I'm thinking that it would be good to have both targets evolving along but at the same time it would make it harder to maintain.

thheller 2020-11-18T16:55:18.080800Z

no clue. depends on how many other changes make sense I guess.

thheller 2020-11-18T16:56:46.081Z

I built the karma stuff because someone asked how to do it ... without ever having used it myself there are probably a lot of things that could be done better

Clément Ronzon 2020-11-18T17:00:56.081200Z

How did you configure the target in your shadow.edn please?

thheller 2020-11-18T17:01:46.081400Z

no change from yours

thheller 2020-11-18T17:01:59.081600Z

except :target :karma2 of course

✅ 1
Clément Ronzon 2020-11-18T17:08:42.081900Z

If you change this in your karma.conf.js you'll get a better result:

preprocessors: {
            'target/files/coverage.!(*_test).js': ['coverage']
        },

Clément Ronzon 2020-11-18T17:09:07.082100Z

Basically it prevents coverage from analyzing the test code.

Clément Ronzon 2020-11-18T17:10:57.082300Z

I noticed that the / are escaped in files.json:

"target\/files\/shadow.test.karma.js"
Is there a way to prevent that from happening ?

Clément Ronzon 2020-11-18T17:42:19.082500Z

found it: (json/write-str filenames :escape-slash false)

Clément Ronzon 2020-11-18T17:47:42.082700Z

I variabilized the "target" since it comes from the configuration: https://github.com/ClemRz/shadow-cljs-karma-coverage-issue/blob/remediation/src/main/shadow/build/targets/karma_coverage.clj

Clément Ronzon 2020-11-18T21:41:55.083Z

I am getting back to your comment: https://clojurians.slack.com/archives/C6N245JGG/p1605630730053000?thread_ts=1604691976.359900&cid=C6N245JGG

Clément Ronzon 2020-11-18T21:42:29.083300Z

Currently there is no mapping produced by the :karma2 target. How difficult would it be to include it?

thheller 2020-11-18T21:44:10.083800Z

that flushes the sources with source map

Clément Ronzon 2020-11-18T21:52:36.084Z

nice! thanks!

Clément Ronzon 2020-11-18T22:31:00.084500Z

Am I missing something? The "file" entry is omitted from the source map:

{
  "version": 3,
  "sources": [
    "coverage/app.cljs"
  ],
  "mappings": ";AAEA,AAAA,AAAMA,AAAeC;AAArB,AACM,AAAI,AAAA,AAAMA;AAAV;;AAAA",
  "names": [
    "<http://coverage.app/some-function|coverage.app/some-function>",
    "arg"
  ],
  "sourcesContent": [
    "(ns <http://coverage.app|coverage.app>)\n\n(defn some-function [arg]\n      (if (nil? arg) \"foo\" \"bar\"))"
  ]
}

thheller 2020-11-18T22:31:54.084700Z

what would that do? the content is right there?

Clément Ronzon 2020-11-18T22:43:13.086500Z

You are right, this field seems to be optional (https://sourcemaps.info/spec.html). I think there is something I missed with the config of remap-istanbul plugin. FYI this plugin allows a mapping between the js files and the cljs sources.

Clément Ronzon 2020-11-18T22:47:09.086700Z

Yeah, that's it, I have an outdated version, this has been fixed: https://github.com/SitePen/remap-istanbul/pull/170

Clément Ronzon 2020-11-18T23:40:08.087Z

After a bit of fighting with this abandon-wares I finally got it to work:

-----------|----------|----------|----------|----------|----------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
-----------|----------|----------|----------|----------|----------------|
 coverage/ |      100 |      100 |      100 |      100 |                |
  app.cljs |      100 |      100 |      100 |      100 |                |
-----------|----------|----------|----------|----------|----------------|
All files  |      100 |      100 |      100 |      100 |                |
-----------|----------|----------|----------|----------|----------------|

Clément Ronzon 2020-11-18T23:40:26.087200Z

Thanks a lot for your help @thheller!!

ro6 2020-11-06T20:06:33.362800Z

@thheller I want to improve the ability to switch between repls when working on a browser extension and contribute the improvements back if I get anywhere. Can you give me a push in the right direction? For a first step, I was hoping to set things up so I can iterate on shadow while exercising it interactively from my main project. Guessing :cli or :create-cli builds are my best bet?

thheller 2020-11-06T20:09:28.363100Z

not sure what you mean by :cli or :create-cli?

thheller 2020-11-06T20:10:03.363500Z

and what do you mean by the "ability to switch between repls"?

thheller 2020-11-06T20:13:32.365Z

technically the setup expects the editor to do the switching but none is really doing it currently. still need to do a proper writeup of how to do it I guess.

Clément Ronzon 2020-11-06T20:32:15.365400Z

The only thing that is missing so coverage can run is to have the sources separated from the tests. Right now they are regrouped in the same file kamra-test.js. I would really appreciate if you could help me figuring out how to separate them please?

thheller 2020-11-06T20:39:48.365700Z

I do not understand what you mean by separate

thheller 2020-11-06T20:42:00.365900Z

I have not used karma coverage so I don't have the slightest clue how it works or what it expects

thheller 2020-11-06T20:42:22.366100Z

if you point me to some documentation I can take a look

Clément Ronzon 2020-11-06T20:44:37.366300Z

Sure, this is the doc: https://github.com/karma-runner/karma-coverage#basic In particular:

preprocessors: {
      // source files, that you wanna generate coverage for
      // do not include tests or libraries
      // (these files will be instrumented by Istanbul)
      'src/**/*.js': ['coverage']
    },
We want the source files to be separate from the test files.

thheller 2020-11-06T20:46:03.366700Z

you can try using a :npm-module build but I have my doubts that changes much

thheller 2020-11-06T20:46:09.366900Z

but that has each ns is its own file

Clément Ronzon 2020-11-06T20:47:41.367100Z

Ok thx, I will try!

ro6 2020-11-06T20:56:11.368700Z

Those are builds in the shadow-cljs repo, I assume they output the npm installable command line tool? Guessing there's also a way to load up and interact with the library code directly?

ro6 2020-11-06T20:59:03.370800Z

I've written some code over shadow/repl-runtime-selectto help me switch between repl environments, but the selection is brittle (it depends on the order they start in to know which one I'm picking) and as the runtimes come and go (eg page reload) it doesn't seem like the connection gets maintained consistently, though I could be wrong.

thheller 2020-11-06T21:00:58.371600Z

:cli is the code for the shadow-cljs command yes. I do not understand what you mean by "way to load up and interact with the library code directly?"

thheller 2020-11-06T21:01:05.371800Z

which library code?

thheller 2020-11-06T21:01:45.372600Z

the repl-runtime-select is never going to be pretty either way since hacking this together over nrepl is always going to be limited by nrepl

thheller 2020-11-06T21:02:33.373400Z

just to clarify: what you call "repl environments" I call "runtimes". will make it easier in communication if you use that word please 🙂

thheller 2020-11-06T21:03:14.374100Z

and yes the editor is supposed to pick the runtime it wants to eval in

thheller 2020-11-06T21:03:26.374400Z

or I guess repl client, not limited to "editor"

thheller 2020-11-06T21:03:52.374800Z

if you open the shadow-cljs UI it will list all connected runtimes under http://localhost:9630/runtimes

thheller 2020-11-06T21:04:31.375500Z

the "vision" is that any client also lists those and you just click whichever one you want to talk do

thheller 2020-11-06T21:05:19.376300Z

the repl-runtime-select thing is pretty much dead and gone. it doesn't do anything at all anymore these days.

thheller 2020-11-06T21:05:30.376600Z

as you say it was very brittle anyways

thheller 2020-11-06T21:26:29.378100Z

do you have a plan for how to make it more reliable? I mean I'd do it myself but I can't come up with a cleaner way to do things that don't require changing how the editor handles/presents the REPL interface