cljs-dev

ClojureScript compiler & std lib dev, https://clojurescript.org/community/dev
plexus 2020-05-29T07:02:48.310300Z

Something I've been meaning to bring up. shadow-cljs has this functionality for test builds where it scans the filesystem for test namespaces, and implicitly makes them dependencies of a main namespace (a test runner ns). This makes sure not just that they are included in the build, but that they are compiled before the runner, so that when the runner compiles it can inspect the compiler env to find all tests. This makes it possible for a third party runner like Chui to exist, where people can just point at a runner ns that's provided by the library, instead of having to write their own where they manually require all their tests. I brought this up with @bhauman and he's considering if it makes sense to have something similar in Figwheel, but having it directly in the compiler so it's available regardless of the tool you're using would be even better. Thoughts?

πŸ‘ 2
dnolen 2020-05-29T12:30:53.313Z

this sounds like a divergence from Clojure? You have to require the test nses for run-tests to work

dnolen 2020-05-29T12:34:46.315700Z

also I don't really understand the "manually require" - the test runners that don't require analysis stuff just support a simple naming pattern matching which works just fine.

dnolen 2020-05-29T12:35:14.316200Z

so I don't see what the gain is for end users - it's already easy right now - but maybe I missing a subtle point

thheller 2020-05-29T12:39:35.317Z

the problem doesn't exist in clojure since the test-runner can just dynamically require all the tests it wants to run

thheller 2020-05-29T12:39:52.317400Z

in CLJS the burden is on the user to create one namespace that requires all the other test namespaces

thheller 2020-05-29T12:41:28.318600Z

so in shadow-cljs instead there is a generic test runner ns everyone can re-use and the requires are just provided by the build

dnolen 2020-05-29T12:54:39.320200Z

yes I understand the dynamic require thing - but there is no such thing as a test-runner in Clojure

dnolen 2020-05-29T12:54:44.320400Z

this is a tooling thing

dnolen 2020-05-29T12:55:36.321400Z

a test-runner implies a lot more than just dynamically requiring - which implies you have to know what look for anyway (filtering)

thheller 2020-05-29T12:55:56.322Z

that is not the topic here

dnolen 2020-05-29T12:56:03.322300Z

but regex based matching a la cljs test runner accomplishing the same thing

dnolen 2020-05-29T12:56:05.322500Z

it is

dnolen 2020-05-29T12:56:15.322900Z

the conversation is about including something

dnolen 2020-05-29T12:56:28.323500Z

and it has to be weighed against existing easy stuff

dnolen 2020-05-29T12:57:40.324800Z

also the above is really problematic in that doesn't elaborate

dnolen 2020-05-29T12:57:47.325100Z

so in shadow-cljs how does a user filter?

dnolen 2020-05-29T12:57:59.325700Z

or control what sets of tests - or run a specific test

thheller 2020-05-29T12:57:59.325800Z

:ns-regexp "-test$", and a couple more options. can also specify by name manually

dnolen 2020-05-29T12:58:32.326600Z

right again this all smells of affordances

dnolen 2020-05-29T12:58:40.327Z

not something that Clojure does or cares about

dnolen 2020-05-29T12:58:47.327300Z

thus probably not something we should care about

dnolen 2020-05-29T12:59:00.327600Z

other than making it possible for someone else to solve the problem

thheller 2020-05-29T13:00:05.328800Z

I think thats what the initial question is about. I think currently this isn't very easy to do.

thheller 2020-05-29T13:00:19.329300Z

assume that the test tool already filtered and found all the namespaces it wants to test

thheller 2020-05-29T13:00:37.329800Z

how does it tell the compiler to compile those before compiling the additional "test-runner" itself?

thheller 2020-05-29T13:01:03.330300Z

ie. if the test-runner doesn't have the requires itself parallel-build may just decide to compile it whenever without actually waiting

dnolen 2020-05-29T13:02:11.331Z

I'm even more confused now by not easy

dnolen 2020-05-29T13:02:25.331400Z

