Fork me on GitHub
#hoplon
<
2016-11-06
>
flyboarder00:11:42

Hey guys, I just put together a presentation for the Toronto Clojure Meetup, it would be awesome if you can flip through it and let me know if I can improve on it anywhere, cheers!

thedavidmeister13:11:50

alpha17 doesn’t support deref on events?

micha14:11:00

@thedavidmeister are you using the jquery attr provider?

thedavidmeister14:11:00

actually, i’m not using alpha17 because it’s not on clojars

thedavidmeister14:11:42

i was just reading the code

micha14:11:24

it should be in hoplon.jquery

thedavidmeister14:11:31

(extend-type js/jQuery.Event
  cljs.core/IDeref
  (-deref [this] (-> this .-target js/jQuery .val)))

micha14:11:34

it needs to implement the protocol in te jquery Event type

thedavidmeister14:11:39

so what’s the way to keep using jQuery moving forward?

thedavidmeister14:11:55

and is that OK, or is the plan to remove it someday?

micha14:11:28

i don't think we plan to remove it, it's just optional now

micha14:11:49

you can do (:require [hoplon.jquery]) now

micha14:11:55

that will install all the jquery stuff

micha14:11:07

or if you use boot-hoplon the hoplon task will do that for you automatically

micha14:11:47

so if you have a project using boot-hoplon using a version of hoplon before alpha17, you can upgrade to alpha17 with no changes

thedavidmeister14:11:49

yeah i have boot hoplon

thedavidmeister14:11:21

well yeah, as i’ve been finding today, getting events to propagate on detached DOM elements is fiddly without jQuery

thedavidmeister14:11:30

so if for nothing other than testing, i want to keep it

micha14:11:53

yeah i like jquery because it does what i expect most of the time

thedavidmeister14:11:39

also it is still being actively developed

micha14:11:57

and it's easy to wrap because it's not object oriented

micha14:11:06

goog closure is very OO

micha14:11:30

so it has pointless enum types everywhere

micha14:11:49

i guess to support the closure compiler

thedavidmeister14:11:56

so do i have to require hoplon.jquery and hoplon.core everywhere?

thedavidmeister14:11:02

because that will get annoying

micha14:11:09

if you use the hoplon task you don't have to do anything

micha14:11:24

no changes are needed to your code whatsoever

micha14:11:35

so you should be good then

thedavidmeister14:11:41

when do you think alpha17 will be on clojars, so i can try it out?

micha14:11:56

i can push it to clojars today

micha14:11:35

are you sure the when-dom really isn't necessay?

thedavidmeister14:11:50

i don’t know why it was there in the first place

micha14:11:13

it was there because certain events couldn't be added until the element was in the dom

thedavidmeister14:11:23

ok, well if you can remember what events they are

thedavidmeister14:11:26

we can update the test easy

micha14:11:32

i do not 😕

thedavidmeister14:11:38

this is why test

micha14:11:44

i just don't want to break stuff

thedavidmeister14:11:12

but if nobody can remember what it was for, that’s tricky

micha14:11:28

i can look in the git history

thedavidmeister14:11:34

that could be good

thedavidmeister14:11:41

also i definitely can confirm that different events bubble differently or not at all while detached in different browsers

flyboarder14:11:50

I think we should be safe for the most part with the when-dom changes

thedavidmeister14:11:57

and jquery events and native ones behave differently in that respect too

thedavidmeister14:11:45

but i wouldn’t expect an event that you bind to a detached element to break when you add it to the document

thedavidmeister14:11:49

that would be weird

flyboarder14:11:58

The issue there is when an event is triggered before it's added not after, something's need the parent to exist

micha14:11:55

what was the issue with with-dom?

micha14:11:06

was it interfering with something?

flyboarder14:11:20

With the tests I believe

thedavidmeister14:11:27

made it harder to test

thedavidmeister14:11:43

because it means events don’t get bound until the element is added to the dom

thedavidmeister14:11:56

so i have to manually add every element to the document before i can test it

micha14:11:30

but if you test it out of the dom you're testing a weird edge case, no?

micha14:11:37

and not the usual case

thedavidmeister14:11:56

i’m just testing the logic of my components

micha14:11:49

i think there must be a way to fix this without removing when-dom

micha14:11:08

is the tst/src/hoplon/on.cljs file an example of the issue?

micha14:11:23

the click-bind-test-div function?

thedavidmeister14:11:46

actually that is rendered in a browser

thedavidmeister14:11:50

and looked at with selenium

thedavidmeister15:11:12

that was hopefully to demonstrate to you that removing with-dom does not break that case 🙂

thedavidmeister15:11:46

this bind-events test is a very simple example of what i might want to test

