Fork me on GitHub
#shadow-cljs
<
2017-10-05
>
thheller06:10:53

ah, right macros have analyzer data too

thheller08:10:22

@mhuebert I finished the proper resource loading and that definitely works. can’t quite work out why it complains about those missing vars

thheller08:10:32

I suspect I generate macros incorrectly

thheller08:10:50

WARNING: Use of undeclared Var cljs.core$macros/seq at line 2 is the warning I get

thheller08:10:13

but it should use cljs.core/seq as its not a macro but a fn

thheller08:10:40

either incorrect macros or not setting some compiler state properly

thheller08:10:49

analyzer data for everything is definitely loaded

mhuebert09:10:01

Macro loading can be weird. I think even self host macros can be in .clj files, as long as no java code is called

thheller09:10:02

I fixed all the macro stuff

thheller09:10:14

they are defintely all loaded (including analyzer data)

thheller09:10:25

they just generate weird code

thheller09:10:47

must be missing something I’m supposed to set

mhuebert09:10:24

Is it happening at read time, syntax quote symbol resolution?

thheller09:10:19

maybe? haven’t tracked down the dynamic vars

thheller09:10:22

cljs.js/patch-alias-map not quite sure what that does yet

thheller09:10:24

;; when compiling a macros namespace that requires itself, we need
              ;; to resolve calls to `my-ns.core/foo` to `my-ns.core$macros/foo`
              ;; to avoid undeclared variable warnings - António Monteiro

thheller09:10:43

cljs/analyzer.cljc

thheller09:10:52

that sounds like the problem

thheller09:10:05

I’m a bit lost. Gotta do some other work stuff. will try more later

mhuebert10:10:35

ah.. I see. when shadow is running the analyzer, compiling macros for self-host, is it taking the :clj path? haven’t looked if the 2nd pass is running in clojure or clojurescript I see, bootstrap.clj runs in clj-mode, so that reader conditional expr is ignored.

mhuebert10:10:06

re FIXME: actually load it all, not just core - loading analyzer caches on init - not sure I understand the intention exactly, but FWIW I think loading/decoding ana caches is something better done at the time the relevant source files are required vs. all at once. (because this can also be slow, these ana caches can be huge.) so for example, the ana cache for cljs.spec.alpha would be downloaded and loaded at the same time as cljs.spec.alpha is required by source code evaluated by the self-host compiler (even if cljs.spec.alpha is already in the app build)

thheller11:10:47

boot/load does not load namespaces that are already loaded

thheller11:10:04

that also means it does not load analyzer data for those

thheller11:10:43

so basically boot/init needs to do one load for the “missing” analyzer data

thheller11:10:21

run the bootstrap build from master, it should log quite a bit about whats happening

thheller11:10:44

it does load everything correctly (I think)

thheller11:10:52

I’m just not setting some analyzer data I’m supposed to set

thheller11:10:15

does this expose the compiler state atom somewhere?

thheller11:10:47

or do you have a bootstrap example handy with just CLJS tooling?

thheller11:10:17

the analyzer data looks correct to me but I have no idea what cljs.js/patch-alias-map does and cljs calls it all over the place

thheller11:10:28

I never do, so thats my prime suspect currently

mhuebert11:10:28

yes, its at maria.eval/c-state

mhuebert11:10:16

yeah I understand what’s happening & have it running locally, have been toying with cljs.analyzer

thheller11:10:06

ah you have a data visualizer, cool

mhuebert11:10:24

it is a work in progress, not perfect 🙂. but you can click the left-brackets to collapse

thheller11:10:31

one suggestion: for maps, attempt to sort the keys

mhuebert11:10:39

oh, good idea

thheller11:10:43

I do it in devtools console stuff

mhuebert11:10:50

what I meant is that instead of a no-op, load should load the ‘missing’ analyzer data only when a namespace is required

thheller11:10:51

makes a huge difference when debugging maps

mhuebert11:10:04

that way you don’t have to do it all in the beginning

mhuebert11:10:17

so the load function, for namespaces that are already loaded, returns only the cache

mhuebert11:10:21

or a blank js as source

mhuebert11:10:25

in addition to the cache

thheller11:10:46

hmm yeah that could work as well

mhuebert11:10:51

and then sets the namespace as ‘fully’ loaded, so the next time it runs, it is ignored

thheller11:10:01

need to rewrite the loader a bit but possible

mhuebert11:10:10

I’ve played with these settings back and forth. in a reasonably sized project this stuff really matters

thheller11:10:13

delaying as much as possible makes sense

thheller11:10:39