the compiler can compile forms, you can create test runner in memory and pass it into build no?

thheller 2020-05-29T13:03:10.332600Z

sorry I don't really know what the state of the official APIs for this is. just wanted to make clear why this is useful to have from the users perspective.

dnolen 2020-05-29T13:03:54.334Z

gimme one second, browser REPL has an example

dnolen 2020-05-29T13:06:18.335Z

yes the compiler can take source forms directly

thheller 2020-05-29T13:07:47.336500Z

that should be enough then

plexus 2020-05-29T13:08:02.336600Z

does this allow me to solve this for my users in a way that is tool agnostic?

thheller 2020-05-29T13:11:43.338700Z

probably no because neither shadow-cljs nor figwheel are "in the loop" for that build path

plexus 2020-05-29T13:12:33.339Z

I'm trying to imagine how this would work in practice, say someone is using cljs.main --compile, what do I tell them?

dnolen 2020-05-29T13:13:52.339700Z

cljs.main doesn't need to be involved, we're talking about writing a test runner easily.

dnolen 2020-05-29T13:14:52.340700Z

build can take a series of ClojureScript forms in memory

dnolen 2020-05-29T13:15:02.341Z

you don't even need to code gen (to disk)

dnolen 2020-05-29T13:15:13.341400Z

you can fabricate the test runner

dnolen 2020-05-29T13:15:24.341700Z

you can set :main

dnolen 2020-05-29T13:15:29.342Z

there's nothing else

plexus 2020-05-29T13:16:27.343100Z

yes, I can invoke the compiler myself. I get that. I don't want that. People have their own setup with their own tools, they figured out how they're dealing with dependencies and externs and whatever. I just want to add something to their build.

plexus 2020-05-29T13:17:04.344300Z

kaocha-cljs currently uses repl-env which means we implicitly invoke the compiler, this leads to no end of trouble because we don't replicate people's actual setup

dnolen 2020-05-29T13:17:10.344500Z

this is going into the weeds about how you would like it work πŸ™‚

dnolen 2020-05-29T13:17:24.344900Z

I'm saying it works right now, maybe not how you want it work but it is already trivial to write a test-runner

dnolen 2020-05-29T13:18:52.346Z

adding test running features to cljs.main is not going to happen

dnolen 2020-05-29T13:18:54.346200Z

... but

dnolen 2020-05-29T13:19:07.346500Z

I just don't understand what your concerns are

dnolen 2020-05-29T13:19:29.347200Z

clj -m my.cool.test-runner-tool -co build.edn --run-tests

dnolen 2020-05-29T13:19:58.348Z

how does this not mean you can use your own tools, deps, etc.?

plexus 2020-05-29T13:20:21.348400Z

so my.cool.test-runner-tool knows about shadow vs figwheel vs cljs.main?

dnolen 2020-05-29T13:20:29.348600Z

huh?

dnolen 2020-05-29T13:20:38.348900Z

why does it need to know about those things

dnolen 2020-05-29T13:20:48.349200Z

if something has to know about those things - something is very, very wrong

dnolen 2020-05-29T13:21:07.349900Z

all those tools already taking different options that are different from cljs.main

dnolen 2020-05-29T13:21:15.350200Z

so there's nothing to reconcile

plexus 2020-05-29T13:21:53.351Z

kaocha-cljs currently doesn't work for a lot of shadow users because shadow's compilation is subtly different. that's why we want to get out of the job of invoking the compiler

dnolen 2020-05-29T13:22:22.351500Z

I don't see how ClojureScript can solve this problem - the build tools are incompatible

dnolen 2020-05-29T13:22:43.351800Z

I don't see how this is different from Lein, Boot, deps.edn

plexus 2020-05-29T13:23:21.352500Z

the thing is I can write a library and people can include it using lein, boot, deps.edn. I'd like to write a test runner that people can include with shadow, figwheel, cljs.main

plexus 2020-05-29T13:23:36.353Z