thedavidmeister15:11:02

that would not work with with-dom

micha15:11:07

so the issue is you need it to be synchronous for testing and not async?

thedavidmeister15:11:39

well, partly the async and partly the explicit checking that the element is in the document before binding an event

thedavidmeister15:11:50

both are inconvenient

micha15:11:58

like why not add i to the dom after line 10 in that example?

thedavidmeister15:11:33

well yeah, but i need to deal with async and attaching elements to the dom for every single test

micha15:11:38

(.append (js/jQuery "#container") i)

micha15:11:55

you could make a div-in-dom function

thedavidmeister15:11:02

well there’s no #container but yeah...

micha15:11:04

instead of (h/div :click f)

micha15:11:15

you would do (div-in-dom :click f)

micha15:11:18

that would do like

thedavidmeister15:11:21

more like (-> js/document .-body (.appendChild el)))

thedavidmeister15:11:54

and also the async

thedavidmeister15:11:31

i dunno, seems awkward to do this juggling for every single test shrug

thedavidmeister15:11:03

well i just did this

thedavidmeister15:11:09

(deftest bind-events
 (let [c (j/cell nil)
       f #(reset! c true)
       i (h/div :click f)]
   (-> js/document .-body (.appendChild i))

   ; Native event.
   (is (nil? @c))
   (.dispatchEvent i (js/Event. "click"))
   (is (= true @c))))

thedavidmeister15:11:17

doesn’t work because of async i think

micha15:11:40

cljs test has async tests

thedavidmeister15:11:54

yes but how do i avoid race conditions with with-dom?

micha15:11:20

oh derp i see it

micha15:11:25

oops just updated again

micha15:11:30

forgot to add to dom

thedavidmeister15:11:41

but why is that with-dom on line 6 guaranteed to execute after the with-dom from on!?

micha15:11:53

because it's added later

micha15:11:00

the handlers execute in order

micha15:11:21

ah yeah that's right

thedavidmeister15:11:31

the first call is first, but if there’s a second call, who knows?

micha15:11:33

a settimeout that's longer than the polling interval perhaps

micha15:11:54

i mean testing stuff will be weird, in any case

thedavidmeister15:11:54

still not guaranteed, what if i get a garbage collection or something?

micha15:11:06

i believe timeouts do execute in order

thedavidmeister15:11:06

i mean, i’m running hundreds of tests that are all doing this

thedavidmeister15:11:26

but then, i also add the overhead of all these timeouts to my tests 😕

micha15:11:43

like if you schedule a timeout and the thing is delayed, it will still execute them in order

micha15:11:48

just later

thedavidmeister15:11:53

yes that’s true

micha15:11:22

testing stuff is always going to be weird when you're doing unit tests and not integration tests

micha15:11:41

like with selenium you have integration tests, which are like making a normal application

thedavidmeister15:11:42

but i either have to add like 100ms to every test, which will really slow things down

thedavidmeister15:11:02

yeah i know, but my selenium tests are already clocking in at 10+ minutes and i’m nowhere near done with my app

thedavidmeister15:11:10

and they’re getting flaky

thedavidmeister15:11:30

and also, it’s very hard to directly measure some things, like the state of cells

micha15:11:48

perhaps mutation observers

micha15:11:54

are the thing we need here

micha15:11:58

instpead of polling

thedavidmeister15:11:16

yeah, if there’s an alternative that would be good

thedavidmeister15:11:27

real shame we can’t remember what was broken in the first place 😞

thedavidmeister15:11:45

but i was listening to your podcast from the other day, and one of you mentioned the two modes of developing with hoplon

thedavidmeister15:11:52

“making the components” and “wiring everything up"

micha15:11:08

i am just wary or making changes just to support tests

micha15:11:22

that road leads to madness

thedavidmeister15:11:32

well it goes somewhere...

micha15:11:46

we have nodejs apps at work that are insane because of stuff they did to support testing

thedavidmeister15:11:03

right now it goes into silly things i have to do for selenium to see 1/10th of what is actually happening

thedavidmeister15:11:47

well… i can live with attaching all my dom elements manually before testing them if i have to

thedavidmeister15:11:02

but i don’t want race conditions or arbitrary timeouts in the tests either 😕

micha15:11:02

we could fire a in-dom event when the when-dom does its thing

micha15:11:18

then you can put an event handler on that

thedavidmeister15:11:24

actually that would be amazing

micha15:11:25

and run your tests

thedavidmeister15:11:32

because i need that elsewhere other than tests

thedavidmeister15:11:55

like for example, i have a js library that needs a canvas element to work on

flyboarder15:11:47

I don't want to suggest life cycles or anything but maybe it would be good to emit events so elements act more like they were created from HTML