;; FIXME: this should probably do something async
          ;; otherwise it will block the entire time 60 or so files
          ;; are eval'd or transit parsed

thheller11:10:55

already left a note there to turn the load into something that is async

thheller11:10:05

so the browser gets a chance to breathe

thheller11:10:33

in the demo it already loads 60 files in one go

thheller11:10:44

well the download is parallel and async

thheller11:10:46

but the eval isn’t

mhuebert11:10:53

I believe Planck uses a lazy-map for cljs.analyzer/namespaces

mhuebert11:10:21

so the ana cache is decoded hte first time it is read

thheller11:10:42

need to finish this work stuff first

mhuebert11:10:34

ok. i am setting up another project with shadow-cljs. a few of us are using maria at clojurebridge this weekend so it needs to be as stable as possible 🙂

mhuebert12:10:56

could these warnings/resolutions be related to clojure.core/cljs.core aliasing? (probably not, more likely related to self-require..)

thheller17:10:13

that took way longer than expected 😛

thheller17:10:21

back from fighting some horrible css

mhuebert18:10:22

🙂 i spent half the afternoon fighting with webpack trying to get sass and postcss autoprefixing to play together

thheller18:10:38

webpack would be a delight. I have this legacy system some designer built that uses compass from like 100 years ago

mhuebert18:10:01

hehe. haven’t heard anyone mention compass in a long time

thheller18:10:05

too much compass weirdness to use sass directly

thheller18:10:34

one day I’ll replace that sucker 😉

mhuebert18:10:52

getting an example project set up now but taking a break for dinner

thheller18:10:09

I have narrowed it down

thheller18:10:13

it must be the macro generation

thheller18:10:17

the macro file is full of

thheller18:10:44

new cljs.core.Symbol("cljs.core$macros","seq","cljs.core$macros/seq",-1873195024,null) which should probably be cljs.core/seq

thheller18:10:24

so, I just set-up a test macro ns with a simple dummy macro

thheller18:10:42

(ns demo.macro)

