back to indexHow HTMX is changing the web, with Carson Gross
00:00:00.640 |
Hi there, this is Jeremy Howard from Answer AI. And I am here 00:00:05.960 |
with Carson from HTMX. And Carson's probably not going to 00:00:13.240 |
like this if I introduce him in two glowing terms, because he's 00:00:16.440 |
a very humble man, but I can't help it. There's just a few 00:00:18.880 |
people in the world, very few people in the world who I 00:00:22.080 |
assign the epithet genius to. And Carson is one of them. He's 00:00:28.440 |
one of the very few. He looks and sounds like a little league 00:00:34.480 |
baseball coach. And that's because he is, I'm sure he's a 00:00:36.920 |
very good one as well. But that is not the genius that I wanted 00:00:39.680 |
to talk about today. I wanted to talk about HTMX. So Carson, 00:00:43.720 |
Thank you. I appreciate that. You know, I appreciate you 00:00:48.040 |
saying that. But no, I can't agree with that. I do. I do look 00:00:54.960 |
Are you a good one? Do your little league say that you do a 00:00:58.400 |
I you know, baseball makes people crazy. So I have a lot of 00:01:04.120 |
people that like me and then a couple of people that don't. And 00:01:08.520 |
I love it. And I feel like I know about your your other life. 00:01:12.640 |
Yeah, it is definitely pretty funny. Sometimes I'll just be 00:01:17.480 |
like, man, this is very different than my online. 00:01:22.800 |
well, something we both share in common is that we live a long 00:01:26.200 |
way away from everybody else doing what we're doing. And we 00:01:29.640 |
do things in a really different way to everybody else. So that's 00:01:33.160 |
where I wanted to start, you know, HTMX is like, the most 00:01:38.840 |
misunderstood piece of technology I've come across in 00:01:41.520 |
my God, how long I've been coding for 40 years of coding. 00:01:45.280 |
So I wanted to help people understand it. And sure, I think 00:01:51.000 |
the best way for people to understand it would be to read 00:01:53.720 |
your damn book. So I'm just going to share like that on the 00:01:56.720 |
screen. But that was short for a pretty short interview. So 00:02:00.400 |
here's your damn book. I'm not just you, you and Adam and 00:02:05.520 |
Dennis. hypermedia.systems called a main name. And the 00:02:09.560 |
whole thing's free for God's sake. What are you trying to do? 00:02:12.720 |
You're like, yeah, you're not gonna actually this right now. 00:02:18.600 |
Books are not a good way to make much money in general. I know. 00:02:22.800 |
Yeah, you know. And even worse, I uploaded the EPUB lib gen. So 00:02:32.240 |
if they don't want to pirate your book, they can they want to 00:02:35.280 |
pirate, they can do so with my blessing. No, but they're not 00:02:38.520 |
going to do that now. Because part of getting stuff off lib 00:02:41.080 |
gen is like, you know, sticking it to the man. And if you're 00:02:43.760 |
like uploading it there yourself, it's like, why even 00:02:46.480 |
bother? Yeah, exactly. Well, you know, I figured someone was 00:02:49.920 |
gonna do it anyway. So might as well be made. So yeah, but yeah, 00:02:54.880 |
there's a hardcover that's, if you really if you want to spend 00:02:57.640 |
some money on a physical artifact, the hardcover, it's 00:02:59.720 |
pricey. And my understanding is it's hard to get in Australia. 00:03:03.440 |
But it, it has a really cool cover that was done by us 00:03:08.720 |
graphics. Really, really happy with that. And then we just 00:03:12.360 |
released the soft cover to Yes, which on Lulu with a beautiful 00:03:17.480 |
song. And that's, yeah, that's got a pixel art cover that we're 00:03:22.720 |
super happy with. It's we there was a, a pixel artist on fiber 00:03:28.840 |
named ash. And he did an unbelievable job with it. So 00:03:32.520 |
super happy with that. Yeah, I love it. And one of the few 00:03:37.200 |
pieces of software were released recently that was initially 00:03:43.320 |
Yeah. Yeah, we did that for a couple weeks. We had a we have 00:03:48.080 |
floppy disks. I don't think they're available on the store 00:03:51.120 |
anymore. But you can buy them for a little bit. So yeah, we 00:03:57.360 |
An interesting thing about your book is that actually the entire 00:04:03.120 |
first part, not just the first chapter, but the entire first 00:04:05.800 |
part isn't about your thing at all. It's about Yeah. It's about 00:04:10.520 |
HTML and HTTP, I guess. So I wanted to start there because 00:04:14.920 |
some of the like, so I've been coding for a while. And I hadn't 00:04:21.240 |
quite noticed until recently that there's a whole generation 00:04:25.600 |
of people who are competent full time coders that are not 00:04:33.240 |
familiar with any of the basic concepts of the web because they 00:04:35.920 |
program at a totally different level of abstraction, which is 00:04:38.320 |
like, you know, React and JSX and all that. So I thought like 00:04:42.440 |
it might be fun to go back to a an existing web 1.0 web page 00:04:48.920 |
is Richard Storman's personal current website. Oh, yeah. Could 00:04:53.240 |
you like just teach us a little bit about what's going on here? 00:04:56.200 |
What are the underlying things? What's the buttons like? What 00:04:59.520 |
are the what are the affordances provided by the web that 00:05:05.400 |
Yeah, yeah. So this is very much an old school, very, very old 00:05:09.480 |
school web page, you know, and there's always been this tension 00:05:13.240 |
on the web, like, is it a document? Is it? Is the web 00:05:16.640 |
about documents? Or is it about something more than documents? 00:05:20.000 |
And how and if so, how much more. And so here, you can see 00:05:24.960 |
sort of a standard web 1.0 style web page with a bunch of links 00:05:29.400 |
or anchor tags that link to various things and let you click 00:05:33.040 |
on them. So I just click here. So inspect. So here is an anchor 00:05:42.200 |
Yeah. And so the important, the important thing here is the href 00:05:47.240 |
attribute. So that href attribute, which specifies 00:05:51.640 |
another URL, that when you click on the on the text that's 00:05:56.680 |
included inside that tag, the browser, which is a hypermedia 00:06:00.800 |
client is going to issue an HTTP GET. And it's going to take 00:06:07.800 |
whatever the hypermedia response is to that and then load it into 00:06:11.520 |
the browser. How it's loaded can be affected by a bunch of 00:06:15.640 |
different things, affordances. So there could be a response 00:06:20.120 |
header that tells it to do something specific, maybe do a 00:06:24.120 |
Well, let's take a look because you know, we can something I 00:06:26.400 |
definitely encourage people to do is to kind of watch their 00:06:30.040 |
browser, doing that, which you can by popping up here. And if I 00:06:38.800 |
Yeah, you go ahead and Yep, exactly. So you can see this is 00:06:44.360 |
the response that came back from that GET request. And so you can 00:06:47.960 |
see the request URL that was made to and just a bunch of 00:06:52.520 |
these are these are headers, these are basically named value 00:06:54.960 |
pairs. And there are some that are sent as part of the request. 00:06:57.920 |
And then there are some that come back as part of the 00:06:59.720 |
response as well. And that's, that's all tied up. 00:07:03.320 |
And that's actually the body of the response. But I guess we 00:07:08.120 |
Yeah, yeah, these are the response headers. So you know, 00:07:11.400 |
there's an E tag in there. And that's what they actually all 00:07:13.800 |
this. Yeah, that's what it looks like when it writes raw. Yeah. 00:07:17.680 |
So HTTP. So the way you're looking at here is sort of a 00:07:20.600 |
partial representation of HTTP, which is the underlying transfer 00:07:25.000 |
protocol, the hypertext transfer protocol, it's what HTTP stands 00:07:28.360 |
for. That's the that's the core network format for the web. And 00:07:34.280 |
that's how web browsers in general make requests, even when 00:07:37.920 |
basically, so I was just gonna say, so we basically have two 00:07:41.440 |
affordances here, right? One affordance is like, underlined 00:07:45.280 |
things I can click on just the links or anchors. And the other 00:07:49.480 |
is a form I can fill out with a button. And one of the 00:07:52.480 |
interesting things you point out in your book is, in terms of 00:07:56.320 |
like, HTML itself, that's it, the entire set of affordances 00:08:02.160 |
provided to interact with a web page. Are those two things? 00:08:06.040 |
Yeah, yeah, affordance is a it's such a broad word that I think 00:08:10.200 |
people could could argue about that. But those are the two 00:08:12.680 |
primary interactive affordances. Or another term I would use for 00:08:17.520 |
those is they're the two main hypermedia controls, 00:08:21.160 |
interactive hypermedia controls in HTML. So, so taking a step 00:08:27.000 |
back again, when you've got so how does the web work? Well, 00:08:30.440 |
you've got documents, let's just start with documents. And this 00:08:33.880 |
is a, this is an HTML document stored somewhere. And when that 00:08:38.440 |
document comes down, embedded within the presentation 00:08:42.320 |
information, are these interactive elements, the 00:08:51.200 |
a tag and a tags and forms. And you can also argue that like an 00:08:54.880 |
image is a hypermedia control, because it's going to drive 00:08:59.320 |
another request that downloads an image element that's then 00:09:02.520 |
inserted. And so there's a you can get into the weeds and that 00:09:05.880 |
interactive to use your terminology. Yeah, it's not it's 00:09:09.040 |
not something that the user selects, you know, when Fielding 00:09:11.760 |
talks about what makes the web special, he, he talks about 00:09:17.160 |
Fielding. Sorry, Roy Fielding, Roy Fielding is the guy who 00:09:21.560 |
wrote the famous or somewhat famous, it was much more famous, 00:09:26.000 |
I guess, in the past, dissertation on the web 00:09:29.160 |
architecture. And that's what gave us the term rest. Yep. So 00:09:33.320 |
that dissertation, he and I'm going to be honest with you, the 00:09:36.960 |
dissertation is a little hard to read. But, but one of these 00:09:41.560 |
core ideas with the web has always been the embedding of 00:09:44.880 |
interactive information directly in the document in the 00:09:49.000 |
presentation information. And so you have this mixing of concerns 00:09:52.880 |
between the presentation as well as the, the network stuff you 00:09:57.000 |
can do with the presentation now in a document like, like 00:10:00.200 |
fieldings, like, you know, it's hard for a lot of people. It's 00:10:04.120 |
like, these are just links, they're just links to other 00:10:06.720 |
documents. Yeah, that's true. But then that form starts to get 00:10:11.120 |
at what really, you know, I think HTML two added forms, and 00:10:17.000 |
when forms were added as a hypermedia control, that really 00:10:20.640 |
is. Yeah. And so you can see there, it's action rather than 00:10:25.120 |
href. I don't know if that's good or bad. There's a lot of 00:10:28.040 |
inconsistencies in HTML. It's a very, it was grown very 00:10:31.160 |
organically. And so as the text, but yeah. Yeah. And so forms are 00:10:37.160 |
much more complicated, because they, you know, the the form of 00:10:41.560 |
the request that's made depends on the state of the inputs 00:10:44.040 |
inside the form and all this other stuff. You can also issue 00:10:48.000 |
posts. So you see there, it says method equals post. So it's 00:10:51.600 |
going to make a, it's going to make an HTTP POST request rather 00:10:54.880 |
than a GET request, which is what we saw for the links. And 00:10:58.760 |
so the forms when forms were added in HTML two, I think 00:11:02.960 |
that's when the web went from really sort of a traditional 00:11:07.680 |
hypermedia system, like the old school documents, like the way 00:11:12.600 |
the web kind of grew up was it was, it was more of a document 00:11:17.080 |
oriented system. And when this form came along, it was sort of 00:11:21.240 |
like a spark that made it possible now to build app web, 00:11:25.080 |
what we today call web applications. And I don't know 00:11:29.360 |
how much thought went into that, like how revolutionary that 00:11:33.200 |
I mean, I remember at the time it happened, it was, it was 00:11:37.760 |
exciting, because like, going behind the scenes as to what 00:11:41.160 |
happens, like when a POST request happens is the contents 00:11:44.920 |
of that form gets sent to your server. And then at that point, 00:11:50.360 |
you can run any program you like, do anything you like, and 00:11:54.560 |
send back a response. And so I remember it was like an exciting 00:11:58.040 |
time for the internet, because suddenly, you could compute on 00:12:05.440 |
Yeah, they really converted the web from a document, you know, a 00:12:09.960 |
document based, like kind of like gopher, and I go and go for 00:12:12.960 |
wasn't a great example. But there were a bunch of these sort 00:12:15.920 |
of document oriented hypermedia systems that were around even, 00:12:20.440 |
you know, low, just purely local ones. But when once you got 00:12:24.960 |
forms that now you have a distributed application 00:12:27.600 |
architecture, and now and not necessarily a good one in many 00:12:31.480 |
ways, but but had some real big advantages to it. The primary 00:12:36.240 |
one being that there was this sort of universal client, the 00:12:39.360 |
browser that was available everywhere. And so to give your 00:12:43.320 |
application to people, you just had to give them a URL. And that 00:12:46.600 |
was it. And that's, you know, that's one of the that's one of 00:12:49.120 |
the reasons why the web, despite all the problems with it, has 00:12:54.080 |
Yeah, well, let's talk about those, like, limits or 00:12:57.520 |
constraints or whatever. So I will, you identified them, and 00:13:03.760 |
you list them in the book very eloquently. So I'm just going to 00:13:08.200 |
go ahead and tell you what you told me. So, so some key 00:13:12.320 |
limitations here of these interactive affordances. Okay, 00:13:16.960 |
number one, there are only two types of things that can 00:13:21.960 |
interactively generate a request. One is the anchor tag. 00:13:24.880 |
The second is the form. Number two, anchor tags can only call 00:13:31.520 |
get request. Forms can only call a get or a post request. So 00:13:39.120 |
they're pretty limited in what they can do. So they're limited 00:13:42.880 |
in terms of the elements, then they're limited in terms of like 00:13:45.160 |
what, what interaction can cause a request. And so, in this case, 00:13:51.160 |
only clicking a link or clicking a button can cause a request. So 00:13:55.200 |
things like scrolling, you know, moving a slider, scrolling 00:13:58.360 |
something into view, typing on the keyboard. And then I think 00:14:03.400 |
perhaps the one I found most interesting, because it just 00:14:06.840 |
seemed such a such an obvious implicit thing to me, I'd never 00:14:11.840 |
realized it was a constraint, is that when you click on a button, 00:14:15.520 |
you know, yeah, or, or a link, the information that comes back 00:14:22.360 |
from the server, there's only one thing that the browser can 00:14:24.560 |
do with it, which is to replace the entire web page. Although in 00:14:31.000 |
this case, it looks like maybe Richard Stallman's site search 00:14:35.720 |
button actually doesn't work. But oh, yeah, here it comes 00:14:39.200 |
So what you what you just saw there is one of the problems 00:14:42.600 |
with the web, right? There was no visual before, like the 00:14:45.760 |
browsers have actually gotten much worse at this, telling you 00:14:51.040 |
Yeah, so the result came back from the browser. And the result 00:14:56.560 |
of that, in fact, I guess we could do the same thing we did 00:14:59.240 |
before, right, which is we can go into our network tab. And if 00:15:04.880 |
I refresh this, it should be an option to refresh the post 00:15:07.760 |
request. And we should be able to see it here it is. So there's 00:15:15.720 |
the post request. And the request headers include, you 00:15:23.720 |
know, various things. But I guess the interesting one is the 00:15:26.240 |
payload, which is the form data. The response thing comes back, 00:15:30.760 |
which is HTML. That's the body of the response. And so the 00:15:35.520 |
server, yeah, tell us about what happened then really on the 00:15:42.000 |
Yeah. So the server received that post request HTTP is a very 00:15:47.440 |
simple network format. If you've done if you've ever studied any 00:15:51.360 |
sort of networking at all. It's very simple. And so the those 00:15:56.200 |
name value pairs were encoded in the body that was sent up. And 00:16:00.240 |
so one of the one of those values was the search term. And 00:16:03.040 |
then on the back end, there's some program that executes and 00:16:06.680 |
figures out which pages have that term that you've passed up 00:16:10.360 |
on it, and then constructs URLs to link to them and then 00:16:13.440 |
presents that beautiful search result that we saw in the in the 00:16:18.200 |
screen. And it's sort of a full page thing. And there. I noticed 00:16:23.320 |
that they did not use the very common, first of all, they used 00:16:27.920 |
a post rather than a get. And arguably, that's not correct. 00:16:31.640 |
Because for a search, you're not you're not asking it to mutate 00:16:37.000 |
anything. And so you probably would using a get would actually 00:16:42.960 |
make like the input values would end up in the URL, and then you 00:16:48.520 |
would have a copy and pastable search, URL and so forth. And so 00:16:53.080 |
I noticed that they also didn't do a redirect. So when you hit 00:16:56.840 |
refresh, you saw another post. Yeah. And depending on exactly 00:17:00.600 |
what the post does, that can be a bad thing, right? Like it buys 00:17:03.800 |
a ticket, you know, it could buy another ticket. So it's, you 00:17:06.960 |
know, just this is sort of like the old school grunky web that 00:17:10.280 |
Okay, so yeah, so this is the thing that blew my mind, Carson 00:17:14.320 |
is that you identified these four specific constraints of 00:17:19.040 |
what a web browser can do. And those constraints are determined 00:17:24.440 |
by the specs themselves, right? And somehow, and we'll come back 00:17:29.880 |
to how later, I don't know how, but somehow, you realized, or 00:17:34.520 |
asked the question, what happens if we remove these four 00:17:37.000 |
constraints? You realize that we can using JavaScript, and then 00:17:43.680 |
with the right script, it's almost like a polyfill for the 00:17:46.640 |
browser. It's almost like saying, let's pretend the 00:17:49.600 |
browser didn't have those constraints. And like, so just 00:17:52.320 |
adding a single script tag, it's like, okay, now the browser 00:17:54.680 |
doesn't have those constraints. And so that is HTMX, right? 00:18:00.080 |
HTMX is like the polyfill, where we say, let's pretend the 00:18:05.040 |
browser doesn't have those constraints. And so you have 00:18:09.400 |
then a bunch of examples here, right, such as click to load. 00:18:16.880 |
And it is still, let's find it here. Okay, so you've got a 00:18:25.280 |
table, right? And in this table, when I load more agents, it 00:18:33.000 |
loads more agents that it did not refresh the screen. And, you 00:18:39.520 |
know, the actual button here, which is in the last row of the 00:18:43.440 |
table, we've got a new one now, but here we are in the last row 00:18:47.960 |
Yeah, it'll call span, good old center tag and call span three. 00:18:53.320 |
Here it is. Now you're not, you know, this button, it's, you 00:18:59.440 |
know, it's not in a form. It doesn't do a submit. It's like, 00:19:05.400 |
but it's all still just HTML. And on these examples, I love 00:19:10.520 |
that I can actually click show. And it actually shows me the 00:19:17.440 |
HTTP request that happened, right? The HTTP response that 00:19:23.000 |
happened. And so we've got something that looks, in a lot 00:19:28.680 |
of ways, a lot like Richard Stallman's website. But it 00:19:34.000 |
behaves like a modern, you know, SPA style app. So I guess like, 00:19:42.360 |
I was thinking like, well, maybe we should, like, how do you 00:19:46.040 |
think this is best to explain? But like, how is it like, what 00:19:49.560 |
are the constraints that we've kind of removed here? And how 00:19:52.560 |
is removing those constraints, in this case, allowing this 00:20:00.280 |
Yeah. And actually, maybe before we do, I'm going to switch over 00:20:03.680 |
to a version where we get to see the server. And of course, I 00:20:07.440 |
then get to show off FastHTML, which is like an extremely 00:20:11.600 |
simple wrapper, largely around the genius of Carson's work, and 00:20:15.520 |
also the genius of something called ASGI. And the details 00:20:21.240 |
don't matter. But here, this is basically says, this is a route. 00:20:24.200 |
So when you go to slash, call get, it's going to return a 00:20:28.920 |
table with a table header with name, email, and ID, a table 00:20:34.280 |
body with five copies of making a row, which has an agent and a 00:20:39.720 |
null.org and an ID. And at the bottom, it's going to have that 00:20:45.160 |
button that we saw. And so if we run this, I think it's kind of 00:20:52.800 |
fun looking at it on the server, because we can now see the 00:20:54.960 |
server running. So if I go there, you can see something 00:20:59.400 |
looking pretty similar, and I just do one at a time, load 00:21:01.280 |
another agent, click. Sure. Click. Yep. And yeah, it's 00:21:07.080 |
it's actually calling when I click this button. It's actually 00:21:14.920 |
calling more. And more is just returning, you know, another row 00:21:24.760 |
plus, yeah, add row. And if we look at the network tab, when we 00:21:29.360 |
click load another agent, we can see more. And it looks very 00:21:36.360 |
similar. It's a get request, it's to a URL, it's got 00:21:39.200 |
headers. But the response is pretty weird looking. So yeah, 00:21:47.680 |
where do you want to start? How do we how do we learn about how 00:21:50.560 |
Well, let's go look at the let's go look at the button. Look 00:21:54.720 |
at it. I think you just inspect it. And we can go through each 00:21:57.640 |
of the attributes on it. So basically, HTML consists of 00:22:01.320 |
attributes, they put in your HTML, because that's how HTML 00:22:04.800 |
has worked, you know, you use attributes to specify network 00:22:08.880 |
interaction behavior. And here, there's three attributes. So 00:22:15.400 |
So they've all got an HX dash on the front. So does that mean 00:22:19.120 |
Yeah, all of the stuff you're adding is always going to be 00:22:21.840 |
have this pretty Yeah, yeah, we use the HX prefix to namespace 00:22:26.760 |
it effectively. You can also some people prefer using data 00:22:30.320 |
dash HX because that's more that's in spec. But I've been 00:22:34.360 |
told by the browser people that this will never break a browser. 00:22:37.560 |
So so I like the shorter version of it. But what HX HX get says 00:22:43.240 |
it's effectively the same as a trough. It's saying, here's a 00:22:50.200 |
URL that I want you to interact with, like, here's a here's a 00:22:53.120 |
hypermedia endpoint that I want you to interact with. And that 00:22:56.040 |
endpoint is then specified as slash more, which you've set up 00:23:00.400 |
In fact, let's just take a look at that. So here's my more. So 00:23:04.720 |
when Yeah, so when somebody clicks this button, it's going 00:23:08.440 |
to send a request to and a get request. And now I get and this 00:23:15.640 |
is the thing that I find a lot of people don't understand 00:23:17.720 |
people like are you using PyScript or wasm? Or like, how 00:23:21.080 |
are you getting Python in the browser? And it's like, we're 00:23:27.360 |
Yep, yep. Yeah, everything's it's it's much it's much more 00:23:31.880 |
like the traditional web application where your HTML I 00:23:35.200 |
don't want to say it's dumb, necessarily. But it's it's just 00:23:38.040 |
everything specified in terms of what I would call hypermedia 00:23:41.640 |
interactions, rather than in terms of, you know, sort of 00:23:45.080 |
programmatic interactions, where you're consuming an API and 00:23:48.200 |
building stuff sort of locally in the browser. So that first 00:23:52.240 |
attribute hx get is specifying sort of where to send the 00:23:54.960 |
request to and how to send it. So you can do hx post if you 00:23:57.840 |
wanted it to be a post for some reason, or whatever. But hx get 00:24:01.280 |
makes sense here. And then the next attribute is hx target. And 00:24:05.760 |
this is really I think, this gets at that last element of 00:24:10.400 |
I think, yeah, probably. Yeah, I agree. I think it's the most 00:24:14.320 |
important one. What this lets you do is say, okay, you're 00:24:18.040 |
going to get back some HTML from this slash more URL from this 00:24:22.040 |
request, this get request you make to that URL, where do you 00:24:25.680 |
So normally, it would just be like, just replace the whole 00:24:30.000 |
page. And I call that a full the full page refresh. That's the 00:24:33.560 |
normal. Exactly. So that and that's what links and forms do 00:24:36.840 |
by default in HTML by default. And so this allows you to say, 00:24:41.280 |
okay, when that HTML comes back, I want you to put it here. I 00:24:44.640 |
want to put it here it is here is hash replace me. So you're 00:24:47.800 |
using CSS, select a syntax there. Yeah, exactly. So we 00:24:51.440 |
decided to reuse the CSS, like just it's universal people 00:24:54.400 |
understand it. Yeah, we do. And so that tells that tells htmx 00:24:59.640 |
where to put the content that comes back from the server. And 00:25:02.840 |
then the the next attribute, which is hx swap, tells htmx 00:25:07.880 |
how to place it. So in this case, we want to replace the 00:25:12.600 |
entire table row with two new table rows. Right. And so that 00:25:16.680 |
that so there were two new table, actually, maybe we should 00:25:19.280 |
just look at that network tab again to see the two table 00:25:22.600 |
rows. Yep. Okay, so here's the response we get back, there's 00:25:28.080 |
the table row for the new agent. And there's just a copy of 00:25:31.880 |
right, basically the one we just saw. Yeah, same button, right. 00:25:35.200 |
And it's gonna replace my name, same element, and so forth. 00:25:38.880 |
Yep. And so, you know what, with this, this new HTML is now 00:25:44.760 |
going to replace the entire existing table row. And so 00:25:49.000 |
that's what because of that, and that's going to replace the 00:25:53.560 |
entire thing. Now, there's there are other options. So for 00:25:56.120 |
example, you could say, let's use one, let's use one now, 00:25:58.720 |
because actually, I think we could like, simplify this a 00:26:01.760 |
little, right? If we took the table, and if we gave the table 00:26:06.480 |
an ID, okay, so we give that there. And then like, we could 00:26:11.480 |
just like, say, Alright, let's like, can we kind of like do 00:26:16.280 |
something like this, where we just return one row, maybe like 00:26:24.240 |
I would change that to a, I would change. Let's see, how 00:26:28.840 |
would I do this, I would, I would make add row no longer in 00:26:35.440 |
Yeah, exactly. So let's just grab the button. 00:26:39.200 |
Grab that button and move it out of the table. 00:26:42.720 |
And let's just do exactly. Okay, and so we don't need add row 00:26:48.080 |
anymore. And we can take the ID off of it. Okay, that makes 00:26:54.200 |
sense. Body, I kind of like these little lines that VS code 00:27:00.640 |
can add. So you can kind of see this is where the T body is. 00:27:07.040 |
T body. Okay, well, in that case, I'll do that, too. 00:27:09.200 |
Because that's where that's where we're gonna, that's where 00:27:13.400 |
Ah, okay. All right, we can do that for sure. So okay. We've 00:27:22.400 |
now got T body, we've got these rows, add row, ID equals agents. 00:27:29.920 |
Okay, that looks pretty good to me. Okay, so now we don't have 00:27:40.880 |
Please, absolutely. Yeah. The interesting thing about fast 00:27:46.800 |
HTML is because it's a direct mapping, like one to one 00:27:49.440 |
mapping. So in fast HTML, the it kind of there's a almost unique 00:27:56.040 |
thing about Python, which is in Python, you can have positional 00:27:59.320 |
and named parameters. And here you can see this doesn't have a 00:28:02.680 |
name. And so you can have as many of these as you like, and 00:28:05.480 |
they become positional parameters. So they're children. 00:28:07.640 |
And then you can have as many of these as you like. And as you 00:28:10.560 |
can see, these are named keyword arguments, and they become 00:28:14.480 |
attributes. So it's kind of like the mapping between HTML and 00:28:18.760 |
Python function syntax is almost uniquely perfect. 00:28:25.720 |
Okay, so now what we want to do is we want to change HX target 00:28:29.800 |
to be agents, because we're going to target that T body with 00:28:33.600 |
the response. And then, rather than outer HTML, we're going to 00:28:41.480 |
I gotta say the reference for HTMX is great. I just type 00:28:45.480 |
HTMX reference. And it's really nice. And here they all are core 00:28:52.000 |
Yeah. So we want to we want to for if you look at HX swap, we 00:28:56.080 |
want before and that's the terminology that the DOM API 00:29:01.320 |
uses to insert something before it because we want to insert 00:29:04.440 |
this new row before the end of the T body, not after the T body 00:29:08.880 |
but like, as its last child effectively. So before and as 00:29:15.120 |
So I think that should work. And now what's going to happen is 00:29:29.200 |
I'm always a little shocked when my stuff works. 00:29:31.200 |
So now we've just got one thing coming back. So I think this is 00:29:34.880 |
a great example of like, what happened here. So maybe just 00:29:46.200 |
Well, so we moved it, we moved the button out of what we were 00:29:50.000 |
replacing, like previously, we were replacing the button with a 00:29:54.440 |
new version of itself. And that makes sense when you're doing 00:29:56.880 |
things like for example, loading another page, because you want 00:29:59.800 |
to update the you want to update the URL with like the next page. 00:30:04.400 |
So when you load the second page, you want the button to 00:30:06.760 |
then load the third page. And so you want to have a chance to 00:30:09.480 |
update the URL. So it makes a lot of sense in sort of a click 00:30:13.080 |
to load more scenario. But here, when we're just like adding new 00:30:16.680 |
rows to to a data structure, it doesn't make as much sense, you 00:30:21.480 |
kind of want it, you're hitting the same URL over and over 00:30:24.120 |
again. So in that case, why not move the button outside of the 00:30:27.920 |
target area. And this is the same, you're just going to 00:30:31.080 |
HX get is the same. The target is a little different. We target 00:30:36.680 |
the T body because that's where we want to put the new content. 00:30:39.360 |
It's not we're not replacing a parent. Yeah. And and then that 00:30:43.840 |
beforehand says, okay, when you get a response, I want you to 00:30:46.920 |
stick it before the end of that T body. So that's the that's the 00:30:50.560 |
DOM way of saying like at the end of the children. 00:30:53.080 |
So I think something that I didn't understand at first is 00:31:01.280 |
how extremely small the surface area of what HTMX touches is, 00:31:06.680 |
you know, and it's basically the core attributes. And there's 00:31:09.320 |
also, I just having a look. Yeah, there's a few more here. 00:31:14.560 |
Well, some of them are really obvious, like, oh, this is just 00:31:17.040 |
the same thing, but a different verb. Yeah. Almost none of those 00:31:20.360 |
I've used. So I can say confidently, this is basically 00:31:23.080 |
the surface area that normal people like me need. Yeah. And 00:31:27.600 |
then like you kind of said, the, even the contents of them are 00:31:33.120 |
like, copied and pasted, like to the name, the semantics, 00:31:38.240 |
everything to like how the DOM works. So it's like, right, kind 00:31:41.840 |
of like very direct mapping. And even then you've also like got 00:31:45.120 |
two versions of swap or B or not two versions of select or B or 00:31:48.760 |
not. So there's like, it's a very small little set of stuff 00:31:54.160 |
to know. And when you know the basics of how the browser and 00:32:00.080 |
the web works, it's super natural. That's my experience 00:32:05.200 |
It well, I think it rhymes really well with the web, like 00:32:10.080 |
it goes with the grain of the hypermedia infrastructure. And 00:32:13.320 |
so if you're familiar with and comfortable with that, which as 00:32:15.960 |
you pointed out, a lot of younger people aren't a lot of 00:32:18.680 |
younger web developers, I should say, aren't, then I think you 00:32:22.760 |
come across as being very foreign, you know, so I think 00:32:26.040 |
that's why you see some of the misunderstandings around HTMX, 00:32:29.480 |
just like, Oh, this is terrible. Like, why would you do this? 00:32:32.200 |
Everything has to be a network request. Well, not everything. 00:32:34.720 |
Yeah. So I think it's not, it's also like, surprisingly fast, 00:32:42.240 |
because the kind of full page refresh, I think, often it feels 00:32:47.160 |
slow, and it is slow, it feels slow, because you see the whole 00:32:50.800 |
thing flashing and changing. It is slow, because it requires 00:32:53.880 |
like the browser reparsing the CSS and rehandling any 00:32:57.000 |
JavaScript and relaying everything out. But when you 00:33:00.800 |
just insert, so this is what I noticed, you know, when I was 00:33:05.480 |
showing the CEO of Vercel this, you know, and he was trying it 00:33:10.240 |
out. And particularly because like, Vercel has this kind of 00:33:13.320 |
edge caching thing working. And he was just like typing and hit 00:33:16.840 |
enter. It's like, boom, boom, boom. He's like, his mind was 00:33:19.680 |
blown. He didn't, you know, he was like, I didn't know this is 00:33:22.160 |
what the hypermedia application can feel like. 00:33:25.680 |
Yeah, it can feel really good. And the browsers are very good 00:33:29.600 |
at displaying hypermedia. Some would argue that's what they're 00:33:32.520 |
designed to do. And so, you know, I think, yeah, the, you 00:33:38.120 |
know, obviously parsing, like little bits of HTML, that's 00:33:41.760 |
something that browsers incredibly fast at and inserting 00:33:44.280 |
it into the DOM is also very fast. Yeah. And so if you're not 00:33:47.800 |
trying to do a bunch of like reconciliation logic, like a lot 00:33:51.200 |
of SPA libraries do, you can be very fast, you don't, you are, 00:33:55.440 |
you know, to an extent, you're more dependent on network, like 00:33:59.400 |
I guess you're in Australia. So I have the worst, because I'm 00:34:02.640 |
using American servers, and I'm in Australia. And so the speed 00:34:07.080 |
of light basically means our ping is 70 milliseconds plus. 00:34:10.960 |
Right? I gotta say, it's not bothering me. Can we can we pick 00:34:16.080 |
another one maybe? So we've looked at like, okay, the what's 00:34:18.600 |
maybe the most important, which is, you can arbitrarily update 00:34:24.320 |
the DOM of the existing page just by passing back an HTTP 00:34:28.720 |
response. Maybe another one to talk about then would be like we 00:34:31.880 |
can respond to events other than clicking something. Is there a 00:34:38.280 |
I'm gonna always point at active search as being well, we could 00:34:42.360 |
do lazy loading, or do active search, which one? 00:34:47.720 |
And this is I have to say this. Yeah. So like AES is what I 00:34:56.000 |
Yes. Okay. And I didn't hit enter. So I'm just typing 00:35:00.400 |
backspace, backspace. Hey, yeah. And let's have a look. We've got 00:35:05.040 |
so I've typed five things that resulted in five requests. And 00:35:10.560 |
so now interestingly, it's obviously done some debouncing 00:35:14.160 |
because I typed AES fast enough, it just sent one request. And 00:35:17.200 |
then I started typing backspace, wait, backspace, wait. This time 00:35:22.720 |
I typed it slower. And so I can see it's basically it looks very 00:35:28.120 |
normal from what you've described. So far, we've got a 00:35:30.840 |
post, it's got some data. Yeah, this response. So should I look 00:35:36.720 |
at this element to see how I would I would go up and we can 00:35:41.120 |
look at the highlighted code. It's a little easier to explain 00:35:43.280 |
if you go to the top there. Okay. Let's zoom in a bit. So 00:35:47.120 |
this is that's a obviously a pattern people are familiar with 00:35:50.160 |
from like Google and like a lot of more advanced web apps. And I 00:35:54.600 |
called it active search. I think I forget what Google calls it. 00:35:58.160 |
But and this is achieved with four htmx attributes, really 00:36:02.760 |
three plus one, we'll talk about at the end. But we once again 00:36:06.680 |
have an HX post here we have HX post instead of HX get because 00:36:10.360 |
we're issuing a post I in an ideal world, this should be a 00:36:13.640 |
gap, but I won't go into the reasons why we don't need to see 00:36:16.520 |
the the server side code for this. But like it's pretty 00:36:19.600 |
obvious what it would do or take the right data, it would do the 00:36:23.040 |
search and it would return the HTML that we just saw. Yeah, 00:36:27.480 |
exactly. And really the big the big difference here, the thing 00:36:30.440 |
that's new here for for people who are watching this and have 00:36:34.120 |
never done any I've never seen htmx before, is this HX trigger 00:36:38.400 |
attribute. And what that HX trigger attribute specifies is 00:36:42.560 |
the event that's going to trigger a request. And so it's 00:36:47.160 |
the event that we use as input. And then there's a couple of 00:36:51.240 |
modifiers on input. The first one is changed. Let's just go 00:36:54.480 |
back. So tell me what is the event input? Is that a normal 00:36:59.200 |
grammar knows? Yeah, exactly. Input is a is a standard DOM 00:37:03.640 |
event that you can look up like on Mozilla on MDN. And it 00:37:09.000 |
basically corresponds to a key up. But when it's it's when when 00:37:13.200 |
the input changes in an in an input of some sort. So it's 00:37:17.520 |
going to be triggered by checkboxes like when you check 00:37:20.120 |
them and uncheck them. With text boxes, it's triggered whenever 00:37:23.880 |
the text changes. And this is something I really like about 00:37:28.160 |
htmx is when I want to know how to do something, you know, and 00:37:34.200 |
it's nearly always like, Oh, well, this is just doing this 00:37:36.800 |
DOM thing, then the doc, then the document I search is like, 00:37:40.760 |
you know, Mozilla web docs. Yeah. It's not like, oh, here's 00:37:48.600 |
the special dashboard abstraction that Carson wrote, 00:37:53.160 |
or whatever. It's just like, no, it's just the web, man. 00:37:56.240 |
Yeah, yeah, I tried very much to lean on existing ideas. So you 00:38:00.520 |
know, again, as you pointed out, the HX swap attribute uses the 00:38:04.000 |
standard DOM name, like they're not the names I would pick, but 00:38:07.800 |
I just figured, you know, we might as well stick with as much 00:38:10.680 |
as possible with what the standards are. Yeah. And so we 00:38:13.920 |
tried to do the same thing with fast HTML, you know, like I say, 00:38:17.080 |
like, you know, there's a lot of people who have tried 1000 00:38:19.600 |
different functional HTML builders. And I thought like, 00:38:24.600 |
well, you know, HTML is kind of XML, their tags, they have a 00:38:30.920 |
name, they have positional parameters, they're called 00:38:34.680 |
children, they have keyword arguments, they're called 00:38:37.160 |
attributes. Python has those things. So it's just those 00:38:40.880 |
things, you know, it's kind of like, I think this thing of 00:38:42.880 |
like, embrace the technology you're working with is a theme 00:38:50.680 |
Yeah, like, I like the term rhyming, you know, make it rhyme. 00:38:55.000 |
Yeah. And so I don't know, but that just appeals to me. So in 00:38:59.480 |
any event, yeah, input is a, it's a standard event. And it 00:39:02.520 |
could be any event, you know, you could even use and people do 00:39:05.200 |
do this, you can use custom events to trigger requests, if 00:39:09.920 |
And you could delete all this. This is like a bit of extra. 00:39:13.560 |
Yeah, extra coolness. But all you actually need to make this 00:39:18.680 |
Correct? Yeah. And so the next two things are modifiers for 00:39:22.320 |
that event. And so there's the change modifier, and then the 00:39:25.520 |
modifier. And the change modifier tells HTMX only issue 00:39:31.840 |
a request if the value of this input has changed. So you don't 00:39:36.120 |
want to like if someone hits an arrow key, for example, that's 00:39:38.720 |
not a reason to issue a new request. And then the delay, you 00:39:43.040 |
notice that there was some sort of D bouncing going on. And 00:39:45.720 |
that's what that delay colon 500 milliseconds is doing. Yeah, 00:39:49.120 |
that's saying basically, when an input occurs, wait 500 00:39:52.720 |
milliseconds. And if another input hasn't occurred, issue the 00:39:59.440 |
So Carson speaking as like a user, something that I like a 00:40:04.000 |
lot about this, but at first made me nervous is a lot of the 00:40:08.240 |
code I saw, including on your website, had like, a lot of 00:40:13.640 |
unfamiliar words in unfamiliar syntax. And I thought, I'm not 00:40:17.640 |
clever enough to understand this. But then I quite quickly 00:40:20.680 |
realized, like, you can delete most of them. And it still 00:40:25.560 |
works. The bits I recognized, which is like respond to this 00:40:29.440 |
event, like a fine. And so I actually found it suited me 00:40:33.400 |
quite well to gradually learn these extra bits. And your book 00:40:39.960 |
is great at this. So the entire first section is about web 1.0, 00:40:47.360 |
you have an application branch. All of section two is about 00:40:53.280 |
HTMX. And you introduce it like, super gently, you know, right. 00:41:00.360 |
And just one little bit at a time. So you know, I would 00:41:05.000 |
encourage people to just go through this book. And then the 00:41:11.840 |
other thing to say is the mapping between just like the 00:41:15.200 |
mapping between HTML and fast HTML functions is a simple 00:41:20.000 |
one-to-one mapping. The mapping between HTMX attributes and 00:41:26.760 |
fast HTML attributes is also a one-to-one mapping. You just 00:41:31.240 |
literally replace the hyphen with an underscore. Yeah. So 00:41:36.280 |
like, you know, folks could go through, I think folks should go 00:41:40.000 |
through this book and build applications. And if you're a 00:41:44.320 |
Python programmer, you don't have to learn any JavaScript. 00:41:48.400 |
But in the process, you'll be learning a little bit about, 00:41:50.840 |
you know, JavaScript things and HTML things like HTML. But you 00:41:55.320 |
know, this book is a really great way to gradually build up 00:42:00.080 |
to understanding these like optional extras, in my opinion. 00:42:03.360 |
Right. Yeah, no, it's always tough to balance like, you know, 00:42:07.720 |
you want to you want to be useful for the advanced users, 00:42:10.920 |
but not too hard on the new users and so forth. So it's, it 00:42:15.160 |
is tough. I do think the book is pretty good at making it a 00:42:19.480 |
general introduction. I appreciate you saying that. So 00:42:23.400 |
and then there's a comma in there. And then there's so the 00:42:27.600 |
events are comma separated. So there's also a search event. 00:42:30.560 |
Okay, so this is event number one, which is an input event, 00:42:35.400 |
but only if it changed. And only if there hasn't been one within 00:42:38.680 |
500 milliseconds. And this is like or, yeah, or this is a 00:42:43.800 |
search event. What they search event, search event is triggered. 00:42:48.080 |
For example, scroll down to the UI. So what browser are you 00:42:55.280 |
using? You're using Chrome? Okay, so that little x on the 00:42:57.520 |
side there. Yeah. When you click that, a search event occurs. I 00:43:04.360 |
don't know an input may also occur there. I need to actually 00:43:08.600 |
And that's because like, there's a lot of stuff in HTML nowadays, 00:43:14.360 |
Yeah, exactly. And so so that search and there's I think there 00:43:19.240 |
are other like keyboard shortcuts. I don't know the 00:43:21.120 |
details of it. But we felt like, okay, we're gonna, we're gonna 00:43:26.480 |
And like I just showed example here. So we use this thing by 00:43:31.800 |
default, you can use whatever styling we like, but by default, 00:43:35.960 |
we use this thing called Pico, which I'm sure you're familiar 00:43:38.560 |
with. And one of the things I like about Pico is it really 00:43:44.000 |
leans in also to the idea of like, just embrace, you know, 00:43:48.080 |
the web. And so here's a rather nice, reasonably, you know, 00:43:53.800 |
reasonably nice looking search box. Right. And as you can see, 00:43:58.360 |
it's an input with type equals search. Yep. And a button, you 00:44:04.040 |
know, and in fact, the source code for this is literally form 00:44:10.960 |
of equal search. So yeah, I think by like embracing the 00:44:14.680 |
stuff that's available in HTML, and then joining it together 00:44:18.400 |
with things, other things that embrace that like Pico and like 00:44:20.960 |
HTMX, you can have very kind of, I don't know, it feels like the 00:44:26.520 |
stuff you learn as you put this together, all joins up together. 00:44:31.160 |
It's very different to learning like, this dashboarding system, 00:44:35.680 |
and you want to use a different dashboarding system, throw away 00:44:41.120 |
Yeah, no, I agree. I think that's a good thing about 00:44:44.480 |
HTMX. And Pico CSS is a great library as well. And that it's 00:44:49.520 |
just it, it, it does, you know, again, rhyme with like, and 00:44:54.160 |
tries to reuse the existing concepts of the web or other 00:44:57.440 |
than imposing a bunch of new sort of mental categories on top 00:45:02.600 |
yeah, okay, so that Okay, so either search or input. All 00:45:07.920 |
right. And then target we've seen so the search results and 00:45:11.080 |
this is a kind of a common pattern that I guess we see with 00:45:15.240 |
HTMX is you kind of start off generally, let's just like 00:45:19.560 |
close, let's just refresh this, you kind of start off with 00:45:24.560 |
so you've got a table, if you open that table up, there's a 00:45:32.920 |
table body in there that's got nothing in it, but it has that 00:45:35.640 |
ID on it. Yeah. And so we're targeting that that that T body, 00:45:39.920 |
and the default swap is going to be inner HTML. So what HTMX is 00:45:44.760 |
going to do is take the response that comes back and then put it 00:45:47.640 |
inside of that element. And so that works for this. So yeah, 00:45:55.080 |
that's the that's the idea there. And then there's a last 00:45:58.720 |
attribute, which is kind of a new one, the AJAX indicator, I 00:46:01.800 |
haven't used this yet, but people rave about, okay. Yeah, 00:46:05.000 |
you use that it takes a CSS selector, and that you can point 00:46:09.360 |
it at an element, and it'll basically show that element 00:46:13.200 |
while the request is in flight. And that addresses that issue 00:46:16.320 |
you saw on Richard Stallman's web page, where you click the 00:46:19.040 |
button, and it seemed like nothing happened for a second, 00:46:21.760 |
because it was Oh, I see that searching thing popped up. Yeah. 00:46:24.680 |
And so I see it. But yeah, yeah. I was so sometimes I make this 00:46:29.920 |
slower. So that like, yeah, I can see the indicator. Yeah. And 00:46:33.800 |
then people complain that HTMX is slow. And then I speed it up. 00:46:38.320 |
And then they don't see the indicators. Okay, great. Yeah. 00:46:44.320 |
Do you have a hard stop at some time? I just want to think how 00:46:51.200 |
So let's look at the lazy loading one, then. That's okay. 00:46:58.200 |
Tokyo. So here, refresh, refresh. Okay, refresh. And 00:47:03.280 |
you'll see like, this is a big indicator. And then I see. So if 00:47:07.000 |
I scroll with let me just I think I understand. So if I make 00:47:10.040 |
this smaller, yeah. And then I do that. And then I scroll to 00:47:15.200 |
it. I see it's kind of happening in the background. And yeah, 00:47:18.480 |
okay, cool. So the reason for that is, if I wanted to, like, 00:47:21.560 |
have something I could start reading, or else something else 00:47:24.160 |
was busy calculating underneath. Is that what's happening? 00:47:26.720 |
Yeah, this is a this is a good pattern for when you have some 00:47:30.960 |
some information that is maybe even even if it's important, 00:47:35.280 |
it's something that you don't want to block the rendering of 00:47:38.200 |
the first render of the page, you don't want it to block that 00:47:40.760 |
first load of the page, because it's going to take a while. So 00:47:43.560 |
this is just I mean, it's just a dumb image, like, but it's a 00:47:46.400 |
stand in for Okay, here's some complicated stuff that we did to 00:47:50.080 |
compute, you know, Tokyo's climate or whatever. Yeah. And 00:47:53.960 |
so the important thing here is that the rest of the page 00:47:58.000 |
renders very quickly. And then, and then we can issue this 00:48:02.760 |
request, sort of when the page loads to sort of have a second 00:48:08.160 |
error request, it's going to bring in the expect the expense 00:48:10.600 |
of computation. So looking at this div, we want to once again, 00:48:15.160 |
have an HX get where we're going to issue a request to URL that's 00:48:18.680 |
going to make presumably take a while because it's expensive. 00:48:21.360 |
And now this presumably would be basically returning an image 00:48:24.920 |
tag or like a div with an image tag, an image tag or whatever. 00:48:28.520 |
Yeah, whatever. And then that'll get loaded into wherever the 00:48:30.880 |
target is. Yeah. And I guess in this case, the target is itself. 00:48:35.640 |
Yeah, the target is since we don't specify a target, the 00:48:38.280 |
default target is going to be the div itself. 00:48:40.440 |
And just to come back to your last thing, you said also that 00:48:43.040 |
the default swap is the inner HTML. So this is going to be 00:48:47.080 |
Exactly. Okay. And then the trigger here is load. And that 00:48:51.480 |
is, unfortunately, that is not a standard. But I just I couldn't 00:49:01.680 |
Okay, so you've got HTMS events here. And we can scroll through 00:49:06.520 |
them to see there's quite a few events. And here is yeah, load. 00:49:10.400 |
Yeah, this is actually if you go to the docs, it's not I don't 00:49:14.800 |
think it's this is a this is triggered when an element is 00:49:17.680 |
loaded. But it's in the docs I mentioned. And if you go and 00:49:31.520 |
Oh, actually, well, if I go to trigger, I guess that would be 00:49:34.760 |
the best way. Yeah, it's probably in there as well. Yeah, 00:49:38.360 |
there's a couple of special ones in there. Cool. So I'll just 00:49:42.080 |
search for load. Here we are non standard events. Great. 00:49:47.720 |
Yeah. So we have load we have revealed and intersect revealed. 00:49:53.320 |
And like, have you ever worked with the intersection observer 00:49:57.200 |
in JavaScript? No. Okay. The the way JavaScript handles sort of 00:50:05.120 |
like things scrolling into view is pretty complicated. And I 00:50:09.920 |
wanted to declare the API. And so I just kind of put and the 00:50:13.520 |
same with loading uses, I forget the name of the event. It's a 00:50:16.560 |
big, ugly name. And so for these three things, I was like, look, 00:50:20.760 |
I'm just gonna have like my own obviously named events for this 00:50:24.560 |
stuff. And we'll, we'll just have to deal with it. And so 00:50:27.920 |
make sure I kind of clarify both myself and for other people are 00:50:32.160 |
just confused. There's two of these two different load events 00:50:40.280 |
Anything that starts with htmx colon is an event that htmx 00:50:45.800 |
itself triggers as a custom event. Yes. These are these 00:50:50.280 |
these three events are synthetic events that htmx makes work as 00:50:57.400 |
htmx colon load before. Because like I like to set up things so 00:51:04.640 |
that when I'm working with a JavaScript library, that when 00:51:08.160 |
htmx adds something to my page, the JavaScript library can run 00:51:12.920 |
Exactly. Yeah, that's exactly what it's useful for. So maybe 00:51:16.840 |
not the best name in the world, but it is what it is. 00:51:19.280 |
Okay, well, this is pretty straightforward, then, isn't it? 00:51:21.200 |
So you've got this div targeting itself. And when it's Yeah, when 00:51:25.760 |
load is done, it's going to go ahead and stick the graph in 00:51:30.280 |
Yeah, exactly. And that's so this can be very, a very good 00:51:34.160 |
way. Like if you have a part of a web page that is expensive to 00:51:38.000 |
compute, and it's making that web page, the first paint of 00:51:41.280 |
that web page very slow, you can just move that that chunk out to 00:51:45.520 |
a new URL, and then use this pattern. And then suddenly, that 00:51:48.880 |
web page will load very quickly. And you know, the other stuff 00:51:52.160 |
will come in when it's ready, but the user can still interact 00:51:54.640 |
with the page, they can still click on links, or if they get 00:51:57.320 |
sick of waiting, or whatever, they're not stuck there waiting. 00:51:59.960 |
Like we were for that search result on Stallman's page, just 00:52:03.600 |
wondering when this was ever going to come back. 00:52:05.640 |
Right. Exactly. So okay, great. I, I wanted to just maybe show 00:52:16.040 |
folks how then all this works together with, like, CSS and 00:52:27.040 |
JavaScript and, and all that stuff, because like something 00:52:30.360 |
else that I found interesting is how the fact that HTMX removes 00:52:36.640 |
those four constraints doesn't really impact at all, how I use 00:52:44.040 |
styles or JavaScript, you know, right. So like, I'll just share 00:52:52.200 |
a couple of things. You know, to maybe make that more clear for 00:52:57.680 |
folks. So for instance, the other thing I found interesting, 00:53:04.520 |
Carson is like, combined with fast HTML, and also combined 00:53:10.040 |
with this really nice deployment service, we've been using 00:53:13.760 |
called Railway, where you can run as many things as you like, 00:53:18.720 |
and they cost two or three cents a month, you know, unless lots 00:53:23.000 |
of people are hitting them. And so there was this interesting 00:53:25.560 |
thing where I wanted to create this little mini page, you know, 00:53:29.760 |
where I talk about things like HTMX and HTTP and memes and 00:53:35.600 |
stuff. And I, what was wild to me as I started doing this was 00:53:40.800 |
I like realized, I kind of created this thing, which has 00:53:45.360 |
like all these like little things like this auto updating 00:53:47.880 |
kind of side and like things that wave over when you go over 00:53:52.280 |
them and they're very bold. It's like, oh, like some blogging 00:53:56.040 |
content framework and I'm like, actually, no, you know, this is 00:53:59.800 |
just a fast HTML page. The source code for this page is 00:54:07.680 |
like, you know, it's just marked down with like a tiny bit of 00:54:12.520 |
code. And all the work happens actually, in Bootstrap, you 00:54:19.000 |
know, right. And so like, with Bootstrap, you know, I was able 00:54:26.640 |
to basically create this tiny little thing for this page, 00:54:30.960 |
probably here, called like a Bootstrap page, you know, so 00:54:35.400 |
overview basically says return a Bootstrap page, it's page 00:54:40.160 |
number zero. So that's why it knows which one to make bold. 00:54:42.640 |
This is the title of it. These are the sections like there's 00:54:46.000 |
all these nice little things in HTMX. Like, if you return a 00:54:49.080 |
title tag, as one of your partials, it actually changes 00:54:52.400 |
the title of the page, which is sweet. You know, like what's a 00:54:56.720 |
section? Well, section is just like, you know, just a div, you 00:55:02.040 |
know, with, so like, all the CSS is just really normal. And then 00:55:10.440 |
like the JavaScript, and I think this is the bit people get the 00:55:14.000 |
most confused about, is also really normal. So if you look 00:55:24.480 |
at, you know, we have fasthtml.js, for example, for 00:55:32.120 |
markdown, if you create, have a marked class on anything, and 00:55:37.520 |
then you basically add a markdown.js component to your 00:55:41.960 |
page, then it runs a bit of JavaScript. And now all of your 00:55:45.760 |
markdown is automatically done. Or, you know, you can do the 00:55:47.840 |
same thing for highlight to get syntax highlighting, or my 00:55:51.520 |
favorite ones, sortable. Yeah, this one like, actually, I much 00:55:59.200 |
prefer my version, because it's less clever than yours. It's 00:56:02.360 |
much easier to see. This is my version of sortable. That's the 00:56:05.080 |
entire thing, is you just got sortable create. And so it's 00:56:12.840 |
down there, drag and drop. Yeah, you end up with this, this 00:56:17.600 |
ability to drag and drop. And the cool thing is that behind 00:56:21.440 |
the scenes, it's telling the server what the new order is. 00:56:26.600 |
Yeah, yeah. So yeah, this is a great example. Like, you know, 00:56:32.560 |
sometimes I've heard a lot, especially now that htmx is 00:56:35.280 |
getting more and more popular. And the JavaScript community 00:56:38.920 |
can't ignore it anymore, or make fun of it like they used to, is 00:56:42.640 |
people say things like, oh, htmx is for people who hate 00:56:46.240 |
JavaScript. And there's some truth to that. Obviously, if 00:56:48.480 |
you're not a big JavaScript fan, htmx can give you a lot of oomph. 00:56:53.520 |
But also to really to take advantage of htmx, like the 00:56:57.520 |
events, the fact that it uses events and integrates, like with 00:57:01.040 |
the DOM via events, means that it should be able to play very 00:57:06.480 |
So like, let's run this little, so I've got this kind of like 00:57:10.480 |
idiomatic app I've created with like, most of its comments, you 00:57:15.080 |
know, and so like, you know, here's the bit, here's the bit 00:57:18.440 |
that makes it drag and drop. Describes how that happens. And 00:57:24.000 |
so if we run it, and then I say like, okay, let's show 00:57:32.240 |
prioritization, drag it to the bottom. Missed, drag it to the 00:57:36.520 |
bottom. There we go. And if I now refresh, it's still at the 00:57:43.600 |
bottom. And yeah, it's magic, you know, and like the, like, 00:57:49.240 |
how does that work? It's like, I think this is really 00:57:52.160 |
interesting. It's like, okay, well, we include this library, 00:57:54.440 |
which as we described, is literally three lines of code. 00:57:58.240 |
And I added this tiny thing, Carson, which is just a little 00:58:01.280 |
JavaScript thing that just basically does a htmx for each 00:58:05.640 |
onload kind of thing. So it causes this to happen on all new 00:58:10.640 |
things as well. And then sortable, it's kind of amazing 00:58:17.240 |
how all these things you made just come together. So we have a 00:58:19.880 |
form. And so the to do list itself is actually inside a 00:58:23.440 |
form. And so that form is triggered by the event that the 00:58:28.360 |
sortable docs say is triggered, which is the end event. I 00:58:33.000 |
didn't have to do anything. And then it just calls slash 00:58:36.640 |
reorder. You know, and then reorder is two lines of code, 00:58:42.280 |
you know, it updates each to do to the new priority and returns. 00:58:46.560 |
This is the reason my code simpler than yours is because 00:58:48.800 |
it's less efficient. I returned the whole to do list. You know, 00:58:52.000 |
it was just fine. Yeah. So sometimes that's the right 00:58:55.320 |
thing. JavaScript is such a delight in htmx, because I only 00:58:59.520 |
have to use it for the bits I need it for, you know, right. 00:59:02.600 |
And that's so you know, I say htmx is pro JavaScript because 00:59:06.440 |
of that, for that very reason, it takes the pressure off of 00:59:09.440 |
JavaScript to be the entire infrastructure for your web app. 00:59:12.920 |
And so it can be used for these situations where it really can 00:59:16.400 |
add a lot of value. So drag and drop is something that's not 00:59:18.920 |
baked into the web out of the box, at least not well by 00:59:22.440 |
default. And so these, you know, sortable JS addresses that and 00:59:26.320 |
provide some really good functionality. And then htmx can 00:59:28.800 |
integrate with it via events really cleanly. So a really 00:59:32.720 |
that's a another great example. I think of htmx being being used 00:59:37.480 |
the way it was intended to and sort of playing well with other 00:59:39.840 |
things, you know, it's designed to be, especially with it's a 00:59:43.000 |
focus on events, it's designed to plug in reasonably well with 00:59:47.280 |
other libraries, as long as they, you know, as long as they 00:59:50.120 |
play well with the DOM to triggering events, and then 00:59:53.360 |
using inputs to communicate information out to the remote 00:59:59.480 |
So let's switch topics a bit if we can. And the reason that I, 01:00:06.880 |
or a reason I use the much unappreciated epithet, genius is 01:00:12.440 |
because the most things that I come across, and I say, like, 01:00:16.480 |
that's clever, I can immediately think like, oh, I see exactly 01:00:20.720 |
how they came up with that, you know, but like, my friend, Chris 01:00:24.120 |
Latner, for example, who's created like LLVM and Mojo and 01:00:28.520 |
Swift and other things, like, very often I have conversations 01:00:32.320 |
with him, where he describes the thing he's created. Having 01:00:36.480 |
described the thing, I can say like, yes, that is the right way 01:00:39.800 |
to do that. And then I'm like, but I don't know how you could 01:00:43.360 |
possibly have known that I only know it now that you've told me 01:00:47.480 |
now this thing you've done, like, there are four constraints, 01:00:50.560 |
we can remove them with a polyfill. Once we do that, we 01:00:53.320 |
can reprogram the web. Like, where did that come from? 01:00:58.400 |
Because like, this goes back to like, like 10 years plus ago 01:01:02.040 |
that you kind of first implemented this. And I hadn't, 01:01:08.000 |
Yeah. I mean, there were, you know, there was a there was 01:01:12.400 |
something called pjax back in the day. I don't know if you 01:01:15.120 |
ever heard of pjax. Yeah, there was pjax. And then there was a 01:01:21.560 |
in jQuery, there was this I think it's called fetch, or 01:01:25.120 |
load, load, I think it's a load. And it does something similar, 01:01:30.400 |
you give it a view, you just give it a CSS selector, like in 01:01:34.040 |
the dollar sign syntax, and then you say dot load, and you give 01:01:36.760 |
it a URL, and it'll issue a get and just load the response into 01:01:40.040 |
that thing. Yeah. And so there were some, there were some 01:01:44.680 |
Yeah, well, we were one of the first jQuery users when it first 01:01:48.840 |
came out, actually. And so it was fun to watch those things 01:01:51.600 |
kind of get added. And definitely Risik, Risik's a 01:01:56.640 |
Yeah, he's, oh, yeah. And so I think, like, you know, I saw 01:02:01.320 |
that, I've told the story before, but I was just having 01:02:04.080 |
trouble with a performance issue. I was trying to do 01:02:06.160 |
sorting in JavaScript, in like 2009, or eight. And it just was 01:02:11.320 |
too slow, because the runtimes at that time were so slow, and 01:02:14.840 |
non standard and all the rest of it. And so DOM manipulation was 01:02:17.960 |
very slow. And I ended up, I don't know if I use the jQuery 01:02:23.360 |
dot load method, but I did something, I think I might have 01:02:26.920 |
seen it and did something similar, and then kind of 01:02:29.320 |
started making that more general using the jQuery AJAX function. 01:02:35.040 |
Where, you know, I was like, Oh, yeah, I didn't. So I had a UI, 01:02:40.120 |
I was trying to sort, it was too slow to do in JavaScript. And 01:02:42.600 |
out of desperation, I tried doing it on the server side, and 01:02:45.440 |
then just slamming it into the UI. And that turned out to be 01:02:48.840 |
really fast. Like, to my surprise, it was pretty desperate 01:02:52.080 |
move on my part, I didn't think I was gonna be able to do it. 01:02:54.040 |
Well, but, but it worked. And I was like, Oh, this is great. 01:02:57.960 |
Okay, I didn't know you're allowed to do that. You can just 01:03:00.480 |
put right, you know, you put HTML wherever you want. That's 01:03:02.720 |
cool. Yeah. And, and then so that turned into like a little 01:03:07.000 |
function that I had for a while that was kind of more in the 01:03:09.840 |
jQuery style of like, you look things up and hook in 01:03:12.920 |
functionality. And then I saw Angular one. Yes, I didn't like 01:03:18.080 |
I didn't like much of Angular one, except that they use 01:03:21.200 |
attributes to specify behaviors. Yeah, I was like, you know, this 01:03:24.480 |
is, this is a lot like, like the href stuff, like links and 01:03:28.400 |
big hit YouTube video was an angular. Okay, yeah. Yeah, I 01:03:33.000 |
don't want to throw it through. I don't want to throw any shade 01:03:36.240 |
at Angular. I've got no beef with Angular, and it's fine. But 01:03:39.240 |
it wasn't what I was looking for. And what I was trying to 01:03:42.040 |
do, but I did like how they use attributes. And I realized, 01:03:45.200 |
okay, I can use attributes to hook this behavior in instead 01:03:50.160 |
of instead of using a jQuery selector. And, and so that sort 01:03:56.680 |
of turned into that just very organically turned into 01:03:59.280 |
intercooler.js. And I've got to be honest with you, like a lot 01:04:01.880 |
of the academic stuff came afterwards. Yeah, I didn't 01:04:04.800 |
understand hypermedia very well. Yeah, when I did when I 01:04:07.880 |
initially did all this stuff. It was just, you know, 01:04:11.080 |
look, that's that doesn't shock me at all. You know, my, my 01:04:14.440 |
friend and co founder, Eric Reese wrote this book called 01:04:18.400 |
the lean startup, which is actually a lot more than just 01:04:21.200 |
about startups, you know, this idea of the MVP. And it's 01:04:25.320 |
actually the basis on which answer AI is created, which is 01:04:28.280 |
building things that way, which is like, iteratively, bit by 01:04:33.000 |
bit, you know, and then later on, you kind of look back and 01:04:35.360 |
you're like, Oh, I kind of built something kind of cool here. I 01:04:38.480 |
wonder how this thing I built actually works. And then you're 01:04:41.760 |
like, Oh, I guess it's hypermedia. And I guess it's 01:04:43.680 |
actually these four constraints, we actually ended up removing 01:04:46.120 |
them. And yeah, I think it makes it less intimidating to know 01:04:50.280 |
that you don't have to invent this new universe in your head 01:04:54.280 |
all ahead of time, and then implement it. Yeah. 01:04:56.760 |
Yeah, you know, there's what's the saying, like, existence 01:05:00.840 |
brings essence into being like, you have to do the thing first, 01:05:04.000 |
and then you can talk about what the thing is. Yeah, it's kind of 01:05:07.200 |
got to be there first. And then you can say, Okay, what what 01:05:10.520 |
You must have had some kind of intuition at some point that 01:05:15.000 |
there was a direction forming that felt like you were enthused 01:05:22.480 |
Yeah, I you know, to me, it was more just an unwillingness to 01:05:27.120 |
deal with the complexities of like, you didn't knock out JS at 01:05:30.520 |
the time. And, and things like that. I just, I was like, man, I 01:05:35.200 |
just don't want to deal with all that. No, I just, I just, I just 01:05:38.760 |
want to be able to put stuff in the DOM. And, you know, I think 01:05:43.000 |
when I first did it, I went through there was a within this 01:05:46.760 |
is with the intercooler, the predecessor to HTMX, which is 01:05:49.240 |
very similar. It's just it's basically a jQuery 01:05:52.000 |
implementation of the same stuff that HTMX does. I went through 01:05:57.080 |
and I started doing examples. And then I started realizing 01:06:00.560 |
like, whoa, you can do infinite scroll with this. Whoa, you can 01:06:03.360 |
do active search with this. Like, yeah, this is cool. You 01:06:05.720 |
can do a lot with this. And so that, but that was, I discovered 01:06:09.800 |
that, you know, I didn't think about that up front, I discovered 01:06:13.000 |
the fact that, hey, with these abstractions, you know, with the 01:06:17.000 |
limitations on HTML removed, you can actually do a lot of cool 01:06:21.240 |
stuff. So yeah, it was very organic. And I definitely not 01:06:27.840 |
Yeah. So, no, I mean, it's, it's interesting to me, because I'm 01:06:34.720 |
sure I've never created anything as clever as HTMX. But I've 01:06:39.080 |
definitely created things that are at least as bloody minded as 01:06:44.120 |
HTMX, you know, like you've kind of been like, you know, it's 01:06:48.840 |
interesting, you mentioned Knockout, for example, most 01:06:50.800 |
people listening probably won't remember it, but it was very 01:06:52.720 |
popular back in the day. And it came out as, as we were building 01:06:58.120 |
Kaggle, which is one of my earliest startups, and some of 01:07:00.400 |
the folks were like, we've got to do Knockout. And I was just 01:07:03.120 |
like, we just so don't have to do Knockout. And yeah, it's 01:07:07.560 |
interesting, you have this reaction to complexity. It's not 01:07:13.720 |
a reaction to like, it's not a kind of classic conservative, 01:07:17.320 |
like, we have to do things the same way. It's more like, no, we 01:07:22.440 |
have to make things accessible. And we have to, like, you know, 01:07:27.840 |
appreciate what's good about what exists and take advantage 01:07:31.000 |
of that. But yeah, it's interesting. Like, I feel like 01:07:35.040 |
maybe, like I said, at the start of this interview, you don't 01:07:41.520 |
look or sound like a tech genius, you don't live in a 01:07:44.520 |
place full of tech geniuses, you know, you're, you know, 01:07:47.640 |
and I'm also not a tech genius. So it all checks out. 01:07:51.880 |
Teaching kids baseball, you know, like, you, you know, and, 01:07:57.960 |
you know, so I guess, you know, I would consider myself an 01:08:01.280 |
outsider, you know, would you kind of consider yourself an 01:08:04.920 |
outsider? And would you say that's part of why you can 01:08:07.320 |
create these somewhat bloody minded things that push back 01:08:13.040 |
Right? Yeah, I definitely was an outsider in the Bay Area, 01:08:17.200 |
because I was from Sacramento. And I've been like one thing I 01:08:21.080 |
realized about my, my, particularly when I was younger, 01:08:24.280 |
as I was very naive about, like, everything, pretty much 01:08:27.800 |
everything. And so, you know, the problem with being naive is 01:08:31.880 |
when bad stuff happens, you can get pretty embittered. And so I 01:08:35.720 |
went through that whole naivety, embittered cycle on the Bay 01:08:38.880 |
Area, and so forth. And so, so there's definitely 01:08:43.160 |
some people who don't know. So Sacramento is like, three hours 01:08:47.560 |
or so inland of San Francisco, and it's like, it's pretty 01:08:50.840 |
hot. And pretty kind of like, it's not. It's not at all like 01:08:57.080 |
Yeah, it's very agricultural or was it's the Central Valley is 01:09:01.400 |
filled up because the Bay Area has gotten so expensive. So what 01:09:04.720 |
I grew up in has been is very different. Now, the area I grew 01:09:07.920 |
up in, but, but yeah, I was just not, you know, I just wasn't a 01:09:11.400 |
barrier person. And I felt that like the entire time was there, 01:09:14.400 |
even when I went to Berkeley and Stanford for grad school, and 01:09:17.600 |
just was very much an outsider. And that's fine. I'm also, you 01:09:22.440 |
know, a little bit of a contrarian, I guess. And so 01:09:25.240 |
that, you know, and that's good and bad, you know, it's been 01:09:28.240 |
good parts of my life and bad and of course, but I do think 01:09:31.960 |
like something you sort of touched on there is there 01:09:34.960 |
doesn't, in tech, tech, technology is so forward 01:09:38.240 |
looking, that we don't do a lot of looking back at what people 01:09:42.520 |
had before, right, or what was done before. And I think that's 01:09:46.120 |
one reason why we're constantly reinventing the wheel, you know, 01:09:49.000 |
in many ways, sometimes worse, you know. And so the with with 01:09:56.120 |
HTMX, and with intercooler before that I really was trying 01:10:00.840 |
to once I understood once I got my feet under myself and 01:10:03.120 |
understood what was going on, is I tried as much as possible to 01:10:06.920 |
rhyme, you know, that's the way I would say it is, you don't 01:10:09.680 |
have to be the past, you don't have to dress or like, you know, 01:10:12.960 |
act or whatever. But like, if you can rhyme with that stuff, 01:10:16.440 |
like, there's probably some good ideas there. And I think that's 01:10:18.440 |
one reason why HTMX has a pretty high power to weight ratio is 01:10:22.240 |
that it just builds on these really, like CSS selectors, and 01:10:26.320 |
like the basic DOM APIs and events, like, you know, the, the 01:10:30.480 |
DOM being an event bus, like, that's, those are all concepts 01:10:33.720 |
are already there. And HTMX really just like, is built on 01:10:39.920 |
I spent months, a year or two ago, teaching people, APL 01:10:45.720 |
notation originally developed in the late 50s. Yeah, like, I 01:10:49.960 |
definitely appreciate this idea of recognising when really deep 01:10:57.200 |
thoughts have been had in the past. And when you can take 01:11:00.840 |
advantage of that. Yeah, present and combine them with new 01:11:05.160 |
Yeah, like, what's a new take on that? You know, that's that can 01:11:08.880 |
often be one example I bring up a lot is the visual basic six 01:11:12.960 |
debugger was like the best debugger I ever used to continue 01:11:17.160 |
so good. Yeah, you can it was like, you could do whatever you 01:11:20.600 |
wanted. You could drag the program count, like you could 01:11:22.520 |
drag the pointer wherever you wanted to during execution. It 01:11:25.160 |
was unbelievable. And my understanding is dotnet has that 01:11:28.200 |
now, but I work on the JVM a lot. And it's got nothing like 01:11:33.640 |
and if you look back to get back, if you go back further to 01:11:37.080 |
Microsoft Access, you know, the thing it had with these like 01:11:40.680 |
reports and stuff was basically flex grid, you know, HTML 01:11:45.280 |
programmable back and I was doing that, I guess, in the 01:11:49.000 |
early 90s. Let me just again, switch then to kind of like 01:11:53.320 |
talking about something which I've seen with you, and I've 01:11:59.280 |
certainly experienced myself. I very intentionally do a lot of 01:12:03.920 |
things extremely differently to everybody else. Because I like 01:12:08.440 |
to experiment with like, what happens when you try things 01:12:11.720 |
differently. So I'd be able to think about nbdev, which is 01:12:15.000 |
where you do all of your assist software development inside 01:12:19.200 |
Jupyter Notebooks. And I've written most of my software like 01:12:21.560 |
that for the last few years. And it turns out, the affordances 01:12:24.600 |
provided in notebooks are actually amazing. I've, you 01:12:30.560 |
know, I've created an AI thing called fast AI, which kind of 01:12:34.600 |
when everybody was trying to build big foundation models, I 01:12:37.360 |
was focused on like fine tuning. And now with fast HTML, when 01:12:41.880 |
everybody's focused on Svelte, React, Vue, whatever stuff, I'm 01:12:47.760 |
like, let's lean into HTMX and hypermedia and Python instead 01:12:52.720 |
of JavaScript. Something I've noticed a lot is, and I've seen 01:12:59.200 |
there's a psychological phenomenon, where when human 01:13:03.600 |
beings are presented with change, there's like literally 01:13:07.800 |
a chemical reaction in their brain that is identical to 01:13:10.600 |
physical pain. And I see that with how people react to HTMX as 01:13:18.080 |
well, which is I often see people respond with an enormous 01:13:22.480 |
amount of anger. You know, almost like this kind of 01:13:27.520 |
desperate anger. And yeah, I'm kind of like, and so it's 01:13:30.720 |
interesting how, what, you kind of have these two really 01:13:36.600 |
different directions. One is like, you're literally a 01:13:38.600 |
university professor, like you say, expertly Stanford, and you 01:13:42.560 |
create these like, incredibly academic things, looking back 01:13:46.640 |
at Roy Fielding and HATEOAS and everywhere else. And then 01:13:50.120 |
there's the other Carson, which is like, trolling, memeing, you 01:13:54.800 |
know. I guess like, yeah, it's like, is it like, partly that 01:14:01.160 |
you're kind of reacting to the bullshit earnestness of this 01:14:07.160 |
world and trying to like, not take it too seriously? Or like, 01:14:10.120 |
is it kind of like an intentional thing you're doing 01:14:12.080 |
to try to deal with the reaction people are having to this 01:14:16.560 |
psychological pain of seeing change? Or, you know, what's 01:14:22.280 |
I will. So I think you're right. And I'm sympathetic. There's a 01:14:26.040 |
reason we're like that, right? Like, there, there's nothing 01:14:29.320 |
about us that is not there for, for some reason or other. And 01:14:32.720 |
so change is hard on humans. So we should make, you know, 01:14:35.720 |
allowances for that fact. Humor is for me, I've always been kind 01:14:41.400 |
of a joker, and last clown and so forth. And I grew up on the, 01:14:46.840 |
you know, on the forums in the late 90s and early 2000s, kind 01:14:50.880 |
of pretty rough and tumble back in the day. And so I got I got 01:14:55.520 |
good with memes. And I just always preferred joking. It's 01:15:00.080 |
funny, you know, I just I don't know, I end up like a lot of 01:15:06.160 |
memes. And, you know, I think they're, there's, they're good. 01:15:09.960 |
They're, you know, a picture is worth 1000 words, and I mean, 01:15:12.840 |
maybe worth like 100,000 words, like a good meme, and really got 01:15:17.280 |
through a lot of stuff. And so that's it. That's one. That's 01:15:22.920 |
one by Alex. That's pretty funny one. So I really like humor. 01:15:26.720 |
So like, it's so on point, like, like, it's literally what we're 01:15:31.720 |
talking about. It's like, I was like, hey, if you do this stuff, 01:15:35.440 |
you're just doing the foundations. And you keep doing 01:15:38.960 |
the foundations, and they all come together. And suddenly 01:15:41.920 |
you're like, you're really good at building web apps, you know, 01:15:45.960 |
yeah. And like, you know, Daniel Roy Greenfield, one of the 01:15:51.480 |
co authors of two scoops of Django, which is one of the best 01:15:54.320 |
programming books of all time, within 45 minutes of trying fast 01:15:58.520 |
HTML, and he'd never also used HTMX, he had rewritten his 01:16:01.480 |
entire blog system. Yeah, his his wife, Audrey, the other of 01:16:07.040 |
the two scoops of Django co authors saw him do that. The 01:16:12.880 |
next day, she was doing a hackathon. She had never used 01:16:17.320 |
fast HTML before she decided that morning that she was going 01:16:20.280 |
to use it for her team in the hackathon. They won the 01:16:22.480 |
hackathon. You know, like these people who have like learn the 01:16:26.480 |
basics, and then they get something that rhymes. Yeah, 01:16:29.880 |
they zoom in. But so these memes, they're like, they're 01:16:35.240 |
funny, but my god, they're like, they're cut to the bone as well. 01:16:39.960 |
You know, yeah, yeah, I think I'm pretty good writer, you 01:16:42.960 |
know, the book, I was actually better at English, like I scored 01:16:48.480 |
better in standardized tests on on English than I did on math. 01:16:52.680 |
And I've always just liked, you know, I like I read a boatload 01:16:57.360 |
when I was a kid. And so I, you know, I just, it's just a knack 01:17:01.120 |
I've got for me. I don't know. It's not this isn't Shakespeare, 01:17:04.120 |
but it's very effective communication medium, combining 01:17:07.680 |
a picture with a, you know, with a short and pithy statement. So 01:17:12.520 |
well, I mean, when I wanted an explanation for HTMX, I, I used 01:17:22.560 |
to I used one of the memes because it is, yeah, it did a 01:17:25.640 |
better job of explaining what was in my head, I could use 01:17:28.480 |
words for which is like, yeah, and actually, so Eric reason I 01:17:31.320 |
were talking about the kind of days of when we were starting 01:17:34.920 |
coding PHP, you've got a shell home directory, you dump a file 01:17:39.880 |
in there, you've got a web app to show to your friends, you 01:17:42.520 |
know, and so it was even simpler than like your 2004 model. And 01:17:48.360 |
yeah, you know, we were both saying like, Oh, you know, it's 01:17:51.480 |
so painful to create an application now, right, you 01:17:54.960 |
know, and so yeah, the picture does tell 1000 words a day does 01:18:01.320 |
it doesn't humor works, people like humor, the people who get 01:18:04.960 |
mad about them, like they're probably the people that you 01:18:07.080 |
want to get mad anyway. So, you know, I don't know, it's been a 01:18:12.200 |
good way. I've gotten much better, though, like, you know, 01:18:14.200 |
if you if you were talking to me 10 years ago, I would have been 01:18:16.520 |
much more embittered about things like much more 01:18:18.920 |
sarcastic, you know, there's, and there's a part of me that's 01:18:21.640 |
still like that. I just really, you know, I was about it was 01:18:25.480 |
about 10 years ago, I just kind of was like, you know what, I 01:18:27.800 |
can't live like this. Like, I'm not I ever got to be more 01:18:31.000 |
positive about things. There's a lot of good things. It's so 01:18:33.640 |
easy to be negative. And, you know, especially with the 01:18:36.920 |
information overload we have now. And I you know, I just was 01:18:41.560 |
I just sort of committed to being more positive about it. 01:18:43.920 |
to does it help to be away from the Bay Area, you know, living 01:18:49.720 |
probably it's, there's less financial pressure. That 01:18:53.120 |
certainly helps. You know, Montana is very beautiful. And 01:18:56.680 |
like, there's a lot of nature also, you can freeze to death. 01:18:59.360 |
So that gives you some perspective on life, like, Oh, 01:19:02.480 |
wow, it's minus 40 outside. I don't know. I really hope the 01:19:04.960 |
power. I really hope that the minus 40 Fahrenheit, I really 01:19:08.640 |
hope that the power doesn't go out, because that would be bad. 01:19:11.520 |
So you know, I think that helps. But I think, you know, when I 01:19:16.440 |
look back, I think I could have handled the barrier much better 01:19:19.000 |
than I did. If I had just been a little bit more, just been more 01:19:22.840 |
positive, you know, early on, it was early on, what do I want to 01:19:26.400 |
say, you know, for a long time, to me, people who were sort of 01:19:29.320 |
Pollyannish were, like, I just would, you know, like, Oh, that 01:19:33.560 |
person's just positive. My role is fake. And now I'm much more I 01:19:38.000 |
tried to be much I tried to be almost fake positive, because 01:19:40.680 |
it's not going to change so much is not going to change anyways. 01:19:43.160 |
Right. So like, yeah, you know, you can control your, like, 01:19:47.080 |
there's a lot of stoicism, I can't handle stoicism, because 01:19:49.920 |
it's often very sort of like, morose. And I just can't be like 01:19:57.240 |
I think also, like, it, like, I've always felt like, the 01:20:03.160 |
internet's a big place, you know, and I always feel like my, 01:20:06.400 |
my job is not to market my weird shit to other people. But to 01:20:12.720 |
find the other people who appreciate my weird shit, and 01:20:15.880 |
let them find me. And so then you end up with a community of 01:20:19.360 |
people who appreciate your weirdness, and you don't have to 01:20:23.880 |
spend time trying to convince people to do something they 01:20:25.680 |
don't want to do. Yeah, well, and that's, you know, I didn't 01:20:28.800 |
know this was gonna work as well as it did. You know, I had, like 01:20:32.360 |
a year ago, we basically, you know, we were gonna release the 01:20:35.960 |
book, and I've been messing around on Twitter a little bit 01:20:38.480 |
more, I'd taken some time off Twitter, because it just gotten 01:20:41.760 |
so crazy. And so, but I came back and I was like, and I about 01:20:46.920 |
a year ago, I committed, I was like, Okay, I'm gonna really 01:20:50.240 |
like, I'm gonna engage on Twitter. And I'm just gonna go 01:20:53.680 |
crazy and be like the crazy person that I want to be on 01:20:56.960 |
Twitter, and have fun with it. And if that works, great. And if 01:20:59.960 |
it all goes down in flames, also great, like, I don't care. And I 01:21:03.920 |
think so, you know, there's probably some authenticity 01:21:07.360 |
there. But there's also a bunch of risks, like, you know, this 01:21:10.400 |
could all end in tears, probably will. But, you know, I just, I 01:21:15.800 |
don't know, I just I really, I tried, you know, I gave that 01:21:18.800 |
talk to big sky DEV CON, where I talked about trying to be more 01:21:21.040 |
positive. And I think that's been the big change for me. 01:21:24.040 |
About 10 years ago, I just was like, I need to be more positive 01:21:27.160 |
about things. Yeah, still be a joker, still be myself. But 01:21:30.560 |
just don't emphasize the negative stuff so much. Don't 01:21:34.960 |
No, I mean, you can find like, you can be you'll continue to be 01:21:38.960 |
authentic whilst finding different facets to highlight 01:21:43.680 |
internally and externally. For sure. Yeah. Yeah. We all have 01:21:48.160 |
those facets. Right? I'm not sure I can recommend what I did 01:21:52.520 |
for other people. But it worked. It worked this one time anyways. 01:21:56.960 |
So, you know, I guess the thing I'd be interested to kind of 01:22:04.080 |
wrap up on unless there's other stuff you feel like is worth 01:22:07.520 |
talking about is like the kind of where to now, you know, if it 01:22:14.040 |
seems to me, you've highlighted how browsers ought to work. I 01:22:20.920 |
don't see any reason they shouldn't work like this. And in 01:22:24.800 |
fact, if this stuff was built into the browser, you wouldn't 01:22:28.880 |
probably need the HX dash pieces, you know, maybe some of 01:22:32.800 |
it could be have a bit of a streamlined developer experience 01:22:37.960 |
in ways that you couldn't do. I guess like, I mean, not that it 01:22:45.400 |
feels like a matter hugely to me, if whether that happens or 01:22:48.560 |
not, I don't mind sticking an HTML script to the top of my 01:22:50.960 |
pages. And in fact, fast HTML adds that script header by 01:22:53.680 |
default. But yeah, I guess I'm curious about like, what's, 01:22:57.400 |
what's in your head now? Are you thinking like, there's other 01:23:03.800 |
things I could do with this? Are you moving on to something 01:23:06.360 |
else? Are you feeling like you know, your, the browsers might 01:23:11.280 |
actually pick up on some of these ideas, you know? 01:23:13.600 |
Yeah, well, I think, I think we'll, I know that the browser 01:23:19.080 |
people are looking at HTMX and are interested in the idea. It's 01:23:22.560 |
a big process to get anything like that into the browser, 01:23:26.280 |
especially coming from more of an external source than sort of 01:23:31.960 |
And also the most important bit, the fourth one, the like, update 01:23:35.240 |
any part of the DOM that feels like it would be hardest to 01:23:38.960 |
Yeah, yeah. So there's, there's already, it's kind of there a 01:23:44.280 |
little bit, you can actually, there's a target attribute on 01:23:47.280 |
anchors and forms. And that takes an ID, but the ID has to 01:23:51.440 |
be of an iframe. So nobody uses it. So there's like, there's the 01:23:56.960 |
infrastructure is there, it's like almost there. So I don't 01:24:00.360 |
think it's, I don't think it's too far of a jump. And one of 01:24:03.200 |
the HTMX team members is working on a more formal proposal to get 01:24:07.080 |
some of these ideas, not the full HTMX API, but some of these 01:24:10.440 |
ideas, and HTML. And you know, I mean, it could happen. That 01:24:14.880 |
would be a very long term process. I do think HTMX is 01:24:18.320 |
pretty much done as far as like what it does, and the API 01:24:21.840 |
provides, if new technologies come out in the browser. So for 01:24:25.880 |
example, the transitions API came out, and we integrated that 01:24:28.720 |
into HTMX. So I would expect to, you know, do some things like 01:24:33.240 |
that, as browser technologies improve, but I don't think HTMX 01:24:37.240 |
is going to change a whole bunch, just fixing bugs and, you 01:24:40.400 |
know, improving it, hopefully not. At this point, I want to 01:24:44.680 |
not ruin it. Like, let's I'll put it that way. So I'm going to 01:24:49.560 |
Yeah, it doesn't feel I mean, that's kind of partly what I was 01:24:51.240 |
asking. It feels like it almost feels like you discovered 01:24:56.280 |
something. You know, you discovered the thing, and you 01:25:00.080 |
should, you know, and then you show the people the thing, and 01:25:02.160 |
then you've written down why the thing's good. And you've 01:25:04.680 |
provided examples of the thing. Like, yeah, dude, where do you 01:25:09.160 |
Oh, man, what's a well, you know, I've got other projects I 01:25:13.720 |
work on. There's, you know, idiomorph, which is sort of a 01:25:16.520 |
DOM morphing algorithm that I think was an improvement over 01:25:20.920 |
Okay, well, let's go slowly here. Okay. So htmx, idiomorph, 01:25:26.120 |
because I know of this thing. But maybe you could like just 01:25:32.480 |
quickly teach me about it. Because it's like, is this like 01:25:38.800 |
when you say a DOM merging algorithm? Is this kind of like 01:25:41.480 |
what Alexia live view does or something like the thumb 01:25:46.000 |
diffing? Like, you should explain maybe from scratch what 01:25:50.400 |
basically, the fundamental problem and the original 01:25:53.840 |
library. Yeah, well, I mean, the original, the original problem 01:25:58.640 |
is, you've got a DOM, which is a tree of stuff. And you've got a 01:26:02.760 |
new tree that you need to take this tree and like, change it 01:26:07.000 |
into this other tree. And you want to do that with as few 01:26:09.760 |
changes as possible. And so that that's called morphing. That's 01:26:15.400 |
you've got that thing with like the Rick Astley video that you 01:26:20.360 |
get playing or something is that that's is that one of these 01:26:23.840 |
Yeah, it's not it's not in the examples. But if you go to the 01:26:27.440 |
bottom of the idiomorph page, there's there's an example that 01:26:30.760 |
shows that. Yes, down there somewhere. So if you watch this 01:26:34.800 |
gif, like that top is what basically what happens is if you 01:26:38.920 |
if you watch the top, top one, the video keeps playing, or the 01:26:43.000 |
top ones resets and the bottom one doesn't. And so like, yeah, 01:26:49.640 |
refreshing. Yeah. And so I don't want to get too much into the 01:26:54.320 |
weeds on this. But basically, idiomorph is an improvement on 01:26:57.400 |
morphdom. It uses something called ID sets to do a better 01:27:00.560 |
job of matching up elements when it's trying to 01:27:03.880 |
add. So basically, I can return a bigger chunk of a bigger HTML 01:27:10.240 |
partial into something where some of what I return is the 01:27:14.720 |
same as what was there before. And it won't actually replace 01:27:17.880 |
what was there. So to be kind of more efficient, it won't update 01:27:21.200 |
Exactly. It doesn't make mistakes higher in the DOM, 01:27:25.000 |
because it has these things called ID sets. So I don't know. 01:27:28.400 |
And then there's and then there's hyperscript. Don't show 01:27:31.520 |
I mean, you say this, because like, you know, a few weeks ago, 01:27:36.240 |
I asked you about this. And I was like, should I learn 01:27:37.960 |
hyperscript? And you're like, no. And that was the end of the 01:27:41.520 |
conversation. And then since then, I've like seen people 01:27:44.560 |
using it. I'm like, wait, this looks amazing. Somebody on the 01:27:47.840 |
discord yesterday had like, literally like a spreadsheet 01:27:51.040 |
written in hyperscript. So I actually want to try it. 01:27:54.480 |
That was pretty incredible. Yeah, so hyperscript is another 01:27:57.760 |
project. And it's basically a scripting language. So it's an 01:28:03.200 |
alternative to JavaScript. And it's based on an old scripting 01:28:08.600 |
language called HyperTalk, which was a scripting language for 01:28:13.520 |
Which is also what AppleScript was based on, you know, same. 01:28:16.680 |
Yeah, AppleScript has given a lot of people a bad taste for 01:28:20.160 |
that style of language, because AppleScript is so bad, which I 01:28:23.440 |
agree 100%. But it's, it has a lot of interesting features. I 01:28:29.760 |
teach compilers, and I like programming languages. And so, 01:28:34.360 |
I enjoyed reading the source code to this, actually, like, 01:28:37.120 |
it's, yeah, it's, yeah, I thought like, okay, I can see 01:28:39.520 |
you're an academic who you probably must teach this shit, 01:28:44.960 |
yeah, it is. Yeah, it's a it's a standard recursive descent 01:28:49.280 |
parser and all that sort of stuff. But you can see like 01:28:51.920 |
these things, it's just like on click toggle disabled until, 01:28:54.960 |
you know, it has a very English like syntax. And then the really 01:29:00.400 |
interesting thing about it, if you go up to the top, go up to 01:29:03.880 |
the where's the nav, or excuse me, go to docs is scroll down 01:29:11.400 |
on the left hand side, go down to us, keep going, keep going, 01:29:15.800 |
what's called keep going. Keep going. Keep going. It's async 01:29:20.800 |
transparency. So if you're, if you're, if you're into 01:29:23.520 |
languages, this is one thing that's pretty interesting about 01:29:26.560 |
HyperScript, which is the it, the way the the runtime works, 01:29:32.400 |
like you don't have to resolve promises, the runtime 01:29:37.040 |
I hate this. So script code, you know, it just makes me 01:29:41.800 |
Right. So instead of like this callback style, or doing a 01:29:46.280 |
wait, you know, there's a if the thing you're working with 01:29:49.240 |
returns a promise, you can do in a wait on it, but then you 01:29:51.360 |
have to mark it as a sink and all the rest of it. Like in 01:29:53.880 |
HyperScript, you just Yeah, in HyperScript, you just you can 01:29:57.240 |
put like, wait one second, and it'll do it does all the stuff 01:30:01.160 |
for you. It like it, it waits for that two seconds, and then 01:30:05.200 |
starts executing the next thing. And so that's a, that's sort of 01:30:10.840 |
a, it's an interesting technical thing. Like, if you scroll down 01:30:14.160 |
a little bit further, there's keep going toggle loops, this 01:30:20.080 |
one. So this scroll up there, that loop, this is a this. So 01:30:24.560 |
one of the neat things about the, the runtime infrastructure 01:30:27.640 |
of HyperScript is that you can have event driven loops. So 01:30:31.400 |
this, this is, this is a loop that's saying loop until you get 01:30:35.160 |
this event. Right. So on click repeat until events stop. And so 01:30:41.080 |
and then send and then there's another button that sends the 01:30:43.520 |
stop event. So if you click on that, click meet a pulse button, 01:30:46.080 |
yeah, it's gonna pulse, and then it'll keep pulsing until you 01:30:50.800 |
click cancel. Yeah. Which is when you click cancel event to a 01:30:55.360 |
particular element. Yeah, to the previous button. And so it's 01:30:59.160 |
sending it to that button. And what's interesting there is that 01:31:01.840 |
if you watch the pulse, it finishes it, the pulse finishes. 01:31:06.240 |
And that's because it that's because it's in this loop, that 01:31:12.040 |
only after the loop is finished as a check, did I receive the 01:31:14.920 |
stop event. And so it's like, it's event driven control flow, 01:31:18.680 |
which is pretty interesting, like when you're working with 01:31:21.280 |
the DOM. So I don't know, this is definitely a passion project, 01:31:24.440 |
I have a hard time recommending any, anyone watching this or 01:31:27.880 |
listening to this, check it out. But it's got some cool ideas in 01:31:30.840 |
it. I know those kinds of projects, like I, I'm a bit the 01:31:34.480 |
same with nbdev. You know, when people are like, should I use 01:31:37.560 |
nbdev? I'm like, I don't know. I'm like, I like it a lot. I've 01:31:42.000 |
written all my software for the last few years. And that, you 01:31:45.040 |
know, people keep asking me, how come I'm so productive? And I'm 01:31:47.640 |
like, I think a lot of us because of nbdev. But should you 01:31:49.960 |
use it? Oh, I don't know. It's pretty weird. Everybody's gonna 01:31:53.640 |
think you're weird. Yeah. Right. It's funny, though, like, you 01:31:58.000 |
know, this kind of parsing compiling stuff. I happen to 01:32:02.200 |
have been lucky enough to have a few friends in my life who, you 01:32:05.080 |
know, have, who are amongst the best in the world. They're like 01:32:08.040 |
Terence Parr, who created Antler, was a colleague at the 01:32:11.000 |
University of San Francisco, and Chris Lattner, obviously, and 01:32:14.560 |
then years ago, I, back in the Perl days, I used to spend some 01:32:17.320 |
time with Damien Conway on Perl. It's such an interesting space, 01:32:23.360 |
you know, like, like, getting down to the hardcore of these 01:32:27.480 |
algorithms, and then implementing a language. It must 01:32:29.840 |
have been super fun for you just to make this. Yeah, yeah, for 01:32:34.680 |
sure. And it's all written in JavaScript. So the parts, it's 01:32:37.880 |
all it's all in JavaScript, which is going to be a little 01:32:41.960 |
bit dodgy, I guess, like it has to. I would not write a Yeah, I 01:32:46.680 |
would not write a Bitcoin miner in it for sure. But I think for 01:32:50.680 |
what is designed for, like little interactive elements, 01:32:53.400 |
like where you embed the code, like it's designed to be 01:32:55.800 |
embedded in HTML, like it's supposed to be and very readable. 01:33:00.160 |
Like, that's one thing there's an essay, I think, what, there's 01:33:04.120 |
an essay on the HTMX website about that about, I think it's 01:33:07.920 |
right click view source extremism, I think is what I 01:33:10.960 |
call it. Hold on, hold on. It's that last one. And so this is a 01:33:17.800 |
kind of riffing on something like Cory doctora, who's a real 01:33:20.920 |
good writer. Yeah, right about guys very passionate about the 01:33:23.680 |
web. Yeah, yeah, 100%. And he talked about how, like the early 01:33:28.880 |
web, you could always look, you could be like, one of the 01:33:31.200 |
reasons why the web was so great is you could, if you saw 01:33:33.520 |
something cool, you could right click and view the source and 01:33:35.520 |
see what was going on. Yeah. And, and so that's one thing 01:33:39.640 |
that I think HTMX and Hyperscript kind of have that. 01:33:43.040 |
Yeah, like, I believe in that ethos, though, like, exactly. 01:33:46.520 |
It's not open source. It's not open source. It's view source. 01:33:50.720 |
It's no, no, exactly. Yeah. And in fact, you know, I really kind 01:33:55.080 |
of leaned into that with, like, one of the things I created for 01:33:59.440 |
fast HTML is like, I really love being able to like, even just 01:34:03.280 |
view, you know, view HTMX or HTML or whatever source. And so 01:34:08.280 |
one of the things I kind of show people in our very first video 01:34:10.720 |
is this idea of like, copy outer HTML, paste it into HTX. And now 01:34:16.800 |
you've got, you know, the fast tag tag ready to go. It's like, 01:34:20.240 |
I really wanted people to be able to grab stuff that's out 01:34:24.920 |
Yeah, yeah, there's something that we've definitely lost in 01:34:27.800 |
the web now that everything's like a huge massive, you know, 01:34:31.600 |
either it's a bunch of like, you know, if you want to cry, like 01:34:34.480 |
go and look at go to google.com and right click view source, and 01:34:38.880 |
then go to the Wayback Machine. Oh, I know. And go to google.com 01:34:42.720 |
and like 2002 and view the source of that. And it's just 01:34:46.080 |
like, guys, what are we doing? You know, like, it's just crazy. 01:34:50.880 |
Say that the current I don't find the current Google a better 01:34:54.400 |
experience to use than that's not I mean, it's a little better 01:34:57.760 |
in some ways. But you know, I do I do like the, the openness and 01:35:03.120 |
that's one of the reason I'm on this kind of riff is just 01:35:06.480 |
because Hyperscript is designed to be part of that. Like, yeah, 01:35:09.520 |
you put the code in, you put the code directly in there. And you 01:35:13.480 |
know, there's another one, I don't know if you've tried it 01:35:15.080 |
at all. Which is a surreal JS, which is actually what what I 01:35:20.200 |
am after you convinced me not to use Hyperscript. Yeah, I don't 01:35:24.680 |
know. It's almost as weird, but not quite. But it's a similar 01:35:28.040 |
idea. Yeah. So there's this like nice example here. Yeah, you 01:35:36.360 |
know, where you can inspect these things. And yeah, they're 01:35:42.840 |
just like, right there. And it's just, yeah, it's just a script 01:35:45.720 |
tag right next to the thing. Yeah, yeah. And, you know, also 01:35:50.280 |
this really beautiful CSS, like, not like this is 320 lines, you 01:35:56.520 |
know, yeah. And then the CSS one is like 50 lines or 40 lines or 01:36:00.360 |
something. But it's like, yeah, in many ways, it takes tailwinds 01:36:04.520 |
us, you know, you just have like me, yeah, in your styles. And 01:36:08.680 |
then it works really well with the fast HTML approach that we 01:36:15.240 |
were trying to create Python components, you know, where it's 01:36:18.360 |
just Python functions, and the Python functions are self 01:36:20.760 |
contained. And so with something like HTMX, or with the surreal 01:36:24.600 |
approaches, you know, everything is like, you don't need web 01:36:28.680 |
components anymore, because right, the servers generating 01:36:32.600 |
the components. So I'm really in that direction. 01:36:37.080 |
Yeah, I think it's a good one. I it's, you know, and that's a 01:36:39.800 |
quick, I mean, I guess, like, maybe a last question for you 01:36:42.040 |
is, how's, how's fast HTML treating you? So you got a 01:36:45.320 |
couple of negative content, it's always easy to focus on the 01:36:47.960 |
negative stuff. But I've seen a tremendous amount of positive 01:36:50.360 |
stuff, too. So yeah, it's been less than a week. Let's see, 01:36:58.280 |
we've got 2.7 1000 stars on GitHub. So it's like people 01:37:02.760 |
definitely gravitated to it. It was number one on Hacker News. 01:37:06.120 |
Yeah. The reaction has been, yeah, it's interesting. Like, 01:37:13.480 |
we get I get reactions to a few different things, right? So 01:37:17.160 |
like, a lot of the people reacting to fast HTML aren't 01:37:19.640 |
reacting to fast HTML at all. But actually, like, so for 01:37:24.440 |
example, I use a different programming style guide, which 01:37:32.120 |
I wrote fast AI style, instead of the one that most, pretty 01:37:35.160 |
much everybody else uses called pep eight. Okay. And it's based 01:37:38.360 |
on like, literally 60 years of study, you know, in other 01:37:41.880 |
communities, like, it's not bad, right. But because people see 01:37:46.040 |
my code looking different to what they used to, a lot of 01:37:47.880 |
people just react like, this code is wrong, or it's bad, you 01:37:53.160 |
know, although the other thing I've seen people react to is, 01:37:57.800 |
like, wait, it's 91% Jupyter notebooks, it's actually worse 01:38:03.160 |
than that, because the other 8% is auto generated. Like, yeah, 01:38:07.320 |
it's like, it looks wrong. It's written wrong. It's written in 01:38:09.720 |
the wrong system. So you know, I get a lot of that. 01:38:12.520 |
I did. I get some of that too, with HTML. So yeah, doing it 01:38:20.280 |
And then people are like, well, you know, you're never going to 01:38:24.680 |
be able to create something that looks nice with like tailwind 01:38:27.800 |
and stuff like this, you know, and I'm like, dude, this is like 01:38:30.600 |
a fast HTML application right here. You know, it's, here's a 01:38:37.880 |
great example. This thing here is like something that wrote, 01:38:40.760 |
like a standalone thing. And then now that we've got it, you 01:38:44.600 |
know, it's just like card 3d. There it is. And this is like, 01:38:49.480 |
there's some things where I just, it's a bit like what 01:38:51.720 |
you're seeing with HTMX, but to a lesser extent, where like, 01:38:55.960 |
this one. So this is actually the current temperature. And 01:39:01.000 |
it's like, well, how the hell are we getting the current 01:39:02.760 |
temperature on the homepage of a really popular website? You 01:39:06.440 |
know, and the cost of running this, you know, including the 01:39:14.440 |
entire launch on Hacker News and all that is like, yeah, you 01:39:22.120 |
know, it's gonna cost 20 bucks, right? Three bucks so far. 01:39:27.320 |
It's and the trick is that I just used Python, right? And 01:39:33.000 |
this is this function actually has a cache on it. And, and 01:39:37.400 |
then I realized like, well, actually what so the normal 01:39:39.400 |
Python cache basically is just like a memoization cache. So 01:39:46.600 |
it's like an LIU cache. So like, I wrote this tiny thing 01:39:51.320 |
called flexi cache. You know, like everything I write Carson 01:39:57.240 |
is just like tiny, right? So this is like one of the biggest 01:40:01.880 |
functions I've ever written is like 30 lines of code. But with 01:40:06.200 |
this cache, you can then say, you can basically define these 01:40:09.320 |
things are called policies. So here's a policy cache, which is 01:40:13.560 |
just like, Oh, let's check the time, you know, and you either 01:40:17.160 |
return none if it's still in cache, or you return the new 01:40:19.880 |
cache time, you know, you know, whatever state you need. So 01:40:23.240 |
there's an end time policy. So like, we have, I basically 01:40:27.240 |
replaced static site generators now, because I just returned 01:40:30.440 |
file responses with an end time policy cache. So like, it 01:40:33.640 |
literally gives you auto reload if the file changes, you know, 01:40:38.040 |
that thing is showing if the weather has like a one minute 01:40:40.280 |
time policy cache on it, and it's just a decorator on the 01:40:42.680 |
function. And so now, you know, this, you know, just updates 01:40:46.920 |
itself once a minute. So it's like using all of Python, 01:40:50.440 |
really, it just feels great. So yeah, so to answer your 01:40:55.640 |
question, you know, this kind of new generation of JavaScript 01:41:02.120 |
only programmers, you know, there's quite a common reaction, 01:41:05.240 |
which is like, you can't do all these things. It's like, you 01:41:09.800 |
know, Instagram's written in Python, Dropbox is written in 01:41:12.840 |
Python, like, it can definitely create whatever application you 01:41:16.440 |
have in your head. Yeah. But then there's this fantastic 01:41:20.840 |
group of like, very experienced coders, who have like, come in 01:41:27.880 |
to our like, Discord channel and just been like, this is the 01:41:32.120 |
thing, you know, so like, for example, Audrey and Daniel, I 01:41:34.760 |
mentioned these fantastic authors, and you know, really 01:41:37.320 |
great web developers. Within like, two days of checking it 01:41:41.240 |
out. Not only had Audrey won a hackathon, they're like, we want 01:41:45.480 |
to fly to Australia to spend two weeks working on this with 01:41:48.440 |
you, please. Wow, they're going to be coming like next week or 01:41:51.240 |
the week after, we're just going to hang out here in my 01:41:53.080 |
backyard, man. Yeah. So like that kind of reaction of people 01:41:58.120 |
who I really respect, who just go like, yeah, I want to focus 01:42:02.840 |
on this as my work for a while. And they're reacting a lot to 01:42:10.200 |
HTMX. Do you know what I mean? Like, I feel like what we're 01:42:12.440 |
doing is we're providing this surface to allow people to 01:42:18.040 |
create hypermedia applications. Right. You know, and it's just 01:42:24.200 |
cobbling together like the idea of functional components that 01:42:27.400 |
goes back a long time in like, OCaml, Haskell, Elm, of course, 01:42:32.280 |
history, you know, then the, you know, the HTMX approach, you 01:42:37.000 |
know, the, the ASGI approach of like simplifying HTML a whole 01:42:41.400 |
lot, just kind of like cobbles together these things. And like 01:42:46.200 |
the whole thing's like 100 lines of code, you know, and HTMX is 01:42:49.880 |
pretty small as well, I think, right? The implementation. 01:42:52.600 |
Yeah, it's well, I think it's, it's 4000 lines of code now, or 01:42:57.240 |
maybe even 5000, because we added so many type annotations. 01:43:00.680 |
I think if you looked at like actual lines of code, it's just 01:43:03.640 |
I don't know, man. Okay, whatever. It found zero bugs, by 01:43:07.160 |
the way, but it's gonna say I don't do type annotations in 01:43:10.360 |
Python, because I've, yeah, we've got a pretty good test 01:43:14.280 |
suite. So but it's all it's fine. It's all good. People want 01:43:17.560 |
it. And now they've got it. So but, but it is, you know, yeah, 01:43:22.520 |
I think if you boiled it down and sort of into normal code, I 01:43:27.240 |
bet it's a couple 1000 lines of code. Yeah, you know, and I 01:43:30.520 |
don't write the most efficient, like lines of code style code, 01:43:34.680 |
I tend to write very plotting code were at this point. So but 01:43:40.600 |
yeah, you know, I, you say it's only 800 lines of code, but 01:43:43.960 |
obviously, it's 800 lines of code to do the right thing or a 01:43:47.720 |
lot better than 100,000 lines of code that does the wrong thing. 01:43:51.320 |
So that's one of the one good thing about getting kind of old 01:43:54.520 |
is you start realizing what the right thing might be. 01:43:57.000 |
Well, exactly. And you suddenly discover these people who have 01:43:59.400 |
built, built the right thing, like when I came across surreal 01:44:02.440 |
JS, and I was like, Oh, yeah, self contained components. It's 01:44:06.840 |
almost like a kind of discovery again, if like, oh, there's 01:44:09.560 |
these things that when you put them together, it creates 01:44:14.040 |
something delightful, you know, and combine well, yeah. So I've 01:44:20.760 |
created all these little apps now. So like this thing of the 01:44:23.880 |
other day, I was like, I was on the plane. And so I started 01:44:27.240 |
writing a blog post in Microsoft Word, you know, and I was like, 01:44:29.960 |
okay, I want to convert this to Markdown. And I was like, okay, 01:44:34.520 |
I can't find anything that does a great job of converting it to 01:44:36.600 |
Markdown. I write a fast HTML app to convert it to Markdown 01:44:40.280 |
that took me like, two hours, you know, chuck it up on the web. 01:44:44.680 |
And I found like, this obscure little JavaScript library 01:44:48.280 |
somebody had used. So I basically hooked up with HTMX, 01:44:51.320 |
you know, I used HX spells, which lets you call JavaScript 01:44:55.880 |
kind of before it passes it back to your handler. And so I was 01:45:00.120 |
able to that way, get this JavaScript client side cleaned 01:45:02.680 |
up thing. And then I used a Python Markdown converter, and 01:45:07.720 |
then use that to update. And I it's kind of funny, though, the 01:45:11.480 |
the way I actually had it set up is that you paste into this 01:45:14.440 |
text box. The on paste event basically is the thing that 01:45:19.480 |
causes the handler to happen. So it actually pastes the 01:45:23.480 |
Markdown. So it's kind of this weird UI experience of like 01:45:27.960 |
literally copy from Word and paste and the Markdown. So yeah, 01:45:34.200 |
so I kind of create all these little things and they just feel 01:45:36.280 |
good. And I think like, yeah, this is this is the right way to 01:45:41.160 |
Well, it's really good that it's scratching your like the 01:45:45.720 |
fact that you're using it. And it's not just you kind of 01:45:48.760 |
inventing this tool for the world. You know, I think my 01:45:51.160 |
team loves it too. Like my friend Jono, he wrote this 01:45:54.120 |
thing called Moodle. It's so fun. And like, so he's somebody 01:45:58.040 |
who spends all his weekends like tinkering with I don't know 01:46:01.640 |
robots or art or whatever. He's a inveterate tinkerer. And 01:46:06.040 |
nowadays, it's a good sign that he always wants to tinker with 01:46:09.640 |
fast HTML. So he wrote this thing called Moodle, where you 01:46:13.880 |
go to the site, and it gives you basically a Pictionary type 01:46:16.840 |
word you have to draw. You start drawing it and then there 01:46:20.040 |
are three different language, three different language models 01:46:22.680 |
running in the background that are trying to guess what you're 01:46:24.520 |
drawing. And as soon as one guesses correctly, you're done. 01:46:28.680 |
And so there's like a leaderboard. It's all HTML based, 01:46:32.120 |
you know, of like, who managed to reach word get it done the 01:46:34.600 |
fastest, right? And again, it's combining like canvas and you 01:46:39.000 |
know, all these things with like, oh, HTML can't do that. 01:46:45.160 |
You know, it does the job. But exactly. And it's it's not that 01:46:48.920 |
he like he makes isn't trying to do all that, right? It's there 01:46:52.040 |
to work with canvas and with you know, JavaScript and whatever 01:46:55.320 |
else it needs to work with. Yeah, we get our leaderboard and 01:46:58.040 |
we get our like, you know, and we're using the WebSockets 01:47:01.400 |
thing, which is nice. And I'm about to dig into the server 01:47:05.960 |
side events extension. That looks nice as well. Yeah. Yeah, 01:47:09.480 |
server side events. Those are, you know, two extensions Web 01:47:12.360 |
Sockets and server side events. I like the server side events 01:47:14.920 |
one. It's read only. So as long as you're just consuming stuff, 01:47:18.040 |
it's good for language models that stream the results back to 01:47:21.960 |
you. So you basically read it until it's finished. Totally. 01:47:24.520 |
A lot of that, you know, being able to use that depends a lot 01:47:28.600 |
on what your server side environment gives you too. So 01:47:31.480 |
you know, if, if there's good support for it, using whatever 01:47:34.440 |
your server side environment is, then you can, you can take 01:47:37.560 |
advantage of them. Yeah, no, I mean, with ASGI, it's all like 01:47:40.040 |
async Python. So everything works. Yeah, pretty cleanly. I 01:47:43.480 |
mean, not as cleanly as the HyperScript example that you 01:47:47.320 |
showed. Sure. The other thing I like about with these things 01:47:49.560 |
like WebSockets or server side events or whatever is this idea 01:47:52.440 |
of like, oh, you want to like stop the connection as like, 01:47:57.320 |
well, you literally just return a new DOM element that doesn't 01:48:00.920 |
have a WebSocket, you know, attribute in it anymore. Like 01:48:05.240 |
it's like, yep. When you got a hammer, everything's a nail. 01:48:08.680 |
Well, kind of in HTMX, everything is a nail. You know, 01:48:11.240 |
it's like, everything's a div. No, no, no, I'm kidding. 01:48:14.280 |
DOM elements. Everything's a DOM element. Not a div, but 01:48:18.520 |
yeah. Yeah, I, you know, again, I feel like just what you said 01:48:23.320 |
originally, like it's more, I discovered this than anything 01:48:25.720 |
else. And it does, it works for a lot of stuff, you know? And 01:48:29.960 |
if you're, you know, like, it sounds like what you got, you 01:48:31.800 |
guys are approaching it the right way, which is, I'm not 01:48:34.120 |
going to try and make HTMX do stuff it's not good at. I'm 01:48:38.360 |
going to instead, I'm going to integrate with HTMX via events. 01:48:41.560 |
And that's what I try to tell people. That's what in my mind 01:48:44.280 |
makes someone a good HTMX developer is if they get that, 01:48:48.680 |
okay, like start thinking in advance, and I've got these 01:48:51.480 |
other tools that I want to integrate. Now, how do I 01:48:53.960 |
integrate them cleanly? Hopefully they have a good 01:48:56.040 |
event model, or maybe I have to impose one on top of it or 01:48:59.080 |
something like that. So maybe I should think that's the right 01:49:01.400 |
I should talk to you sometime about my coming up plans. I'm 01:49:04.760 |
hoping to actually create a kind of like web programming from 01:49:08.280 |
scratch course. And I've actually now created this whole 01:49:11.160 |
thing where I like literally it's a notebook that starts 01:49:13.400 |
with a socket handler and builds up HTTP and then builds 01:49:18.120 |
up ASGI. And, you know, I'm really hoping that a lot of 01:49:23.480 |
people will understand the pleasure of this style of web 01:49:27.640 |
development. I also want to introduce people to things like 01:49:30.600 |
pay five bucks a month to run your own VPS that you SSH into 01:49:34.200 |
and you deploy things by r syncing to it. And, you know, 01:49:37.160 |
yeah, it's a, it's a bit of a superpower, I think, to have 01:49:42.840 |
It is. Absolutely. I'm teaching, I'm teaching a class at MSU this 01:49:47.240 |
fall on hypermedia. And so I'll be teaching sort of similar 01:49:51.800 |
Will you have a chance to record any of that? 01:49:54.360 |
Or, you know, I've got to I've got to talk to the department. 01:49:57.560 |
But maybe alternatively, you know, we can do something 01:50:02.840 |
together where you could show some of your slides if you're 01:50:10.600 |
Yeah, no, I'll I'll I need I just want to I need to right 01:50:14.840 |
now it's summertime. So everyone's gone and no one 01:50:16.920 |
responds. But, but I'll talk to him as soon as everyone they 01:50:23.160 |
Well, Carson, I really appreciate it must be getting a 01:50:25.320 |
little late in the evening for you. So I feel like it's not too 01:50:30.360 |
bad. I've learned a lot. And I feel like I've hopefully helped 01:50:33.640 |
other people learn a lot. Yeah, is there anything else you 01:50:36.360 |
wanted to say or ask or anything before we wrap up? 01:50:40.840 |
No, I just, you know, congratulations on the launch. 01:50:43.080 |
And I really appreciate, you know, your support. 01:50:45.160 |
And like I said, you're unembarrassed by it, because I 01:50:48.520 |
feel like all I'm doing is showing people what you already 01:50:50.920 |
made. So I hope I don't get, you know, obviously, that's not 01:50:54.440 |
true. But, you know, the I think the Python community has been a 01:50:59.720 |
big source of, you know, HTML, people excited about HTML, 01:51:03.640 |
because they can stay in Python. And so, you know, I'm just I'm 01:51:08.360 |
excited to see what you guys are, what you guys are going to 01:51:10.680 |
be able to do with this tool looks really, really neat.