thedavidmeister15:11:32

just knowing that something is “done being built” would be helpful

thedavidmeister15:11:39

both for testing and working with 3rd party libs

micha15:11:59

there is no way to really know when a thing is done being built

micha15:11:03

because we're in lisp

micha15:11:19

a dynamic language has no way to know when you're done programming

micha15:11:27

because you can even be doing stuff in the repl

micha15:11:02

but i do think that when we poll like in when-dom we are introducing nondeterministic behavior

thedavidmeister15:11:06

what about “hoplon core is done messing with this element”?

micha15:11:16

so the event would totally make sense

micha15:11:24

well hoplon is extensible

micha15:11:35

hoplon doesn't know when it's done

micha15:11:43

you can be hoploning at the repl

micha15:11:29

just in general there isn't a way for lisp programs to know much about what their end goal is

thedavidmeister15:11:48

but it really is not fun to have to fall back to timeouts to hope an element is ready to pass off to a lib/test

micha15:11:01

yeah that's a unique case though

micha15:11:16

we use timeouts in the when-dom business because of browser limitations

micha15:11:32

but an event that fires when the thing is in the dom would solve that

thedavidmeister15:11:32

i feel that if you extend hoplon with something that introduces async it’s up to you to manage that

thedavidmeister15:11:45

but what hoplon ships with should be manageable “out of the box"

thedavidmeister15:11:07

i do get what you’re saying about being able to change things dynamically

micha15:11:20

well you definitely shouldn't be making applications that depend on being able to order your event handlers via reflection

micha15:11:04

if you're running into race conditions with when-dom in your application i'd say you're doing something crazy and there is certainly a simpler way

micha15:11:29

usually lifting whatever it is to one level of abstraction higher

micha15:11:15

testing is a good example of what you don't want to do in an application

micha15:11:42

like in tests you're exposing internals of different levels of abstraction and intermingling them

micha15:11:50

which you definitely don't want to do in the application

thedavidmeister15:11:34

i probably could solve the lib problem using when-dom

thedavidmeister15:11:52

but i am a bit concerned about “stacking” when-dom

micha15:11:58

we can fix that

micha15:11:07

what we do is make a vector of callbacks

micha15:11:12

attached to the element itself

micha15:11:34

when you call when-dom it creates that vector or adds a handler to it if it already exists

micha15:11:56

and when the thing is in the dom it fires all the handlers

micha15:11:26

if you add a handler via when-dom when it's already in the dom it will do process.nextTick or whatever it is in the browser

micha15:11:41

or settimeout 0

micha15:11:10

then there is no nondeterminism

thedavidmeister15:11:24

i think that would be a good improvement

thedavidmeister15:11:06

then i’d be willing to try your suggestion of wrapping the tests in when-dom

micha15:11:34

ok cool i'll get something going here

micha15:11:44

should be straightforward

thedavidmeister15:11:20

should i paste this conversation onto the github issue?

micha15:11:03

that would be good for future-us to have when we wonder why we did this 🙂

flyboarder15:11:03

Browserify solved next tick already, maybe we can use this approach? http://timnew.me/blog/2014/06/23/process-nexttick-implementation-in-browser/

micha15:11:24

interesting

flyboarder15:11:16

We can also skip their ie8 portion

micha15:11:41

do we not support ie8 anymore?

micha15:11:56

or we just do settimeout for ie8?

flyboarder15:11:02

I think we should move all the ie8 stuff to its own namespace otherwise we will have compatibility patches in core

flyboarder15:11:22

But a fallback to set timeout is probably best

micha15:11:33

yeah this code you linked to looks fine

micha15:11:41

it falls back to settimeout and stuff

flyboarder15:11:00

I'm sure it can be cleaned up as cljs in a smaller fashion

micha15:11:42

i think for when-dom we might actually want a timeout though

micha15:11:46

since we will want to poll

flyboarder16:11:17

Would the event emitting not work?

micha16:11:49

we don't want to prevent other threads from running though

micha16:11:25

like process.nextTick in node can be used to make an infinite loop that monopolizes the cpu forever

micha16:11:46

so if you're waiting for other code to do stuff you don't want to use that

micha16:11:03

at least you don't want it to call nextTick itself

micha16:11:57

ok if there are no objections i will merge boot-hoplon PR in hoplon

micha16:11:09

actually i do some stuff first

flyboarder16:11:31

@micha: on an unrelated note, did you have a chance to look at the presentation I linked to? I'm just wondering if you see anything that's wrong 😜

micha16:11:46

ah one sec, will look

micha16:11:29

ok i shouldhave something to show in a little bit

micha16:11:35

i'll make a PR

flyboarder17:11:46

@micha: that is an interesting piece of machinery in #156

