Share your thoughts in the 2024 State of Clojure Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in ClojureScript by

Use case for boot-cljs and boot-reload:

After compilation boot-reload reloads the changed JS files. So that the files can be reloaded in correct order, boot-cljs uses dependency graph to sort the files. Currently boot-cljs accesses compiler state directly and uses data from {{:js-dependency-index}} to build the graph: https://github.com/adzerk-oss/boot-cljs/blob/0.0-3308/src/adzerk/boot_cljs/impl.clj#L17-L36

Simple solution:

If dependencies (requires) of namespace are exposed through API it is easy to build graph of cljs namespace dependencies: https://github.com/adzerk-oss/boot-cljs/blob/d479f10935be321232e2363e2ae3e9cc515a81af/src/adzerk/boot_cljs/impl.clj#L12-L32

Problem with this solution is that {{all-ns}}, {{ns-dependencies}} or {{target-file-for-cljs-ns}} do not work with foreign-deps. While foreign-dep files don't usually change and thus aren't reloaded, it's possible that user has local JS files in the project using foreign-deps and those can change.

Questions, notes and issues

  • Should {{cljs-dependency-graph}} be exposed in the API or is it enough to provide {{ns-dependencies}} and such which user can use to create dependency graph?
  • {{cljs.build.api/parse-js-ns}} can also be used to read provides and requires from compiled JS files, but this doesn't work with foreign-deps either
  • Perhaps there is some way in Closure library to reload files in correct order?
  • Supporting foreign-deps is not perhaps necessary, but if there is good way it would be nice to have.

5 Answers

0 votes
by
_Comment made by: deraen_

I would add the call to {{cljs.compiler.api}} and it could be called {{output-dependency-graph}}.

Creating the graph requires list of all the nodes and dependencies for each node. For Cljs namespaces
these are accessible through {{all-ns}} and ns analysis map {{:requires}}. Data about foreign-deps
and closure libs is available in the compiler state under {{:js-dependency-index}} key. To create the
graph we need to:

1. Get list of all nodes
2. Get dependencies for given node
3. Get output file for given node

Because steps 2 and 3 depend on the type of node, it would probably be easiest to collect those
values in step 1. So step 1 would do something like this:

{{(get-nodes ...) => [{:provides "goog.net" :file "out/goog/net.js" :dependencies #{"goog.foo"}} {:provides "frontend.core" :file "out/frontend/core.js" :dependencies #{"cljs.core"}}]}}

That could be implemented by concatenating data from cljs namespaces retrieved from {{all-ns}} etc. with
data from {{:js-dependency-index}}. The next and last step would be to construct the graph using reduce.

Using this implementation there would be just one new API call: {{output-dependency-graph}}.

I was thinking alternative approach with {{all-ns}}, {{find-ns}} etc. versions which would work also with foreign-deps and closure libs, but I don't think it's very easy (or efficient) e.g. to retrieve data for foreign-dep with just a name as they are indexed by file paths.
0 votes
by

Comment made by: dnolen

Now that CLJS-1437 is merged what is needed to wrap this one up?

0 votes
by

Comment made by: deraen

My current plan with boot-cljs/boot-reload is to use Figwheel client code which uses Google Closure dependency graph for loading the files in correct order. Thus I don't need this anymore. Perhaps it's best to close this if no-one needs this currently?

0 votes
by

Comment made by: dnolen

It may still be useful at some point. Will just lower the priority.

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJS-1407 (reported by deraen)
...