Fork me on GitHub
#cljs-dev
<
2018-04-09
>
john19:04:36

xposting so more devy folks see it. I'm trying to build a module framework similar to MDC: https://material.io/components/ But I'm getting undefined errors for ModuleLoader when using cljs.main in the attached repro.

john20:04:56

This is an interesting resource, btw, if y'all haven't seen it yet: https://material.io/components/web/docs/closure-compiler/

john20:04:33

talks about some of the conventions they use to make sure that closure keeps working like it is supposed to, wrt code splits

john20:04:16

And is passing a co.edn to -co the best way to pass in the module info to the compiler? EdnReader doesn't like the '#{blah.core} forms found in the documentation's :entries vals, complaining that "maps require an even number of keys." The examples use a build.cljs file to pass the module info to the compiler, but I'd think this'd be doable from the edn file. Not sure if that has anything to do with the EvaluateCodeEvent and RequestSuccessEvent errors I'm getting.

john20:04:10

Also, it seems non-deterministic... do a fresh compile, it'll get to module one. Do a second, it'll get to module two. Hasn't got to module three though.

john20:04:00

Also, there seems to have been some churn in the code-splitting-modules space in the last half year, and some of the docs don't seem to match. Some are declaring (loader/set-loaded! :this-module) at the bottom of the file, others aren't. Some have the :entries vals formatted differently. If I can get a MDC-like module framework working on a sizable project, I'd like to update the docs with the latest and greatest.

john20:04:38

I think the current ModuleLoader is getting disposed of accidentally, or overwritten for some reason

john21:04:48

So, according to this, the bulkLoader is always disposed of after handleSuccess_ and handleError_

john21:04:08

perhaps successive calls to the same loader won't work if the calls aren't issued within the same 5 ms goog.Timer window?

thheller21:04:23

@john loading is async. I don't think you are allowed to kick off multiple loads at the same time

john21:04:30

hmm, bulkLoader is only a temporary loader created in downloadModules_

thheller21:04:13

and especially starting loads before set-loaded! is called is not a good idea

thheller21:04:35

since that will start the download of the already partially loaded module again

john21:04:02

Indeed, calling set-loaded! is causing double loads sometimes

thheller21:04:26

in general calling load at the top level is not a good idea. no point in splitting in the first place if you immediately load things

thheller21:04:34

I guess its for the examples sake but still

john21:04:48

Yeah, it was just for the example

thheller21:04:40

also why are you messing with cljs.loader when building a component lib? libraries should basically never use cljs.loader.

john21:04:26

To provide smaller, piece-meal consumable libs, similar to MDC

thheller21:04:48

that is not what modules do

thheller21:04:13

closure already takes care of that for us

thheller21:04:40

just use separate namespaces if you must but its totally fine to put everything into one fat namespace

thheller21:04:53

closure will remove the things we don't use when everything is done "correctly"

thheller21:04:32

this MDC piece-meal is done for the JS world ... absolutely not required for CLJS/Closure

john21:04:56

right, I also want to make the libs consumable via npm, if possible

thheller21:04:05

aren't there already plenty of those? CLJS is really not a good fit for writing those kind of libs when consumed from JS

john21:04:28

I'm writing a special kind of analytics platform that mostly doesn't exist

thheller21:04:35

everything in CLJS is built around the Closure whole-program optimization. writing libraries means it can't optimize the whole program.

thheller21:04:12

so writing this piece-meal type style of lib is really not going to work well

thheller21:04:59

this is what I have done in shadow-cljs to make this sort of work. its not a great fit but it does work.

john21:04:04

WRT that, I was also wondering if downstream users could reuse the moduleIds I declare in my set-loaded! statements, so that they can construct their own module deps (for building their own modules downstream) using my moduleIds

john21:04:52

I haven't gotten that far yet, with testing, but I don't see why not

thheller21:04:23

I don't see a way how cljs.loader could ever work in a library kind of way for npm

john21:04:38

What's the issue?

thheller21:04:56

assuming that your code is going to get processed by webpack or something. those are never going to understand which files they need to move and stuff

john21:04:54

hmm, yeah I'm not sure about the webpack stuff. With respect to doing the loading downstream, I was thinking of just exposing functions for each module that did the autoloading of the module lazily, when one of its exposed functions is called.

john21:04:31

Of course, if you don't happen to need to load components lazily, you could consume the entire thing as one large library and let DCE get rid of whatever you don't use. But I'd like to provide both options.

thheller22:04:03

but webpack already provides that option for example? are you assuming that your JS folks won't use a build tool at all?

thheller22:04:38

cljs.loader only makes sense if you assume that your JS users will only use YOUR generated JS directly without any other code

john22:04:05

I'm supposing that if a user is capable of exploiting modules and codemotion, either via cljs or closure directly (in js land), then they'll be able to leverage my lib in such a way.

john22:04:28

But if not, then they'll just be able to use it normally

john22:04:27

But, it sounds like you're saying that, unless they're using goog closure specifically, all of this is a wash anyway? I wonder if this module stuff is providing any benefit to users of MDC, outside of google?

thheller22:04:38

I'm saying that cljs.loader is meant for the final app, because only at that point is code-splitting useful. It is never useful for a library.

thheller22:04:55

I think you are mixing your understanding of ES6 Modules with Closure Modules

thheller22:04:03

they are completely different things and not related at all

john22:04:07

Can't downstream users reuse my moduleIds?

john22:04:19

why not?

thheller22:04:25

because it does not make sense

john22:04:35

Not yet 😉

john22:04:02

just kidding, it's still pie in the sky idea... But I don't see why this shouldn't work.

thheller22:04:04

suppose you package one component per module. but a user of your lib wants to use 3 components on the same page. why force them to download 3 different modules via cljs.loader?

thheller22:04:20

maybe I just don't understand your vision. I remember a while ago I didn't understand a different vision of yours. 😉

john22:04:27

🙂

john22:04:56

Yeah, I'm going to bang on it more tonight. The leads you gave me will probably resolve my issues. Then I'll put together an example of what I'm talking about

thheller22:04:43

start two when one finishes, three when two finishes

john22:04:13

Perfect explanation. Thanks!

thheller22:04:56

don't know if cljs.loader exposes a loadMany but the ModuleLoader from goog has methods for loading multiple mods an continue when all are loaded

john22:04:52

Awesome. I'll ping you back with my progress. It may end up being a useful experiment.