but there is one aspect that I can't handle as a library

plexus 2020-05-29T13:23:50.353300Z

and that brings us back to the top

dnolen 2020-05-29T13:23:51.353400Z

let's rewind a bit

dnolen 2020-05-29T13:24:00.353800Z

because I do not understand now what you are saying

plexus 2020-05-29T13:25:08.354700Z

ok... let me try to rephrase or explain better the use case

dnolen 2020-05-29T13:25:35.355Z

well first let's elaborate what I see the issue w/ what you're saying is

plexus 2020-05-29T13:25:41.355500Z

ok, sure

dnolen 2020-05-29T13:25:41.355600Z

and maybe you can tell me how you could solve it

dnolen 2020-05-29T13:26:44.356500Z

to me you can't make a generic thing that works with all these build tools because they might inject something tooling specific

dnolen 2020-05-29T13:26:56.356800Z

ClojureScript can't possibly know about these tooling specific things

dnolen 2020-05-29T13:28:22.358100Z

you could write a library to create test-runner namespaces sure (but this is like ~100 lines of code for the basics)

dnolen 2020-05-29T13:28:34.358600Z

but every tool actually needs to integrate that

dnolen 2020-05-29T13:28:44.358900Z

and maybe they want to customize it

dnolen 2020-05-29T13:29:05.359200Z

so a library doesn't appear to me to offer anything

dnolen 2020-05-29T13:30:05.360400Z

the other option - which is perfectly fine and it's what I currently do is not care about these tooling in my testing scenario since these inevitably ends up as CI things

dnolen 2020-05-29T13:30:17.360700Z

so who cares about shadow, figwheel, etc.

dnolen 2020-05-29T13:30:31.361100Z

you just going compile w/ your test-runner and run Node.js or Puppeteer

plexus 2020-05-29T13:31:28.362100Z

right, so that's all fine, I think we're getting off track here. I don't care about these tools apart from the fact that they can compile ClojureScript. They may have their own testing features, that's not what I'm concerned with.

plexus 2020-05-29T13:33:11.364100Z

based on this chui offers an API for dynamically invoking tests. That API is used in browser testing UI, as well as in a component that gets tests to execute and reports on the results via a websocket

plexus 2020-05-29T13:33:39.364700Z

this is all just standard ClojureScript, you just add it to your build and start it with a browser or node or whatever, we don't care.

dnolen 2020-05-29T13:34:04.365500Z

this seems REPL-centric?

plexus 2020-05-29T13:34:08.365800Z

but we can only know about the tests that have been compiled by the time that macro runs

dnolen 2020-05-29T13:34:12.365900Z

since you're reflecting?

plexus 2020-05-29T13:34:56.366100Z

is it?

plexus 2020-05-29T13:35:49.367200Z

currently there are two ways this can work, either you do

(ns foo (:require <all-the-tests>))
(capture-test-data!)
or you let shadow add those requires for you

plexus 2020-05-29T13:39:08.368600Z

maybe there are better ways to solve this.... I don't know. As Thomas pointed out we lack the dynamic require so we can't scan the filesystem the way we do in Clojure, making it harder to provide a similar user experience

dnolen 2020-05-29T13:40:13.369500Z

Some thoughts

dnolen 2020-05-29T13:44:27.371400Z

it maybe we're missing something small - you need some dep graph for capture-test-data! to find/filter on

dnolen 2020-05-29T13:45:34.372500Z

the REPL has a feature :analyze-path which just analyzes everything in a directory

dnolen 2020-05-29T13:45:54.373100Z

this could be generalized to feed something like that macro

bhauman 2020-05-29T13:46:16.373900Z

this also happens when you use a directory as a build input

dnolen 2020-05-29T13:46:19.374100Z

finally you need require outside of ns but we already added that

dnolen 2020-05-29T13:46:28.374300Z

@bhauman right good point

dnolen 2020-05-29T13:46:54.375200Z

@plexus so that's probably enough a directory for build, and emitting require

plexus 2020-05-29T13:47:20.376Z