micha17:11:13

this presentation is prety slick @flyboarder

micha17:11:04

the middleware concept is difficult to explain in a slide i think

flyboarder17:11:08

maybe I should show the cascading portion in another one

micha17:11:29

"returns next-handler + fileset" could be confusing

micha17:11:50

but then again the whole concept is kind of confusing until you do it

flyboarder17:11:14

yeah perhaps a code demo there, show the whole (apply next-handler fileset)

flyboarder17:11:40

as the result

micha17:11:31

perhaps like "returns a fileset, can call the next handler" or something?

micha17:11:06

the pipeline is a sequence of steps

micha17:11:15

each step transforms a fileset

micha17:11:27

each step can decide whether to call the next step or not

flyboarder17:11:31

ok, since the timing can be controlled and such

micha17:11:56

the actual middleware and whatnot is implementation detail to make it work in lisp

micha17:11:16

excellent, yes

flyboarder17:11:28

actually that might be bad saying it returns middleware and returns a fileset

micha17:11:54

yeah the task itself returns middleware, and middleware returns a handler, and the handler returns a fileset

micha17:11:00

head explode

micha17:11:46

awesome yes

mynomoto17:11:02

@flyboarder Do you have a code example with that slide? It may help a lot to understand what's going on if people can read code. I think I can only understand the slide because I'm already familiar with what that does.

flyboarder17:11:38

yep, im presenting a demo of a freecodecamp react app that I converted to hoplon, thats a previous presentation

mynomoto17:11:38

I mean of one boot task for the concept of middleware. But looking at your presentation it's a part too small to be able to give lots of details.

flyboarder17:11:06

yeah the boot part is mostly an overview of whats going on, then it goes into hoplon with a bit more detail about the inner workings of that, followed by a visual app

flyboarder17:11:01

the idea is to express that everything is usable on it's own, but cover the concepts which make it awesome to use together

mynomoto17:11:23

Yeah, there is only so much one can explain with limited time. 😉 It's a really nice presentation. I always get a bit dizzy looking at prezi stuff lol.

flyboarder18:11:26

yeah plus i dont want to spend too much time explaining and not demo

micha19:11:11

@jumblerg issues related to deps.cljs resolved in my PR (#155)

jumblerg19:11:34

@micha: awesome, many thanks!

micha19:11:39

deps.cljs does appear to work in the project as well as in jars

micha19:11:43

so that's good

jumblerg19:11:58

in that case, maybe i'll throw in a cigar.

micha19:11:12

cubans are legal now

jumblerg19:11:26

and quite delicious with a congnac

jumblerg19:11:24

you've been upgraded

micha19:11:00

i ended up putting in a special case

micha19:11:16

cause otherwise you do want to see exceptions if a namespace is malformed

jumblerg19:11:21

eh, nvm, back to beer then in that case. 😄

micha19:11:42

so tehre is a bogus-cljs-files set in there now

jumblerg19:11:08

i think that makes sense, for the next person who decides to invent a new kind of cljs file.

jumblerg19:11:06

it does seem that the boot-cljs task could take the initiative to clean this up, and encourage the user of a deps.edn file or something with a depreciation notice when someone tries to ram a deps.cljs file down the pipe.

jumblerg19:11:38

we don't have to break ppls shit, but i'm all for annoying them.

micha19:11:07

don't worry i'm sure they're annoyed enough already

jumblerg19:11:24

maybe toss a few alerts at them for good measure, i see my old friend boot speak was generalized to do this.

micha20:11:46

what would the multimethod look like?

micha20:11:52

i mean like what does it dispatch on?

flyboarder20:11:56

Which would let us replace the different ctors for SVG and factor out ie8 patches from core to its own ns

flyboarder20:11:37

I also see this opening up to other frameworks creating hl compatible elements

flyboarder20:11:16

Like jquery element for example

flyboarder20:11:19

Then it's always a jquery element for the jquery provider instead of wrapping it each time

flyboarder21:11:16

I think it would dispatch on the element itself when it's constructed

micha21:11:39

hm i dunno

flyboarder21:11:35

i dont know if that would work tho

fiddlerwoaroof22:11:03

Hello, I have a couple confusions about using hoplon/castra with multiple routes. I'm using the template from here https://github.com/tailrecursion/hoplon-castra-template and I want to have a / route and a /comments/:id route. So, I just copied the / route and changed the route specification and the file name. However, when I navigate to /comments/0 or something, it doesn't seem to be able to find the new template.

fiddlerwoaroof22:11:17

Hmm, I think I figured it out, I had to put the complete path relative to the site root inside (page)

fiddlerwoaroof22:11:56

Now, I have to figure out how to pass data from defroutes into the template.