(defmacro foo [& body]
  `(seq ~@body))

thheller18:10:03

that then contained new cljs.core.Symbol("demo.macro$macros","seq","demo.macro$macros/seq",-1873195024,null)

thheller18:10:22

rewrote that manually and it works

thheller18:10:39

now I need to figure out what controls that 😛

thheller19:10:39

woho I might have it

thheller19:10:27

works, with react via my JS deps 🙂

thheller19:10:55

only one issue, reagent doesn’t declare that it uses clojure.string. gotta get that fixed.

thheller19:10:59

hmm weird. it has proper requires in master

thheller19:10:52

nvm the demo doesn’t have the proper require 😛

mhuebert19:10:07

spinning up a demo project, getting

[:browser] Build failure:
The required namespace "cljs.env.macros" is not available, it was required by "cljs/js$macros.cljc".

mhuebert19:10:01

thats good news!

thheller19:10:16

hmm strange. now I’m scared to relaunch my process 😛

mhuebert19:10:26

sorry not that project

mhuebert19:10:28

my own project

thheller19:10:55

ah did you delete target/shadow-cljs before trying? it might just be AOT issues

mhuebert19:10:09

didn’t do that

thheller19:10:32

still need to fix some issues but I’m amazed that reagent just works

mhuebert19:10:15

yeah that is fantastic

mhuebert19:10:19

how does reagent require react?

mhuebert19:10:46

ah i see, just [react :as react]

mhuebert19:10:02

so shadow is pulling that from node_modules

thheller19:10:31

no :foreign-lib involved

thheller19:10:26

code evaled in the browser probably will not be able to access those JS dependencies

mhuebert19:10:47

still getting the same error

thheller19:10:12

I’ll check it out

thheller19:10:29

might be the missing cljs/js.cljs override?

mhuebert19:10:39

yes, i remembered to put it in the project but not in the entry

thheller19:10:08

do you use yarn or npm?

mhuebert19:10:40

yarn usually

thheller19:10:50

hmm no the override is correct

thheller19:10:06

always yarn add shadow-cljs to the project itself

mhuebert19:10:08

i am not using node_modules here for anything though

thheller19:10:36

I’m surprised it compiles at all

thheller19:10:43

since it won’t find any of the foreign libs

mhuebert19:10:48

from a yarn global add ...

thheller19:10:08

the global install is just for convenience

thheller19:10:27

so you can use shadow-cljs CLI command with yarn run

thheller19:10:40

if its part of the project, it will always use the version from the project

thheller19:10:52

and ensure that the project has the proper dependencies available

thheller19:10:28

anyways .. not sure what the problem is

thheller19:10:32

digging deeper

mhuebert19:10:11

i had clojurescript in the dependencies that was project.clj

thheller19:10:27

:entries [shadow-eval.core]

thheller19:10:38

this is not required, as the app will load it anways

thheller19:10:59

it just needs “extra” entries that the app doesn’t load on startup

thheller19:10:04

ie. support files

thheller19:10:29

it should still find the macros though

thheller19:10:48

there might be an issue with self-host using self-host 😛

mhuebert19:10:04

wait, what do you mean about shadow-eval.core

mhuebert19:10:25

doesn’t every build need at least one entry point?

mhuebert19:10:30

err every module

mhuebert19:10:25

you might be right about this self-host using self-host

thheller19:10:22

taking it out fixes it

mhuebert19:10:45

here is my cljs-live entry for maria.user:

{:name            maria.user
                  :entry           #{maria.user}
                  :provided        #{maria.frames.live-frame}
                  :entry/no-follow #{maria.eval
                                     cljs-live.eval
                                     cljs.js
                                     cljs.compiler
                                     maria.editors.code
                                     maria.repl-specials
                                     cljs.core.match
                                     maria.views.repl-specials
                                     maria.live.analyze
                                     maria.live.source-lookups}
                  :entry/exclude   #{cljs.pprint}}

thheller19:10:09

right I didn’t add the no-follow support yet

mhuebert19:10:28

i forgot about that.

thheller19:10:40

basically the :bootstrap-options :entries just controls which namespaces are allowed to be used by self-host eval

thheller19:10:20

and that can’t use self-host itself it seems … would probably make my head explode if that worked 😛

mhuebert19:10:46

yeah. so the :entry/no-follow excludes a thing, and does not look at its transitive deps at all (it does not specifically exclude all of its transitive deps, because they could be used elsewhere), there are some namespaces (like all those listed above) that I just found to be problematic with self-host

thheller19:10:16

cljs.js is in there 😉

mhuebert19:10:21

precisely 🙂

thheller19:10:59

so I can probably add a :bootstrap-options {:exclude #{cljs.js other syms} to control that

thheller19:10:21

to prevent it from compiling those

thheller19:10:49

so the app fails with a bunch of React is not defined

thheller19:10:01

that is because its still trying to use the React global

thheller19:10:29

eg. (def ^:dynamic *create-element* js/React.createElement) in re-view-hiccup.hiccup

thheller19:10:55

thats not great.

thheller19:10:15

hmm I should add an option that lets expose some of my js deps as globals

thheller19:10:19

to ease the transition

mhuebert19:10:41

i ended up doing that because cljs compiler things have been changing so frequently, and the :foreign-libs was so unpredictable

mhuebert19:10:43

finally gave up

thheller19:10:01

yeah, totally understandable

mhuebert19:10:50

^^ an option to expose js deps as globals would be super helpful i think, i was trying to figure out how to make all my libraries possible to compile with shadow-cljs and also cljsbuild et al

thheller19:10:22

you already configured everything to use the global

thheller19:10:26

just didn’t include it 😉

mhuebert20:10:00

no nevermind. for now i will just include script tags.

thheller20:10:27

if you want something that is compatible with both tools

thheller20:10:40

you should probably use ["react" :as react]

thheller20:10:07

BUT that needs updated cljsjs.react, I’m not sure those are available yet

thheller20:10:34

do you have a script tag I can test with?

thheller20:10:06

seems to work

thheller20:10:18

doesn’t work quite right, init doesn’t seem to complete

mhuebert20:10:53

there are some other errors on that page, just a sec

mhuebert20:10:55

cleaning it up

mhuebert20:10:13

do i still need to include :macros in bootstrap options

thheller20:10:52

only if you want macros that aren’t otherwise included

thheller20:10:37

ah, the load fn just silently stops if a namespace is not available

thheller20:10:40

thats not great 😛

mhuebert20:10:41

if you pull the demo, it works now

mhuebert20:10:07

put in the value-viewer

thheller20:10:16

yes, works. 🙂

mhuebert20:10:55

did you fix the thing with for loops?

thheller20:10:03

(defonce _
         (boot/init #(swap! state assoc :ready true)))

mhuebert20:10:25

now, if i run (require '[re-view.core :as v :refer [defview]]) it says :invalid-refer, but if I run (require-macros ...) first, it loads

thheller20:10:28

I’ll fix that so you can call init more than once without issue

mhuebert20:10:56

(`defview` being a macro)

thheller20:10:26

right, thats the analyzer data issue

thheller20:10:55

this one ;; FIXME: actually load it all, not just core

thheller20:10:17

since the shadow-eval.core namespace already uses re-view.core it doesn’t properly load the analyzer data for it

thheller20:10:20

at least I think so

mhuebert20:10:42

hmm. so currently we set cljs/*loaded* (or whatever) with the names of preloaded namespaces, so boot/load isn’t called at all for them

thheller20:10:24

yes, but it should only skip loading the JS. it should still load the analyzer data

mhuebert20:10:47

but if we don’t put all of those into *loaded*, but instead just keep that knowledge to ourselves, then when we see them for the first time in boot/load we return the cache + blank js

thheller20:10:13

but that evals the JS

mhuebert20:10:34

it only evals what we return, the blank helper js

thheller20:10:44

no I control the eval of the deps

mhuebert20:10:09

and always return the blank helper?

thheller20:10:39

I load the JS and analyzer data, put it into the correct places, then callback

thheller20:10:01

it just stops too early in cases where the JS is loaded but the analyzer data is not

thheller20:10:32

should be an easy fix though

thheller20:10:06

thought for a moment I could drop init entirely

mhuebert20:10:10

but this is triggered by load and not init

thheller20:10:17

but I can’t since cljs.js may not always call the load fn

mhuebert20:10:42

i think cljs.js will call the load fn if we don’t put all the app namespaces into *loaded*

mhuebert20:10:58

then we can get rid of init

mhuebert20:10:17

well, still need init for the index

thheller20:10:34

can load the index in load if its not loaded

thheller20:10:21

if I just take out the init and then do something like (+ 1 2) I get an error

thheller20:10:36

[ 
:div "Error: " "#error {:message \"Could not eval [test]\", :data {:tag :cljs/analysis-error}, :cause #error {:message \"Cannot read property 'findInternedVar' of null at line 1 \", :data {:file nil, :line 1, :column 1, :tag :cljs/analysis-error}, :cause #object[TypeError TypeError: Cannot read property 'findInternedVar' of null]}}"
 ] 
but no load is ever called

thheller20:10:46

so definitely need init

mhuebert20:10:04

without init do we need (require '[cljs.core :include-macros true])

thheller20:10:39

I think init is safer to ensure that everything is actually ready

thheller20:10:53

should be simple fix anyways, just really need to grab some food 🙂

mhuebert21:10:42

is there a reason to use both loaded-ref and cljs/*loaded*?

thheller21:10:59

re, yes. will matter later.

mhuebert21:10:03

ignore the fact that loaded-ref was also taken out, i didn’t know its purpose

mhuebert21:10:23

this compiles/runs for me

mhuebert21:10:30

(the bootstrap demo)

mhuebert21:10:21

ech i’ll put loaded-ref back in there

mhuebert21:10:40

it should never load the :js for a pre-loaded ns, but otherwise the compiler doesn’t need to know they exist until they are required

thheller21:10:29

pushed the fix

thheller21:10:19

the loaded-ref is there because of code splitting, well thats the plan

thheller21:10:50

will make sense if I actually enable it 😉

thheller21:10:15

right now there will be a problem if you use 2 modules and shadow.bootstrap ends up in the second module

thheller21:10:38

the first will blindly call shadow.bootstrap.set_loaded without having declared a proper dependency on it

thheller21:10:46

so it will fail

thheller21:10:52

not important yet

thheller21:10:23

but the fix should take care of all loading issues

mhuebert21:10:30

ok taking a look

thheller21:10:42

it might load a bit too much now in init

thheller21:10:56

since it loads analyzer data for everything loaded by the app

thheller21:10:07

but that could be delayed until load

thheller21:10:09

ah not its all correct

thheller21:10:21

cljs.core$macros depends on all that stuff, not the app

mhuebert21:10:07

where is it loading all of that?

thheller21:10:54

hmm something doesn’t quite work

mhuebert21:10:22

did you see the gist above? the demo totally worked without doing any extra loading in the beginning, just making sure not to load :js for the pre-loads

thheller21:10:59

it worked, but it was missing analyzer data for things like clojure.string

mhuebert21:10:59

boot/load should be called for clojure.string, analyzer data loaded but no js evaled

thheller21:10:03

so if something was loaded it never ended up in the list

thheller21:10:20

its correct now though

mhuebert21:10:32

that check stays

mhuebert21:10:42

but the ns doesn’t get put into loaded-ref until loaded

thheller21:10:43

but (require '[re-view.core :as v]) doesn’t seem to do anything

thheller21:10:15

right .. *loaded*

thheller21:10:45

right … now I get it

mhuebert21:10:13

the only reason i am focusing on this is because i used to have cljs-live behave like this and load everything up-front, and with a project that goes beyond tiny example, it can be really slow

thheller21:10:46

don’t worry .. it will not be slow, doesn’t matter which size

thheller21:10:05

once I make load async properly

thheller21:10:40

but yes I get your point

thheller21:10:38

analyzer data is now checked against the actual compiler state not the loaded-ref (or *loaded*)

thheller21:10:37

should be far more accurate

thheller21:10:05

would it make sense if I let you pass in the compiler state to init/load?

thheller21:10:41

yeah seems wrong to declare that global

mhuebert21:10:59

you can have multiple compiler states in an app, perform namespace surgery on namespaces, reset them, etc. so checking the compiler state for whether or not to load an analysis cache makes perfect sense

mhuebert21:10:28

I’d have to do quite a refactor if I had to ‘move’ maria’s compiler state, it is referenced from so many places

thheller21:10:51

ok (require '[re-view.core :as v :refer [defview]]) works now

thheller21:10:27

pushed the fix

thheller21:10:03

does a bit more work but should ensure that everthing is properly loaded

mhuebert22:10:35

hmm, I think there are still some funky things with syntax quote

mhuebert22:10:12

these are all in syntax quoted forms where i would expect them to resolve to cljs.core

mhuebert22:10:48

actually that one, self i think is a function parameter

mhuebert22:10:41

this is the macro being called, in the cells.cell$macros namespace:

(defmacro cell
  "Returns an anonymous cell. ..."
  ([expr]
   `(~'cells.cell/cell nil ~expr))
  ([key expr]
   `(let ~lib-bindings
      (~'cells.cell/cell* ~(cell-name key) (fn [~'self] ~expr)))))

mhuebert22:10:29

i’ve pushed the current state

mhuebert22:10:36

(to shadow-eval)

mhuebert22:10:40

heading to sleep now

mhuebert22:10:21

oh…… AOT issue

thheller22:10:04

whats that? quil?

mhuebert22:10:46

a thing i wrote

mhuebert22:10:32

well i wrote the cells lib, friends wrote the shapes library and collaborated on that intro doc 🙂

thheller22:10:41

just pushed a bit of cleanup, both boot/init and boot/load now take the compiler-state as their first argument

thheller22:10:55

also did the first async run queue

thheller22:10:02

but its a bit too naive for our purposes

mhuebert22:10:37

if code was written on paper, i would be preparing for a festive burning of the cljs-live repo 😉

thheller22:10:13

this maria.cloud stuff is seriously cool

thheller22:10:39

I would hold off on the burning, not quite sure we covered everything yet

thheller22:10:50

still missing the excludes

thheller22:10:08

although not sure they are actually needed

mhuebert22:10:24

how would you approach it w/o them?

mhuebert22:10:58

eg. the reason that you can do (require [maria.eval :as e]) and inspect the compiler state is because I’m able to exclude cljs.js. I could attempt to reorganize the whole app around dividing lines based on which namespaces happen to not freak out in self-host, but that could get rather tedious

thheller22:10:07

yeah thats a good use case

mhuebert22:10:12

there are quite a few macro namespaces, for instance, which will never work in self-host (or not unless the authors make a serious effort), but namespaces that use those macros can nevertheless be used in self-host without problem (provided we can exclude those problematic ones)

mhuebert22:10:54

eg. you can have a namespace which uses core.async, and run those functions (compiled) in self-host no problem, because macroexpansion already happened, despite core.async not working in self-host. (mfikes has a fork that does, but many libs don’t use it)

mhuebert22:10:06

*core.async macros

thheller22:10:21

hmm yeah but inside self-host you can’t use go

thheller22:10:42

you can use the functions of cljs.core.async but not actually do anything without go

mhuebert22:10:46

right. you can’t use the macro, but you can use a function that was defined using go, because it has already been expanded/compiled.

mhuebert22:10:47

(maybe some day this will become obselete: https://github.com/mfikes/andare)

thheller22:10:54

ok, I’ll add :exlude taking a set of namespace symbols for macros that won’t be included

thheller22:10:12

yeah problem with andare is that it uses the same namespaces

thheller22:10:19

so it overrides cljs.core.async

thheller22:10:26

can’t really do that

thheller22:10:31

should have used other namespaces

thheller22:10:05

that seems tedious, should I add an option to init that can load stuff?

mhuebert22:10:17

i was wondering about that

mhuebert22:10:23

probably would make sense

mhuebert22:10:27

ok, i am crashing. good night!

thheller23:10:02

(shadow.bootstrap/init compile-state-ref {:load-on-init '[shadow-eval.user]} init-cb)

thheller23:10:11

damn forgot about excludes again 😛

thheller23:10:17

after sleep