I did think of that but assumed I wouldn't be able to emit a require from a macro. Does that work?

dnolen 2020-05-29T13:47:49.376600Z

we could probably make it work in (do ...) if we didn't already do that

bhauman 2020-05-29T13:47:50.376700Z

the scan part is still missing?

dnolen 2020-05-29T13:50:14.378600Z

like scanning for tests? analyzer apis should work here - not sure about doing test specific stuff unless Clojure has something similar

dnolen 2020-05-29T13:51:32.379100Z

cljs.analyzer.api

plexus 2020-05-29T13:51:36.379200Z

alright, this is promising. I can experiment with that.

dnolen 2020-05-29T13:52:20.379700Z

@plexus if do doesn't work then a patch is welcome, I don't think this will be very hard

plexus 2020-05-29T13:52:39.379900Z

πŸ‘

dnolen 2020-05-29T13:53:16.380200Z

@plexus but also I don't think you need it?

dnolen 2020-05-29T13:53:33.380700Z

(require ns-spec ...)

plexus 2020-05-29T13:53:43.381Z

right

dnolen 2020-05-29T13:53:44.381100Z

you can have N

bhauman 2020-05-29T16:13:20.382500Z

my gosh getting simple re-bundle on npm_deps.js file change is much harder than I imagined, but almost done

dominicm 2020-05-29T16:14:05.382900Z

What's the complexity? Curious more than anything :)

bhauman 2020-05-29T16:15:06.384Z

its mostly with extra-mains and stuff

bhauman 2020-05-29T16:15:48.384800Z

had a simple-stateful file-changed function and it was failing because well its stateful

bhauman 2020-05-29T16:17:11.386100Z

and a single npm_deps.js file is shared between the build and an extra-main build

bhauman 2020-05-29T16:18:45.387500Z

so hard to detect a change twice

dominicm 2020-05-29T16:18:51.387800Z

I see, so the state of bundle is external.

dominicm 2020-05-29T16:19:30.389500Z

Hmm, maybe you just need to check if the bundle is newer than the npm_deps.js?

bhauman 2020-05-29T16:20:21.390300Z

nope πŸ™‚ npm_deps.js gets output on every run!!

bhauman 2020-05-29T16:20:51.391Z

so you may start to see these problems accumulating

bhauman 2020-05-29T16:21:21.391900Z

so I have to have a checksum ie hashcode of the contents

dominicm 2020-05-29T16:21:27.392100Z

Ah! So you'd need to do a contents based hash then.

bhauman 2020-05-29T16:21:37.392600Z

yep

bhauman 2020-05-29T16:21:53.393400Z

yeah I thought this would take an hour, you know the story

dominicm 2020-05-29T16:22:07.394100Z

If you don't know, there's a crc32 implementation built into the jvm. It's fairly nice to work with.

bhauman 2020-05-29T16:22:10.394200Z

now I’m having to store that hash in a scoped manner

bhauman 2020-05-29T16:22:32.394600Z

actually (.hashCode ) works just fine

bhauman 2020-05-29T16:22:55.395400Z

not perfect but I’ve never seen it fail

dominicm 2020-05-29T16:23:02.395700Z

I guess it's short and if you're slurping it... I've used crcs with very big files

bhauman 2020-05-29T16:23:42.396300Z

yeah main.js and deps are both small files

dominicm 2020-05-29T16:24:06.397Z

But I have 10,0000 npm deps!

bhauman 2020-05-29T16:24:34.397600Z

not in npm_deps.js you don’t πŸ™‚

bhauman 2020-05-29T16:24:38.397800Z

right????

bhauman 2020-05-29T16:25:03.398100Z

its only the ones you require directly

dominicm 2020-05-29T17:28:23.399500Z

Haha. The fact you put right??? Let's me know you'd have believed me if I'd said that's how many I directly required.

bhauman 2020-05-29T17:29:30.399800Z

hey we’re developers, anythings possible

πŸ˜‚ 1