spotifyovercastrssapple-podcasts

elm-spa v6

Ryan Haskell-Glatz joins us to discuss the latest version of elm-spa, including authenticated pages and the updated file-based router.
July 19, 2021
#35

Key new features in v6

Protected pages

Transcript

[00:00:00]
Hello, Jeroen.
[00:00:01]
Hello, Dillon.
[00:00:02]
And today we've got another guest joining us, Ryan.
[00:00:05]
Ryan, thank you so much for joining.
[00:00:06]
Ryan Haskell Glotz, the author of Elm SPA.
[00:00:09]
Hello, everybody.
[00:00:10]
Thanks for having me.
[00:00:11]
Welcome.
[00:00:12]
Very excited.
[00:00:13]
Elm Radio.
[00:00:14]
Elm Radio, boys.
[00:00:15]
And we talked about Elm SPA v5, and well, now we get to talk about v6 with you, which
[00:00:25]
I'm excited to hear it straight out of the horse's mouth.
[00:00:30]
Since we defined Elm SPA in the last episode, why don't you give us your definition?
[00:00:37]
What is Elm SPA?
[00:00:39]
Yeah, so Elm SPA, it is, I guess it's a framework for making single page apps with Elm.
[00:00:45]
So most people will tell you like, oh, Elm doesn't need a framework.
[00:00:48]
It's got the Elm architecture.
[00:00:49]
So it's not a framework like React or Vue would be to JavaScript.
[00:00:53]
It's more of a framework like Next.js or Nuxt.js, if you're coming from the Vue community, is
[00:00:59]
to Vue or React.
[00:01:01]
So yeah, so it kind of makes it easy to get your routing set up, kind of pass data between
[00:01:07]
pages, like choose how complicated a page needs to be, that kind of thing.
[00:01:12]
For people that are new to Elm, that can be really nice.
[00:01:16]
Yeah.
[00:01:17]
Yeah, it is really nice.
[00:01:18]
I think a lot of people are really enjoying v6 and the changes you've made there too.
[00:01:24]
So what are the headlines to you?
[00:01:27]
What are the most important changes in v6 in your mind?
[00:01:31]
So I think one of the flashier features of v6 is user authentication.
[00:01:37]
Previous API user authentication required a lot of like custom code, and it wasn't really
[00:01:41]
supported by the framework.
[00:01:42]
I kind of left it to the developers to be like, hey, like you can do it.
[00:01:46]
You can figure this out.
[00:01:47]
I'm leaving you.
[00:01:48]
Exactly.
[00:01:49]
You got to have faith in the people.
[00:01:51]
But what it turned out to be was a lot easier to just have a few primitives in place.
[00:01:56]
The current state of v6 user authentication, you can kind of say like, hey, a page can
[00:02:01]
be protected.
[00:02:02]
You can get upgraded to a protected page.
[00:02:04]
And from there you can say like this page will always have access to a user or a token
[00:02:08]
or whatever you need for authentication.
[00:02:10]
In your case, you kind of define your own value that you care about getting to those
[00:02:13]
pages and you have like the guarantee that it's there.
[00:02:16]
You can basically just have a check saying like, hey, if the shared model doesn't have
[00:02:20]
a user, then I'm going to redirect to a sign in page.
[00:02:23]
If it does, then I'll allow the page to be rendered.
[00:02:26]
That kind of thing.
[00:02:27]
Okay.
[00:02:28]
And people can define their own authentication system?
[00:02:29]
Exactly.
[00:02:30]
Yeah.
[00:02:31]
They can use JSON web tokens or whatever they're used to.
[00:02:33]
As long as that value can be stored in some way, that's the way to go.
[00:02:38]
So I think the most popular examples are API tokens and JSON web tokens and stuff like
[00:02:43]
that.
[00:02:44]
Right.
[00:02:45]
And the way that API works is you return this LMSPA protected type, which can either provide
[00:02:55]
some value or it can redirect.
[00:02:57]
Is that right?
[00:02:58]
Yeah.
[00:02:59]
Yeah.
[00:03:00]
So there's basically a custom type that has two options.
[00:03:02]
I'd be kind of exploring maybe there's some extra options that people in the LMSPA users
[00:03:07]
channel and Slack have brought up.
[00:03:09]
Just like wait and do nothing might be one that's good.
[00:03:12]
I still kind of have to explore that.
[00:03:13]
But yeah, at a high level, you have like one spot in your app, one file called auth.elm
[00:03:18]
and you define a single function that takes in like the shared state and the current request.
[00:03:23]
And from there returns a custom type value.
[00:03:27]
So it's either provide page width and you give it the thing that you're interested in
[00:03:30]
passing through, or you give it redirect to, and then you give it a route.
[00:03:34]
So kind of like a URL, like a type safe URL.
[00:03:36]
Right.
[00:03:37]
Yeah, that's very cool.
[00:03:38]
It's kind of like a parse don't validate type idea.
[00:03:41]
It seems like that you're making sure that you have this data.
[00:03:45]
And if you do, you're guaranteed to get that nice typed validated data.
[00:03:50]
Otherwise you go to a different page.
[00:03:52]
Yeah.
[00:03:53]
And you don't have to re validate the user every time you want to access it.
[00:03:57]
Yeah.
[00:03:58]
Right.
[00:03:59]
If logged in all over the place.
[00:04:01]
Yeah, exactly.
[00:04:02]
Yeah.
[00:04:03]
That was a big pain point in v5 because it kind of made people implementing pages have
[00:04:07]
to use this weird model underscore.
[00:04:09]
We kind of have like the real model and then the model that the framework's expecting and
[00:04:13]
it was really messy.
[00:04:14]
But yeah, in the latest version, that's nice and clean.
[00:04:16]
So I'm happy with it.
[00:04:17]
And it actually came from a friend of mine.
[00:04:20]
I tried to convince to use Elm as we all do.
[00:04:23]
He was working on kind of like a Spotify app and he's like, how does user authentication
[00:04:28]
work?
[00:04:29]
And I was like, oh, you just do this, this, this, this, this, and this.
[00:04:32]
And I'm like, this is a horrible explanation.
[00:04:34]
There's got to be a better way.
[00:04:36]
Right.
[00:04:37]
And a lot of the motivation is like kind of shame driven development, right?
[00:04:40]
Or you're like, if it's hard to explain it, it's like, maybe that's not such a good design.
[00:04:44]
Explanation driven development.
[00:04:45]
Yeah.
[00:04:46]
So shout out to my buddy, Drew.
[00:04:50]
He was the first test runner and is the reason that the user authentication model is not
[00:04:54]
painful.
[00:04:55]
And does he use Elm now?
[00:04:56]
Yeah.
[00:04:57]
So he's kind of working on a side project.
[00:04:59]
He wants to make a Spotify app called Boombox.
[00:05:02]
That's so you just kind of share your music locally.
[00:05:04]
I just kind of see what people are listening to in your area.
[00:05:06]
So that's his thing.
[00:05:07]
He's using it for cool.
[00:05:09]
Yeah.
[00:05:10]
He was the first LMSPA v6 user.
[00:05:12]
Oh, nice.
[00:05:13]
Alpha, alpha, beta, beta, alpha.
[00:05:14]
Yeah.
[00:05:15]
I love that.
[00:05:16]
Like, I mean, you can really tell that these v6 changes were from real world usage.
[00:05:23]
Yeah, it's, it's, it's cool to see the transformation as, as you've sort of learned these things.
[00:05:28]
And so like another, another feature that's really interesting in v6 is the eject workflow.
[00:05:35]
And I found that that to me seems really unique.
[00:05:38]
Like I don't think I've seen any other frameworks using something like that.
[00:05:41]
Is that something you came up with or was it inspired by a different frameworks approach
[00:05:46]
or how did that come about?
[00:05:47]
Yeah.
[00:05:48]
Well, I'm glad it looks authentic.
[00:05:50]
I stole it.
[00:05:51]
I stole it from a view press.
[00:05:52]
So, yeah.
[00:05:53]
So they have this, I am, I'm a huge fan of any tool that when you get started, it just
[00:05:59]
gives you like one or two files to look at.
[00:06:01]
Okay.
[00:06:02]
Like I'm new to the framework, I'm new to the whatever.
[00:06:04]
So with LMSPA and in our case, it's three files you start with.
[00:06:07]
You start with the LM JSON file.
[00:06:09]
You start with the homepage, which is just like a view function that says hello world.
[00:06:13]
And you start with an index HTML, which is like the entry point to your app.
[00:06:16]
With view press, it was a similar situation.
[00:06:18]
So how they used it was for customizing your theme.
[00:06:22]
So for anyone not familiar with view press, basically it's a way to make like a quick
[00:06:27]
doc site.
[00:06:28]
If you look at Aaron Vonderhaar's program test documentation site, he's actually using
[00:06:34]
view press.
[00:06:35]
You'll start to see the CMF where it's kind of like the new Git book, I guess, where you
[00:06:39]
kind of recognize the theme.
[00:06:41]
But if Aaron chose to customize his theme, he would eject like the default theme.
[00:06:47]
And then from there, view press would give him control.
[00:06:49]
So this, the ejection feature in LMSPA, there's like a lot of things that you might want to
[00:06:53]
customize like the main.elm file.
[00:06:56]
Maybe you want to add a top level message or the not found page.
[00:06:59]
You know, that's pretty common one.
[00:07:01]
But the idea is when you get started, you don't really need to look at all these files
[00:07:05]
at once.
[00:07:06]
So it's nice to be able to kind of incrementally introduce you to the different things as you
[00:07:11]
need them, as opposed to say like, Hey, there's like seven things you can ignore these five,
[00:07:15]
like look at these two and try to convince someone that it's like, it's okay.
[00:07:18]
Like, don't be scared about these five files that, you know, have a hundred lines of code
[00:07:22]
that you might not have read before.
[00:07:24]
Right.
[00:07:25]
And then if you like, like if you wanted to use vanilla elm HTML and have like title equals
[00:07:31]
title body equals list of HTML, then you don't need to eject view.elm.
[00:07:37]
Exactly.
[00:07:38]
But if you wanted to customize that, then you, you literally just move the file from
[00:07:44]
the dot LMSPA slash default folder called view.elm into your source directory.
[00:07:51]
Exactly.
[00:07:52]
Yeah.
[00:07:53]
And then you could use Elm CSS, Elm UI, and there's like examples for how to do that on
[00:07:56]
the repo, but that's the idea.
[00:07:58]
That's super clean.
[00:07:59]
I like it.
[00:08:00]
Yeah.
[00:08:01]
So do you expect users to eject all the files at the end of their project?
[00:08:05]
And but yeah, it never ends.
[00:08:08]
Yeah, no, I don't, I don't expect anything like that.
[00:08:12]
I think, I think the main dot Elm file can really hang in there for a while.
[00:08:16]
For example, if you're not using authentication, you never did the auth.
[00:08:18]
It's really on a project by project basis and like how far it needs to go.
[00:08:22]
So if you still have files in the defaults folder, if you're out there, you're, you're
[00:08:26]
a very good developer still.
[00:08:27]
It's not no shame on you.
[00:08:28]
Like it's, it's totally cool.
[00:08:30]
I don't think I have ejected main dot Elm in any of my side projects.
[00:08:35]
The LMSPA website is built with LMSPA cause that's meta and exciting.
[00:08:39]
I don't believe that one has a main dot Elm file.
[00:08:42]
Oh, it does.
[00:08:43]
I lied.
[00:08:44]
It doesn't have auth and it doesn't have a view ejected.
[00:08:47]
Does that mean you're a bad developer now?
[00:08:48]
I'm a bad developer regardless of what I've done.
[00:08:54]
But yeah, good question.
[00:08:56]
So the, so LMSPA handles or generates all those files while you haven't ejected them?
[00:09:02]
Yes.
[00:09:03]
Yeah.
[00:09:04]
So it basically checks to see if the files, these specific files, there's about six of
[00:09:09]
them exist in your source folder.
[00:09:11]
And if they do not, it will generate them for you by default.
[00:09:14]
Okay.
[00:09:15]
And what does LMSPA do once you've ejected them all?
[00:09:18]
It just doesn't generate anything.
[00:09:19]
So it just trusts that the code that you've chosen, you need to customize will do that.
[00:09:23]
Besides the other code generation that LMSPA will do like routing and all that stuff.
[00:09:27]
So these, these six files are separate from like the routing system and separate from
[00:09:31]
like the URL parameter wiring up stuff that, that you get with the project.
[00:09:36]
That's probably the big thing that LMSPA does that we haven't talked about, which is that
[00:09:41]
automatic routing based on the file structure.
[00:09:44]
Do you want to talk about that?
[00:09:45]
I'd love to.
[00:09:46]
Yeah.
[00:09:47]
That sounds good.
[00:09:48]
So I also stole this idea from plenty of things.
[00:09:52]
I know like if you're in the C sharp ecosystem, like.NET MVC uses this, React.
[00:09:58]
Personally I took this from Vue's Nuxt.js project.
[00:10:02]
I was a big Vue developer before I encountered Elm.
[00:10:05]
I still love Vue.
[00:10:06]
I think it's, I think it's great saying I love Vue because it always sounds, sounds
[00:10:10]
very direct to the listener.
[00:10:12]
I love Vue.js as well as you.
[00:10:17]
But yeah, they, they have this really awesome framework called Nuxt where you basically
[00:10:21]
just create files in a certain folder.
[00:10:24]
And from that, the app can tell like what routes you want that you don't have to wire
[00:10:27]
up any routing code yourself.
[00:10:29]
So for example, if you want a homepage in LMSPA, you just put a new file called home
[00:10:34]
underscore dot Elm in the pages folder and that would automatically be wired up as your
[00:10:38]
homepage.
[00:10:39]
The docs cover this in more detail, but you've got, you know, static support for like static
[00:10:43]
things like, you know, slash people.
[00:10:44]
You can also do dynamic things like slash people slash Dillon or slash people slash a
[00:10:49]
Jeroen or, you know, whatever, whatever you have.
[00:10:51]
And that's, that's all covered in the documentation.
[00:10:53]
But the idea is you don't need to go like looking for a certain page file.
[00:10:58]
You always know where to find it based on the URL structure in the browser, which is
[00:11:01]
nice.
[00:11:02]
Right.
[00:11:03]
There's a clean mapping.
[00:11:04]
Yeah.
[00:11:05]
Yeah.
[00:11:06]
It's also very nice that every page and every route has a kind of like a main function because
[00:11:10]
it reduces all the boilerplate that you need to write.
[00:11:13]
Totally.
[00:11:14]
Yeah.
[00:11:15]
If you only need a static code, then you do page dot static and you give it a view function
[00:11:19]
or just no, just HTML.
[00:11:22]
And that's it.
[00:11:23]
No, no need to connect it with anything else.
[00:11:26]
That's really nice.
[00:11:27]
Sweet.
[00:11:28]
Yeah.
[00:11:29]
Every, every page will have a single page function and just kind of like a, an adapter
[00:11:33]
pattern going on, I guess.
[00:11:34]
But basically what that translates to in the real world is if you just need to render a
[00:11:38]
view, you just need to write a view function.
[00:11:41]
It's that same kind of learning curve that the core Elm has where it's like, you know,
[00:11:45]
browser dot sandbox, browser dot element, that kind of thing where if you're not, you
[00:11:48]
don't need to manage state, you don't need to yet.
[00:11:50]
If you don't want to send commands, you don't need to yet.
[00:11:52]
And you can kind of incrementally make your pages more complex as needed.
[00:11:56]
Oh, I'm wondering about something.
[00:11:58]
When I start a new Elm project, I usually start with something like a browser dot sandbox
[00:12:03]
or elements.
[00:12:04]
I don't remember which one.
[00:12:05]
And they're very simple.
[00:12:06]
And as soon as I need more complex things, I like subscriptions.
[00:12:10]
I upgraded to the next function, like application.
[00:12:15]
And that transformation is a bit tedious to do.
[00:12:19]
And I imagine that in Elm SPA, you do it a lot more often.
[00:12:22]
Do you have ways to make that simpler or is it just now?
[00:12:26]
Do you have a shortcut for that in your head?
[00:12:29]
Let's put it that way.
[00:12:31]
Yeah, I guess, I guess my strategy for that, I still do the kind of manual upgrade.
[00:12:36]
There's no like, I think to really nail that down and get it right, there needs to be some
[00:12:40]
intelligent, like AST.
[00:12:42]
If only there were a static analysis tool that could transform AST.
[00:12:47]
Yeah, has anyone heard of anything like that?
[00:12:51]
Hmm.
[00:12:52]
Doesn't really help.
[00:12:53]
I keep trying to convince Jeroen that I think it would be really cool to have a code action
[00:12:58]
API in Elm review.
[00:13:01]
So it's not like this is something that's wrong with this code and I can either fix
[00:13:06]
it or here's where you need to fix it.
[00:13:11]
But like a code action would be like, there's nothing wrong with this, but I can do something
[00:13:16]
if you'd like me to in this location.
[00:13:18]
So your cursor is over page.static and then an Elm review code action could say, would
[00:13:24]
you like me to upgrade this to a page.sandbox.page.protected.
[00:13:31]
I'm convinced.
[00:13:32]
I'm convinced.
[00:13:33]
Just a matter of a whole bunch of things.
[00:13:38]
People applying, giving me the resumes, Hey, I would like to work on this feature and I
[00:13:43]
would like to do it for free, please.
[00:13:47]
Yeah.
[00:13:48]
I would love that.
[00:13:49]
Yeah.
[00:13:50]
I do it manually.
[00:13:51]
I think in like when you get like super, you know, when your app gets super far along,
[00:13:55]
I feel like there's probably a lot of common wiring that'll make you always lean towards
[00:13:59]
that those element, those more complex things just to reuse your modals or, you know, whatever
[00:14:04]
your common component system is.
[00:14:07]
But yeah, when getting started at, it's kind of the same flow as like the Elm core upgrade
[00:14:11]
path.
[00:14:13]
So for the routing, V5 had this like, you know, you would do like source slash pages
[00:14:20]
slash hello slash name underscore string.elm.
[00:14:27]
And then V6 changed it.
[00:14:30]
So there used to be a string and int where the two types you could do.
[00:14:34]
Now everything is just a string, which I think makes sense and is nice.
[00:14:40]
Have you run into any challenges with this file based routing approach where, you know,
[00:14:46]
cause you do give up some of the power of this sort of Elm style API for a URL parser
[00:14:52]
where you, you know, you parse the URL and you say, if it ha if the URL has this shape,
[00:14:58]
parse this part into these types and make, you know, this sort of parse don't validate
[00:15:02]
technique.
[00:15:03]
But at the same time, like if it's just like rest style URLs where it's like slash users
[00:15:11]
slash one, you don't need to get that sophisticated and parsing and stuff.
[00:15:15]
So in your experience, like have you, have you found any, any areas where the file based
[00:15:20]
routing API doesn't quite fit well or does it generally work pretty well?
[00:15:25]
Yeah.
[00:15:26]
I guess specifically the change from like the int string to just string.
[00:15:30]
There's kind of a trade off there that I went with, which is, you know, however boasts here
[00:15:34]
pages are going to go.
[00:15:35]
And also something that was weird about the support for string and int is as soon as,
[00:15:40]
you know, folks would see that in the docs are like, well, what about my custom type,
[00:15:42]
you know, color?
[00:15:43]
Right.
[00:15:44]
It's like, oh no.
[00:15:45]
Well like by doing this now I have to support.
[00:15:47]
Yeah.
[00:15:48]
It is like a, an urge to support more.
[00:15:50]
Yeah.
[00:15:51]
And initially the string and int stuff I just pulled from Elm URLs, you know, core library,
[00:15:55]
right.
[00:15:56]
Where that's the only thing supported natively.
[00:15:58]
I kind of, I got to a point where I just kind of thought about it and I'm like, at the end
[00:16:01]
of the day, they're all just strings in the, in the, the browser.
[00:16:06]
When I thought about the use cases of when I've used integers in the past, for example,
[00:16:10]
it's been to send a ID up to a server.
[00:16:13]
So for example, like, you know, people slash one, I might just send that over to my, my
[00:16:17]
backend.
[00:16:18]
So, and there are some invalid routes you can make, right?
[00:16:20]
You could say like people slash banana that you'd have to handle manually.
[00:16:25]
But I think you'd handle that in the same way you'd handle people slash like nine, nine,
[00:16:28]
nine.
[00:16:29]
If that didn't show up.
[00:16:30]
Exactly.
[00:16:31]
Right.
[00:16:32]
So in practice, I'm okay with it.
[00:16:33]
I will say that, for example, I've taken a look at Elm pages, the new like 2.0 routing
[00:16:39]
where you have like splat support and stuff like that.
[00:16:41]
I think that's like interesting things to think about.
[00:16:44]
Yes.
[00:16:45]
In terms of the types of the variables, I think, I think strings are nice trade off
[00:16:49]
there.
[00:16:50]
So people don't have to write their own like custom decoders or anything like that.
[00:16:52]
So I was curious as to why you removed the string and the int because I thought they
[00:16:57]
were pretty nice.
[00:16:58]
But once you removed them, that was like, hmm, maybe it's because when you need to handle
[00:17:05]
people slash one and you say it's an int, then what happens if someone types banana?
[00:17:10]
So do you need to add another file just to handle the error case?
[00:17:15]
Was that the reasoning partially?
[00:17:17]
No.
[00:17:18]
Yeah, not really.
[00:17:19]
It was, yeah, it was mostly the whole, the whole idea of providing like an integer is
[00:17:23]
usually, is usually an ID that you're providing.
[00:17:26]
So whether that's a number that doesn't have a hit in the database or whether that's a
[00:17:31]
string that doesn't have a hit in the database, it's all kind of a 404 page type situation.
[00:17:36]
Right.
[00:17:37]
So you're going to have to handle in some way, like you said, if it's 999 or whatever,
[00:17:42]
whatever gives results in a 404, you're going to have to handle it somehow.
[00:17:47]
Also I do like that, you know, cause yeah, we're sort of spending a lot of time thinking
[00:17:54]
about these things, you and I, Ryan, the routing APIs and stuff cause for Elm pages, I've been
[00:17:58]
thinking about this a lot too.
[00:18:00]
And so the, there is something very nice about the consistency, kind of like Yuren was hinting
[00:18:06]
at like, if you have, if you have an int one, if you do like users.id underscore int dot
[00:18:14]
Elm in the old V5 API, then, then it wouldn't be handling routes that are not an int.
[00:18:22]
And then, well, what happens if like, what if you have a string one and what is the precedence
[00:18:27]
now of these different routes and stuff that you get into that sort of thing.
[00:18:31]
And it, that'd be messy.
[00:18:32]
You get a little bit messier.
[00:18:33]
So it's nice to just have a mapping and say, you know what, the file based routing stuff
[00:18:38]
is very simple.
[00:18:39]
If, if you have to sort of scrub the input and, and check it before, or go and hit an
[00:18:44]
API and look for things, then do what you got to do and let the user know if, if something
[00:18:50]
goes wrong.
[00:18:51]
But the, the way we split apart URLs is very simple.
[00:18:55]
And I do like that for the, for the splat stuff in Elm pages, we should definitely,
[00:19:01]
I guess we'll, we'll talk about that more, we've got a call scheduled to nerd out about
[00:19:05]
all of these details even more.
[00:19:07]
But I think it's quite nice because you, so splat can be helpful in certain cases if you
[00:19:14]
want to just handle N URL segments.
[00:19:18]
And then the optional stuff is really handy too.
[00:19:21]
So if you, the optional stuff, like for example, in the, in the new Elm pages 2.0 docs that
[00:19:26]
I'm working on, I handle, like if you go to slash docs or if you go to slash docs slash
[00:19:32]
getting started, it's actually the same page and that's the optional segment stuff.
[00:19:38]
So if you do a double underscore, then that allows you to handle a maybe string for the
[00:19:44]
optional segment.
[00:19:45]
It kind of sounds like just regular Elm.
[00:19:48]
Like if you go to slash docs or slash docs slash getting started, it's just the same
[00:19:53]
Elm application.
[00:19:54]
Well, it's, yeah, it's going to the same Elm page.
[00:19:57]
It's like handling it through the same page module, but then, you know, the routes are
[00:20:04]
different and like the, the built in Elm router.
[00:20:07]
So the URL parser in Elm doesn't, isn't really built to say handle one or more segments.
[00:20:15]
It's built to be very simple where you say slash users slash int and it gives you that
[00:20:22]
int and you can do something with it, which is great.
[00:20:25]
But then it's not built in a way where it's like slash file slash whatever else comes
[00:20:30]
after that with a bunch of slashes after that.
[00:20:33]
You cannot do that with the Elm URL API, Elm URL parser.
[00:20:38]
So I actually had to use a custom URL parsing API under the hood in Elm pages 2.0 for that.
[00:20:46]
So it's, it's a, but I think that there's a ton of value to having like this file based
[00:20:52]
routing.
[00:20:54]
It's like, it's a game changer.
[00:20:56]
It's so, and, and like when you're trying to create, when you're trying to create an
[00:21:00]
about page as an example, right?
[00:21:03]
Like if you're trying to do that with your own custom Elm SPA wiring, sorry, not like
[00:21:10]
Elm SPA itself, a generic Elm SPA wiring.
[00:21:15]
It's a lot of work to create an about route and wire it in and wire up all the pages.
[00:21:20]
It's like, Oh, here we go.
[00:21:21]
All right.
[00:21:22]
I got it.
[00:21:23]
Like you don't, you don't want to do it, but like with Elm SPA, you, you say Elm SPA
[00:21:29]
add slash about, and then it gives you what's the syntax slash Elm SPA.
[00:21:36]
That's totally right.
[00:21:37]
Yeah, you got it.
[00:21:38]
And then if you want to do a template, you can use one.
[00:21:40]
If you leave one off, it'll just give you the default view.
[00:21:43]
Right.
[00:21:44]
So it's not like static or sandbox.
[00:21:45]
Yep.
[00:21:46]
Yeah.
[00:21:47]
As soon as you type Elm SPA add and then slash about, you can immediately visit in the browser,
[00:21:54]
you know, local host, one, two, three, four slash about whatever your dev server is running
[00:21:57]
at and it'll say about right in the window.
[00:22:00]
So you know that it works.
[00:22:01]
It's a game changer, like creating an about page.
[00:22:04]
It's night and day with that workflow.
[00:22:06]
And it's just, it's a huge quality of life improvement.
[00:22:09]
A long time ago when I was first messing with Elm SPA, you and I talked Dillon about this
[00:22:13]
or it's just like, what's that 20 second demo that'll dazzle them.
[00:22:18]
And that kind of inspired like the code generation bit.
[00:22:21]
Oh cool.
[00:22:22]
There's a lot of great code generators out there for doing more sophisticated stuff.
[00:22:27]
So I kind of had like a conflict.
[00:22:28]
I'm like, I'm just going to make it simple.
[00:22:30]
They kind of made the same trade off with Elm SPA server.
[00:22:33]
There's already Elm Live out there.
[00:22:34]
I didn't want to say like, Oh, Elm SPA's.
[00:22:37]
I didn't want to say Elm SPA's dev server is an alternative to Elm Live.
[00:22:42]
I didn't really care in getting involved in making a dev server.
[00:22:46]
So what I did was I kind of made a Elm reactor like server.
[00:22:50]
What did you build that with?
[00:22:52]
So that's just vanilla node, HTTP.
[00:22:55]
There's some WebSocket stuff going on.
[00:22:57]
Just like a simple, I kind of looked at how other projects were doing it.
[00:23:01]
And the trick is they just inject a little script tag with a web component listener listening.
[00:23:06]
So anytime in Elm SPA server, anytime you make a file change, it basically sends a message
[00:23:12]
to tell the browser refresh.
[00:23:14]
Super super simple.
[00:23:15]
Got it.
[00:23:16]
It's like one line of JavaScript versus like a bunch of dependencies that I don't want
[00:23:18]
to patch when someone decides they don't want to be an NPM contributor anymore.
[00:23:25]
So basically like if somebody wanted more sophisticated hot module replacement and web
[00:23:32]
pack stuff pulling in NPM modules and stuff like that, then you're like, okay, you got
[00:23:37]
started with the equivalent of Elm reactor.
[00:23:40]
And it's actually just an Elm map that I'm sort of helping you generate a few modules
[00:23:45]
for.
[00:23:46]
So go create your web pack, configure whatever config you want to use, go for it at that
[00:23:50]
point.
[00:23:51]
Exactly.
[00:23:52]
And the CLI has a few commands to make that easier.
[00:23:54]
So right now the Elm SPA server command, it'll generate the files, it'll build the Elm project
[00:24:00]
with Elm make, and then it will spin out the server.
[00:24:02]
So there's also commands that just kind of strip away those extra features so that it
[00:24:06]
can interop better with web pack or parcel.
[00:24:09]
So you just run like Elm SPA watch that will listen for file changes and that'll generate
[00:24:13]
the code, but it won't build your project and electric dev server and your process handle
[00:24:17]
that.
[00:24:18]
And there's an example of the change files.
[00:24:20]
Yeah.
[00:24:21]
There's an example in the examples folder of how to do this with VEAT, which is one
[00:24:25]
of the fancier, faster, another view ecosystem based thing.
[00:24:29]
This is like basically a view sales pitch.
[00:24:31]
VEAT is the new hotness.
[00:24:33]
It's like, it's all the rage these days.
[00:24:35]
It's pretty, I've been very inspired by VEAT's philosophy as I've been building Elm pages
[00:24:42]
2.0.
[00:24:43]
Cause I, unlike you, Ryan, I bit the bullet and went all in on building a custom dev server
[00:24:51]
for Elm pages 2.0 because Elm pages is different because it has a life cycle on the server
[00:24:57]
side where it's like running these data sources and stuff, right?
[00:25:02]
It doesn't just create an Elm map.
[00:25:04]
So there are all sorts of like things that create a much better dev experience when you
[00:25:11]
have a proper dev server.
[00:25:13]
So I had to create a custom dev server for it to get those things for Elm pages and it
[00:25:18]
was hard, but I was super inspired by VEAT's approach of this sort of just in time.
[00:25:27]
Compilation approach.
[00:25:28]
So VEAT is very cool.
[00:25:31]
Like I love this.
[00:25:32]
I love this approach of like you start up the dev server and it's like, all right, the
[00:25:36]
dev server is ready, right?
[00:25:37]
It's not like, let me go compile the whole world and get back to you.
[00:25:40]
And then five minutes later, it's ready.
[00:25:42]
It's instantly ready.
[00:25:43]
And then you go load a page and it does the work it needs for that page.
[00:25:48]
Totally.
[00:25:49]
Yeah.
[00:25:50]
Yeah.
[00:25:51]
I'm a huge fan of like the, just the documentation too.
[00:25:52]
And that if you like good documentation, like Elm and viewer, like the top in my opinion,
[00:25:56]
like they're so good at writing like clear beginner friendly docs.
[00:26:00]
So like shout out to docs, docs authors everywhere.
[00:26:04]
You're doing great.
[00:26:06]
The unsung heroes.
[00:26:07]
So I noticed there's also in the, in the view.elm module, which we talked about in Elm SPA,
[00:26:14]
which you can you can eject or use the default one.
[00:26:18]
There's this sort of, you know, API, so to speak for, for that module that the module
[00:26:24]
exposes a view type.
[00:26:25]
It exposes a placeholder value, which it takes a string and it gives you the view type.
[00:26:33]
It it has to expose a none, which is a view type that's empty.
[00:26:38]
So this is another really interesting sort of like developer experience thing you came
[00:26:43]
up with here.
[00:26:44]
Or I don't know, maybe you, you were inspired by another framework there, but tell us a
[00:26:49]
little bit about like the view module and like this placeholder thing.
[00:26:53]
What's the idea there?
[00:26:54]
Yeah, so so the view module at a high level back in like Elm SPA version three, I was
[00:26:59]
trying to wrap everything in my package.
[00:27:03]
So what I mean by that is in order to spin up like a sandbox, it had to be HTML.
[00:27:08]
And then there was like modifiers for like, Oh, what if you're using Elm UI?
[00:27:12]
And I quickly kind of realized that I need to cover every permutation of every view library
[00:27:16]
that ever exists.
[00:27:17]
And I just at that point would disallow any custom view libraries.
[00:27:21]
And that's something I'm a huge proponent of, like making your own custom UI type that
[00:27:26]
kind of encapsulates your design system.
[00:27:28]
Like that's a huge plus.
[00:27:30]
So I needed something that was going to be generic and kind of pluggable.
[00:27:34]
So view is actually a generic argument at like the core library.
[00:27:39]
You don't really interface with the, so I didn't talk about this earlier, but Elm SPA
[00:27:44]
is primarily a CLI tool available on NPM.
[00:27:47]
There's also an Elm SPA package, but that is more so to constrain the CLI and to make
[00:27:53]
it so you can't modify things that would break the CLI.
[00:27:57]
So in version five, you could potentially change the page function because it was in
[00:28:02]
user code land, I guess.
[00:28:05]
And what that led to is people bricking there, basically giving it the shape the CLI didn't
[00:28:11]
expect.
[00:28:12]
And then they get these weird cryptic errors that generated code.
[00:28:14]
So in order to kind of take a step away from that, the new Elm SPA package is really about
[00:28:19]
saying, no, I control the page type.
[00:28:21]
This is what I need to be able to generate stuff for you correctly.
[00:28:25]
But in order to do that, I needed to wrap, or to take your view in as a generic argument.
[00:28:29]
So that's a long winded way of saying that the view file, the view module is a way for
[00:28:34]
you to just give the framework what it needs to do all the right stuff.
[00:28:39]
So connect your pages together.
[00:28:41]
You're going to need a map function to bubble up messages and things like that.
[00:28:44]
You're going to need a two browser document function to convert it at the very top level.
[00:28:48]
If you ever get to the point where you do eject the default main file, you'll see it's
[00:28:52]
being used there.
[00:28:53]
It's a view.two browser document, because that's what the Elm runtime is expecting.
[00:28:57]
It's expecting that core thing.
[00:28:58]
So whether you're using Elm UI or Elm CSS, there's always a function at the top level
[00:29:03]
that'll convert those libraries to that.
[00:29:05]
And you can just wire that up in one place.
[00:29:07]
And then yeah, the view.none, I needed that when I implemented protected pages.
[00:29:11]
That's kind of like an implementation constraint there where when you're looking at a page
[00:29:16]
that you don't have access to a user yet, but you haven't quite redirected, there needs
[00:29:20]
to be something to render there.
[00:29:22]
So view.none is called by the generated code for you.
[00:29:26]
So you just need to provide that.
[00:29:27]
You don't need to wire that up or anything.
[00:29:28]
And then view.placeholder is for the LMSPA add feature, just so that no matter what framework
[00:29:34]
you're using, I can always render something on the screen with whatever UI library you're
[00:29:38]
up to.
[00:29:39]
Yeah.
[00:29:40]
It's really interesting.
[00:29:41]
Did you consider customizable templates as a way of doing that?
[00:29:45]
Because that seems like that would be the other alternative would be to let users customize
[00:29:51]
their templates for the add commands.
[00:29:53]
But I mean, at that point, the users could also create their own custom tool to create
[00:29:59]
these templates.
[00:30:00]
But there are a few LMSPA specific things it needs to add in the imports and stuff.
[00:30:07]
This is an Elm radio listener special.
[00:30:09]
I'm going to let you guys in on a little secret.
[00:30:12]
You can do this with the current LMSPA 6.
[00:30:15]
I hit it because I didn't want to...
[00:30:17]
I wanted to experiment with it and see...
[00:30:19]
If you build a foundation on stuff like this, people will send you issues at three in the
[00:30:25]
morning and say, why doesn't it do this?
[00:30:27]
So I wasn't sure if I wanted to announce it, but why not?
[00:30:30]
So if you look in the.LMSPA folder, if you're currently using LMSPA v6, there is a templates
[00:30:37]
folder and it's got four files in there, one called static, one called sandbox, another
[00:30:41]
called element, another called advanced.
[00:30:43]
Those are actually the templates that I use.
[00:30:46]
I use some bizarre handlebars and text thing.
[00:30:52]
You can take those out of your Gitignore and actually make your own custom templates there.
[00:30:57]
And you can even create your own.
[00:30:59]
So if you created within LMSPA templates, let's go back to the banana example.
[00:31:03]
If you created a banana.elm file, the CLI would accept LMSPA add slash fruit and then
[00:31:08]
like banana, and it would use that custom template.
[00:31:11]
So if you're a power user and you listen to Elm radio, then yeah, you can make stuff specific
[00:31:17]
to your app.
[00:31:18]
There are, that being said, as a disclaimer, there are better tools out there for this.
[00:31:22]
At my company, at Blissfully, we use Plop, which is like a template generator where you
[00:31:29]
just plop in kind of random things.
[00:31:31]
They've got like functions like to camel case and to sentence case, nice helpers and stuff
[00:31:36]
like that.
[00:31:37]
So for more advanced use cases, don't ask me, just use a better tool for the job.
[00:31:42]
That's kind of a simple one that gets you up and running.
[00:31:45]
The framework really is responsible for making a templating language.
[00:31:49]
That's fascinating.
[00:31:51]
I'm going to need to look into Plop, but that's really cool because I've got like a similar
[00:31:55]
thing in Elm pages to like create a new route and you know, it's, and I've been trying out
[00:32:04]
this like view placeholder pattern, which is cool, but it definitely like as a user,
[00:32:10]
when I'm using Elm pages V2 working on things, I feel a little frustrated that I have to
[00:32:16]
then go replace it with my own record type and stuff.
[00:32:20]
Yeah.
[00:32:21]
Having a nice templating system is like game changing.
[00:32:23]
Yeah.
[00:32:24]
You can really save yourself some time that with good code generation and you you're a
[00:32:28]
winner.
[00:32:29]
Exactly.
[00:32:30]
Yeah.
[00:32:31]
Now, by the way, the, these templates, so the, so it's this templates folder that has
[00:32:34]
like an advanced element sandbox static.
[00:32:37]
Are those hard coded options or if you add different named things, will those be exposed
[00:32:43]
as options?
[00:32:44]
Yeah.
[00:32:45]
If you add different name things, they'll be exposed.
[00:32:46]
We're not documented anywhere.
[00:32:47]
So you're really going in the wild west.
[00:32:49]
If you're using these things, you're going off the grid.
[00:32:52]
I can't help you, but you'll see, you'll see examples of where the module name is inserted.
[00:32:56]
Those templates, your warranty is void and null.
[00:33:00]
Yes, exactly.
[00:33:01]
No liability on this, but feel free to feel free to look at those if you want.
[00:33:06]
I personally don't mess with them.
[00:33:07]
I haven't, I haven't gotten there yet.
[00:33:09]
I would use a third party tool for that.
[00:33:12]
Just like with the dev server.
[00:33:13]
I think the approach is we need a sane, stable way to like make apps that just work without
[00:33:17]
any dependencies.
[00:33:18]
And then if you want to get fancy, feel free to get fancy.
[00:33:21]
Right, but you strongly endorse getting fancy and building your own templates.
[00:33:25]
Yeah.
[00:33:26]
That's cool.
[00:33:27]
So what is it that plot brings you that the templates that you have don't?
[00:33:31]
Yeah.
[00:33:32]
There's a lot, I mean, templating languages, there's so much sophisticated stuff.
[00:33:36]
It's like when you, when you start to implement one, you think it's going to be easy.
[00:33:39]
And then you realize there's all these edge cases and then people will be like, Hey, like,
[00:33:43]
you know, I created a file called about us, you know, with a capital A and a capital U,
[00:33:48]
you know, Pascal case together.
[00:33:50]
But for my thing, I really want it to be, you know, hyphenated in between like different
[00:33:54]
converters like that kind of come out of the box.
[00:33:57]
So I mean, plop is when I'm familiar with, cause I, cause I use it at work.
[00:34:01]
But there's gotta be hundreds of these things out there where you just generate strings,
[00:34:05]
right?
[00:34:06]
It's then in the day, we're all just making strings.
[00:34:09]
It's not, it's not special, but I did not put a particular amount of time into making
[00:34:15]
a templating engine for those things.
[00:34:19]
Cause I just know there's so many out there and it's not the worth the effort.
[00:34:22]
Yeah.
[00:34:23]
It's kind of like the Elm live approach.
[00:34:24]
It's like someone spent a lot of time making a really nice thing for this.
[00:34:26]
Yeah.
[00:34:27]
One, I don't really want to step on anyone's toes, but two, it's like, there's so much,
[00:34:30]
so many more edge cases that they've accounted for that I would have to like kind of reinvent.
[00:34:35]
So yeah, I think that's sort of the Unix tool chain idea too, to like do one job really
[00:34:41]
well and let something else do a job really well and compose together with your tool.
[00:34:47]
And when you can, when you can narrowly define the scope of something and do something really
[00:34:52]
useful, really well, it's gold, pure gold.
[00:34:55]
So I had another question about, I believe in V5, in LMSPA V5, there was like a shared
[00:35:03]
view.
[00:35:04]
Am I misremembering that?
[00:35:05]
That's correct.
[00:35:06]
No, there was.
[00:35:07]
Yeah.
[00:35:08]
So I'm curious about like that change.
[00:35:10]
And also like as a user, if I wanted to create an LMSPA V6 app and have like a header and
[00:35:17]
footer on every page, where would that live?
[00:35:20]
Yeah, that's a really good question.
[00:35:22]
That's like super common.
[00:35:24]
Just so I can understand, because I don't remember what it was for.
[00:35:29]
The shared view was for adding global layouts and it was not for saying, Hey, I want to
[00:35:35]
use LMI or I want to use LMS CSS.
[00:35:38]
Correct.
[00:35:39]
Yeah.
[00:35:40]
So the view module, different than the shared.view function.
[00:35:45]
So shared.view is like you're saying, and this is kind of the naive thing that I think
[00:35:50]
when you start an app, you think is the case, which is all pages will use this layout.
[00:35:55]
No.
[00:35:56]
Which falls apart as soon as you have like a sign in page, right?
[00:35:59]
It's like, Oh, actually I don't need a nav bar on that.
[00:36:00]
So I kind of hit this thing where I was providing, I made it easy for people to do the wrong
[00:36:06]
thing.
[00:36:07]
So here's your shared.view function, put your header in there, put your footer in there.
[00:36:11]
It'll be great.
[00:36:12]
And then you, you know, want a sign in page.
[00:36:14]
It's like, well, how do I support other layouts?
[00:36:17]
It's kind of a natural question that comes out of this because I don't need the header
[00:36:21]
and footer here.
[00:36:22]
So the solution with V6, and you can see this in the, if you go to the LMS PA repo, you
[00:36:27]
can see in the doc site, this kind of connects back to our earlier conversation about like
[00:36:31]
the Splat routes and like the optional parameters and stuff.
[00:36:35]
The way you reuse things in Elm is you just, you know, you make a common view function.
[00:36:40]
You do the same thing with LMS PA.
[00:36:41]
So the way that I got around that is I created a UI folder with a module and a called layout,
[00:36:48]
and I have a few layouts to find there.
[00:36:50]
And you can wire those up at the view level if you want, but if your header and footer
[00:36:55]
have to deal with state, you can't just wire that up to the view level.
[00:36:58]
So depending on your use case, that could be as easy as a reusable function that your
[00:37:03]
view would call like UI.layout.default.
[00:37:06]
And then you wrap your page in that.
[00:37:08]
So just a few characters there.
[00:37:10]
It's not too bad.
[00:37:11]
Or if you have like state you need to wire up, you can actually create a different page
[00:37:16]
type.
[00:37:17]
So like page.static, page.element, you can create like a UI.layout.element, which takes
[00:37:22]
in your init, your update, your view, and kind of wraps it in its own special model.
[00:37:25]
Let me see.
[00:37:27]
I feel like LMS PA, the site did the first approach.
[00:37:31]
I don't think it needed state for its thing, but maybe that nav bar search did.
[00:37:36]
So let me verify that really quick.
[00:37:38]
But yeah, if things need to get more advanced, you can kind of make a page, a common page
[00:37:43]
function that wraps your init, update, and view.
[00:37:45]
And I think that's what we do here.
[00:37:48]
So going the composition way instead of the inheritance way.
[00:37:52]
It'll always be more flexible at the end of the day.
[00:37:54]
It'll always be easier because there was a tech talk that Evan gave a while ago, and
[00:37:58]
I don't even remember what one it was, but he said something along the lines of like
[00:38:02]
your view code, it's always going to diverge.
[00:38:04]
It's never going to become more similar.
[00:38:06]
You're not going to be like, oh wow, this all of a sudden is the same component.
[00:38:10]
It never happens.
[00:38:11]
So just being flexible and saying like, no, there is not one top level layout always.
[00:38:16]
That's like a good constraint not to set on yourself.
[00:38:19]
But it has a few characters on each file.
[00:38:21]
Yeah, that'll get you.
[00:38:23]
If you're afraid of characters, Elma is not the language for you.
[00:38:27]
If you want to have a good time, that's when you use Elma at the cost of typing sometimes.
[00:38:32]
I mean, even just programming is not for you.
[00:38:36]
It's like Siri, please type all the space.
[00:38:39]
There's got to be a voice app for that, right?
[00:38:41]
GPT3, is that what it is?
[00:38:43]
The AI?
[00:38:44]
Give it a few years.
[00:38:46]
Okay.
[00:38:47]
So you're saying like you can have like a suite of helper functions for expressing different
[00:38:53]
layouts, like wrapping with different layouts.
[00:38:57]
What about you could also like have your view function be a custom type, right?
[00:39:01]
That would also be a way to approach that?
[00:39:03]
Yeah, you could make your view function.
[00:39:06]
You mean as opposed to just like a view message, you could have like a different, yeah.
[00:39:10]
Yeah, you could have it be a custom type where each variant is with header photo or whatever
[00:39:15]
it might be.
[00:39:16]
That is a really cool approach.
[00:39:17]
Yeah.
[00:39:18]
And that's what I love about accidental flexibility that the framework has.
[00:39:24]
I really tried not to constrain too much.
[00:39:27]
And so when Dillon has a great idea, like, hey, you could use a custom type.
[00:39:30]
I'm like, oh yeah, you could.
[00:39:31]
You know, it feels good.
[00:39:32]
It's like, yeah, go do it.
[00:39:33]
I don't have to implement it.
[00:39:36]
Yeah.
[00:39:37]
Anytime I constrain something or I make something unavailable, that's really when I put people
[00:39:42]
in a rough spot.
[00:39:43]
So a lot of the progress on LMSPA has been kind of cooling off, like stepping off the
[00:39:47]
gas.
[00:39:48]
V3 had like transition support and I'm like, this is way too limited to maintain and it's
[00:39:53]
not what people really need, which is full control over how things fade.
[00:39:57]
It seems like a Matt Griffith problem to me.
[00:39:59]
It seems like an animation thing I don't have to worry about.
[00:40:02]
Shout out to Matt Griffith, LMI guy.
[00:40:05]
He's always up to something.
[00:40:06]
I'm sure he's got some cool animation thing in the works.
[00:40:08]
Oh, he's got some things up his sleeve for sure.
[00:40:11]
Yes.
[00:40:12]
Talk about transitions.
[00:40:13]
You guys do a transition.
[00:40:15]
Two transitions.
[00:40:17]
So how do you handle going from one page to another now?
[00:40:21]
Like I'm not talking about the animations, but how do you change the model?
[00:40:25]
How do you initiate your page?
[00:40:27]
How does that work now?
[00:40:28]
Totally.
[00:40:29]
Yeah.
[00:40:30]
So right now from a user's perspective, the most common way to go from one page to another
[00:40:33]
is using that A tag, right?
[00:40:35]
Where you just have an href.
[00:40:37]
So from a user's perspective, all you'll do is you'll make your URL slash people.
[00:40:42]
There's some helpers to make that type safe if you want to use routes.
[00:40:45]
But what LMSP will do under the hood is it stores a shared model, which persists across
[00:40:52]
page transitions, going from one page to another, and it stores a custom type for the page.
[00:40:57]
So there'll only ever be one page state active at a time.
[00:41:00]
So for example, if I am on the homepage, I navigate to the about page.
[00:41:04]
I'm going to reset my page state to be the about page, but my shared state is going to
[00:41:09]
stay the same.
[00:41:10]
So there's this notion of a shared module that Dillon alluded to earlier, that's going
[00:41:15]
to store data that you might want to persist, like a logged in user or, you know, I'm not
[00:41:19]
sure what else.
[00:41:20]
That's the most common example.
[00:41:22]
There's plenty of things that you might want to persist, like the time zone or whatever
[00:41:25]
you need.
[00:41:26]
So this is something I've been wondering about a lot ever since I discovered LMSP.
[00:41:32]
Imagine I have a page where it has tabs and choose that each tab corresponds to one segment
[00:41:40]
in the URL.
[00:41:42]
So it's like about slash team about slash CTOs.
[00:41:48]
And you go from one to the other, but it's almost the same page.
[00:41:52]
But there are like UI things that you want to keep, like you want to keep the accordion
[00:42:00]
open when you go from one page to another.
[00:42:03]
So as soon as you have a page transition where you need to keep some things, do you put it
[00:42:09]
in the shared model?
[00:42:10]
Because that feels like kind of a waste in a way.
[00:42:13]
Yeah, it's like a weird trade off.
[00:42:15]
So right now, like one of the biggest constraints of LMSPA is that routing, the routing is managed
[00:42:20]
by the framework.
[00:42:21]
So you run into these weird cases.
[00:42:23]
So yeah, you have two choices there for that example.
[00:42:26]
One you move things in a shared, which kind of feels a little clunky and weird.
[00:42:29]
Another one is you use query parameters as opposed to the nested slashes.
[00:42:33]
So you could say tab equals, you know, about tab equals CTOs.
[00:42:38]
That won't change.
[00:42:39]
So it's kind of sad.
[00:42:42]
And I'm sure there's a better solution out there to it that you can't have full flexibility
[00:42:46]
of like, hey, this is just like a sub page transition.
[00:42:50]
Don't clear it.
[00:42:51]
The third option is you eject that main.elm and you add a specific handler for that.
[00:42:56]
Like if I'm going from this URL to that URL, don't call page init again.
[00:42:59]
That makes sense.
[00:43:00]
So if you take a look at the default main that's provided, I don't hide that underneath
[00:43:06]
my framework.
[00:43:07]
That's not hard coded generated code.
[00:43:08]
You can take full control over that.
[00:43:10]
And you can say when I get the page message, if I'm switching URLs on URL change, for example,
[00:43:16]
if I go from this to this, don't clear things out.
[00:43:20]
So you have the flexibility.
[00:43:21]
It's a little extra work.
[00:43:22]
I think my choice would be the second option because it's the least resistance, which is
[00:43:26]
just use a query dictionary for that.
[00:43:29]
So what happens when you only change the query parameters?
[00:43:33]
What is the flow that happens behind this Elm ESP?
[00:43:37]
Yeah.
[00:43:38]
So if you change the query parameters, it will not re initialize the entire page.
[00:43:42]
So you'll have your current state.
[00:43:43]
I'm actually, I got a good question in the LMSP users channel about how to respond to
[00:43:47]
external changes from like, let's say like the shared model changes on a subscription,
[00:43:51]
for example, how can the page respond?
[00:43:53]
How can the page plug into that?
[00:43:55]
LMSP v5 had a mechanism for this.
[00:43:57]
If you're familiar with like the load function where you kind of get like a, almost a hook
[00:44:01]
that triggers and says, Hey, like something changed from outside you in this new area
[00:44:06]
I'm exploring, which would be a compatible minor update.
[00:44:09]
We would have hooks for query parameters changing as well as shared models changing.
[00:44:14]
But to, I guess, to answer what happens to your shared state in the current state of
[00:44:17]
things, your page state will not change and you will have access to your, you will always
[00:44:23]
have access to the latest query parameters for every page that you use, whether it's
[00:44:27]
a static page or an advanced page or an element page or whatever.
[00:44:31]
You'll always be able to view the right tab based on those changes.
[00:44:34]
Okay.
[00:44:35]
So the view function would be called again, but not updates.
[00:44:38]
Exactly.
[00:44:39]
Yep.
[00:44:40]
100%.
[00:44:41]
Yeah.
[00:44:42]
Okay.
[00:44:43]
Right.
[00:44:44]
Which, which you can actually see in the, in the main.elm in the defaults, which you
[00:44:46]
can eject, there is a changed URL message and it says, if URL.path does not equal model.url.path,
[00:44:55]
then it's going to init the next page.
[00:44:57]
So, so you actually can tweak that if, if you need to for a particular use case.
[00:45:01]
But I like Ryan's philosophy too, that like, if you can be on the same page, if it, if
[00:45:07]
it effectively is the same page, semantically, then why not keep it on the same page?
[00:45:12]
Like do you really need to change the URL?
[00:45:14]
So it's up to you.
[00:45:15]
How are the people?
[00:45:16]
Sure.
[00:45:17]
Yeah.
[00:45:18]
So the, so let's talk a little bit about the, the difference between shared state in V5
[00:45:25]
and V6.
[00:45:26]
So like this is, this is one of the, this is one of the really interesting features
[00:45:31]
of LMSPA.
[00:45:32]
So when I look at the changes here, it, it makes me think like we talked about how shared
[00:45:37]
no longer has a view function, how that view function now lives in main in LMSPA V6.
[00:45:44]
So it seems like the shared module in LMSPA V6 is really focused on state.
[00:45:50]
It's just shared state.
[00:45:52]
It's not shared anything else.
[00:45:54]
Is that a fair assessment?
[00:45:56]
Yeah, absolutely.
[00:45:57]
I think that's spot on.
[00:45:58]
It's yeah, the shared, the shared model and everything in that shared module is really
[00:46:01]
about what state do I care about that I don't want to clear as I navigate to a different
[00:46:06]
page.
[00:46:07]
Right.
[00:46:08]
Including flags because you can't like, it wouldn't really make sense to handle flags
[00:46:12]
over and over in every single individual route.
[00:46:16]
You kind of, you get flags when the app starts, whatever page it starts on and then you handle
[00:46:21]
it appropriately.
[00:46:22]
Yeah.
[00:46:23]
And you can choose to persist those to your shared state.
[00:46:25]
If you ever need to reference them again, sometimes you'll have like some, some data
[00:46:29]
that a certain page will need.
[00:46:30]
What's cool about V6 is every page will have access that shared state.
[00:46:34]
I've changed like the external API.
[00:46:36]
I used to have like a, like an Elm core main function that returned one value.
[00:46:41]
Now I return a function that takes an arguments.
[00:46:43]
So the arguments are the shared model, the current like request, which includes the URL,
[00:46:47]
the query parameters, the route and everything, and then you return a page.
[00:46:51]
So you can choose like if your view function is the only thing that needs access to the
[00:46:54]
shell, you just pass it to the view.
[00:46:56]
You don't need to type all this weirdness where it's like init taking a shared, taking
[00:46:59]
a request and ignoring them.
[00:47:01]
That was kind of the old, the old API that I'm glad is gone.
[00:47:05]
That, yeah, that's a really interesting design you've got there.
[00:47:09]
So the, so you're saying like when you, when you define a page, the equivalent of like
[00:47:15]
doing like a browser dot application browser dot element, when you define that for each
[00:47:20]
route that top level page function has, has arguments, which you can choose to wire into
[00:47:28]
the view function, init update and all those places, right?
[00:47:31]
Yeah, exactly.
[00:47:32]
Yep.
[00:47:33]
Yeah.
[00:47:34]
Context that you might opt into, but it's always available.
[00:47:35]
So you don't have to complicate your, your code to deal with the fact that they're there.
[00:47:38]
You just choose if you need them or not.
[00:47:40]
Right.
[00:47:41]
So you don't have to annotate, init, update, view subscriptions with all of the things
[00:47:47]
that it has access to.
[00:47:48]
You just wire it through if and when you need it.
[00:47:51]
Yeah.
[00:47:52]
Super interesting.
[00:47:53]
So, okay.
[00:47:54]
So V5 had save and load.
[00:47:57]
So like, tell us about that change.
[00:48:00]
Cause that was like a really interesting design.
[00:48:03]
What what made you change directions there and what are the benefits of the of the new
[00:48:09]
design?
[00:48:10]
Yeah.
[00:48:11]
So save and load in the previous iteration of V5 was a little bit, it was interesting,
[00:48:15]
a little controversial.
[00:48:16]
It was a little like, what the heck?
[00:48:19]
Very quickly to summarize what, what that kind of mental model was.
[00:48:23]
It was let's keep the init, update, view and subscriptions function just as they are in
[00:48:28]
core Elm.
[00:48:29]
Like people coming to the framework will have the exact same APIs.
[00:48:32]
They'll return commands, you know, init and update the subscriptions, return subs and
[00:48:36]
we'll all be happy.
[00:48:37]
Commonly, if you're building your own, wiring up your own SPA with Elm, you, you, you'll
[00:48:42]
commonly see people do like a triple out of an update where they do like model.
[00:48:46]
I've got a command and then I've got some type of you know, shared update thing.
[00:48:50]
Right.
[00:48:51]
And out message type thing.
[00:48:52]
Yeah, exactly.
[00:48:54]
So the idea with the save and load is when you get to that, that final most advanced
[00:48:58]
type of page where you want to potentially update like the signed in user and the shared
[00:49:02]
state you would create these two like implement these two functions.
[00:49:07]
And one of them would write to the shared state when the model changed.
[00:49:11]
And one of them would read from the shared model if the shared model changed.
[00:49:15]
So you could do effects.
[00:49:16]
What I found was happening in practice from that design.
[00:49:20]
So the API was nice, but what that led to, and this kind of goes in tandem with that
[00:49:24]
the page design that we talked about where you always have access to shared and request.
[00:49:30]
Previously init was the only function that had access to the shared state.
[00:49:33]
So what you were seeing people do was they would cache a local copy of the signed in
[00:49:39]
user and it was up to them to make sure that if the user signed out that they were listening
[00:49:43]
and that they correctly invalidated their local cache.
[00:49:46]
So I was forcing everyone to deal with this local cache and no one really complained but
[00:49:52]
they should have because that it was a lot of typing and it was ultimately for a less
[00:49:57]
reliable experience.
[00:49:59]
So with v6 the way I fixed that was instead of doing that triple pattern, I extended kind
[00:50:06]
of the second bit.
[00:50:07]
So instead of model command, now it's model effect.
[00:50:10]
And what that unlocked for me was the ability to play well with Aaron's own program test
[00:50:15]
library.
[00:50:16]
Also allowed me to say like to send shared messages from an init and update as you could
[00:50:22]
in previous versions of LMSPA or like you might want to in a real world app without
[00:50:26]
the need for save and load and without some of the headache of that.
[00:50:30]
What I got rid of was load is actually useful as we talked about a little bit earlier where
[00:50:34]
you might want to respond to an external change that you don't know about.
[00:50:37]
So I'm looking to add that back in in a way that doesn't break anyone's code base.
[00:50:42]
It's like an optional upgrade.
[00:50:44]
A hook that tells you that the shared state changed.
[00:50:46]
Yeah.
[00:50:47]
So like if a user gets signed in, you know, off some asynchronous process to basically
[00:50:53]
allow you to turn off your loading spinner on a page or something like that.
[00:50:56]
It's a pretty common thing.
[00:50:58]
So but yeah, so save and load are gone and I'm happy.
[00:51:03]
And with messages like so let's see the effect to command is where does that code live effects
[00:51:11]
to command?
[00:51:12]
That's a default module.
[00:51:14]
It's a yeah.
[00:51:15]
So you can also check this effect module just like you would view or shared and control,
[00:51:20]
you know, if you want to define your own custom things for doing program testing.
[00:51:24]
But by default, it has two functions to command and or sorry, I think it's from command and
[00:51:28]
from shared message where you give it a command.
[00:51:30]
Well, you give it a shared update.
[00:51:32]
I see.
[00:51:33]
Okay, so that so that's an effect type that you you have in the default, ejectable effect
[00:51:39]
module that it's just shared with a shared message.
[00:51:42]
And then that's just going to trigger that.
[00:51:44]
That's really interesting.
[00:51:45]
That's really interesting design.
[00:51:46]
Yeah.
[00:51:47]
So you kind of kill two birds with one stone you you got rid of this thing that was tending
[00:51:52]
to lead to people ending up with stale data in their model from the shared data.
[00:51:58]
And you enabled the effect pattern, which allows people to test with Elm program tests,
[00:52:05]
because that requires an effect type, it can't directly test commands.
[00:52:08]
And you can pass these shared effect messages using that pattern.
[00:52:13]
So you killed two birds with one stone with that design?
[00:52:16]
Yeah, yeah, I'm happy with where it landed.
[00:52:18]
Yeah, very interesting.
[00:52:20]
Yeah, definitely seems a lot simpler.
[00:52:22]
Do you think do you think there are any trade offs with like, reaching in, like basically
[00:52:28]
being able to trigger a shared message from anywhere?
[00:52:32]
Are there like, does that concern you?
[00:52:34]
Or in practice?
[00:52:35]
Have there been issues?
[00:52:36]
Or is it just fine?
[00:52:38]
In practice, there haven't been issues.
[00:52:39]
I always feel bad exposing custom type variants outside of a module boundary.
[00:52:44]
Yeah.
[00:52:45]
Even even like simple examples where I'm kind of should like think about like, Boolean,
[00:52:49]
it's like, it always feels dirty.
[00:52:51]
Right.
[00:52:52]
Lowercase t, r, u, e equals capital, true.
[00:52:57]
Yes, exactly.
[00:52:58]
Right.
[00:52:59]
And you can go that route.
[00:53:01]
If that makes you feel bad, you can kind of create functions that just expose it for you.
[00:53:07]
So you have a little bit more control over like, what can be caused by the outside world,
[00:53:11]
like what pages can send.
[00:53:12]
Yeah, there's there's a, I think the Elm debugger takes care of any, any weirdness.
[00:53:16]
So you'll see that like, you know, that message is being fired off, and then you just got
[00:53:19]
to hunt it down.
[00:53:21]
But that is a, I think it was a trade off worth worth making in the grand scheme of
[00:53:25]
things.
[00:53:26]
But yeah, I'd rather have Yeah, I want it's like, I want everything, right?
[00:53:29]
It's like, I want you to have one place to write your shared update code.
[00:53:31]
But I don't want you to I don't know.
[00:53:33]
Yeah.
[00:53:34]
No, but like you said, I like that.
[00:53:36]
I like that thinking, like, I mean, you know, once you eject the shared module, it's yours,
[00:53:42]
you can, you don't have to expose all of the variants of the message type.
[00:53:48]
And you could have like, shared, like type message equals internal, and then have like,
[00:53:56]
a bunch of internal ones that you don't expose, and then external, and the external ones could
[00:54:02]
be exposed, or you could expose constructor functions forward or whatever, like, so you
[00:54:07]
can sort of define the constraints you want to there, which is pretty, pretty cool.
[00:54:12]
Yeah, another Dillon idea that you don't need to support.
[00:54:15]
Yeah, this is great.
[00:54:16]
Like, it's always has great ideas outside of like routing stuff, then I'm the happiest
[00:54:22]
man alive.
[00:54:23]
You know, it's like, it's like, well, I want a number at the end of it's like, Oh, sorry,
[00:54:28]
man.
[00:54:29]
You know, like, I kind of got you on that one.
[00:54:32]
But yeah, we're all doing our best, you know, to make nice stuff.
[00:54:38]
But yeah, that would totally be supported.
[00:54:39]
Yeah, what you described?
[00:54:41]
Yeah, being giving some flexibility and not over constraining your framework as a as a
[00:54:47]
framework author is basically the best way to be smarter than yourself.
[00:54:53]
Because your users are going to come up with smart ideas that you would have never thought
[00:54:57]
of.
[00:54:58]
And that's just a fact that you have to accept as a framework author.
[00:55:01]
So you can't can't try to outsmart your users.
[00:55:04]
Yeah, but especially in the Elm community, you also want to prevent people from falling
[00:55:10]
into pitfalls.
[00:55:11]
Totally, totally.
[00:55:12]
Yeah.
[00:55:13]
Or in my case with v5, enforcing them into pitfalls with that.
[00:55:17]
Save state caching thing.
[00:55:18]
Yeah, please fall into this hole, please, please just you don't have a choice.
[00:55:23]
Follow the line.
[00:55:24]
You want shared data, don't you?
[00:55:25]
Yeah.
[00:55:26]
I do.
[00:55:27]
I really like this.
[00:55:29]
Don Norman design of everyday things concept that basically like, if there's a door, and
[00:55:36]
you try to pull it, but you can't because it's a push door.
[00:55:40]
That's the designer of the doors fault, not the puller of the door.
[00:55:47]
It's not their fault.
[00:55:48]
The puller of the push door.
[00:55:49]
The puller of the push door is not at fault.
[00:55:52]
And well, I mean, your ruin always references this Elm philosophy idea of take responsibility
[00:55:58]
for user experiences.
[00:56:00]
And that it is is a great philosophy, I think.
[00:56:03]
And I think LMS PA does a great job embodying that of like taking responsibility for creating
[00:56:10]
nice user experiences in these ways, but also giving the right extension points.
[00:56:15]
And and I will say from experience, it's hard, it's hard to create a meta framework in Elm
[00:56:21]
because like Elm doesn't give us tools for doing some of these things.
[00:56:25]
For example, saying this module must expose these types and functions like a prototype
[00:56:32]
module.
[00:56:33]
There's no concept of that, right?
[00:56:34]
So by the way, have you done any?
[00:56:37]
I know of a tool that can do that.
[00:56:39]
Yeah, actually, that I think it's not a bad idea.
[00:56:45]
But you can do that with code generation.
[00:56:48]
Not kind of not kind of kind of why I ran into a problem with this with LMS PA where
[00:56:55]
in order to render just the view function, or you know, in order to plug your page in,
[00:56:59]
you have to expose the page, right?
[00:57:01]
If you don't expose the page, sorry, you get a weird error, you know, in the middle of
[00:57:04]
a generated code that says, sorry, in the previous version in v5, right, you would get
[00:57:08]
this crazy error saying, oh, generated dot pages dot Elm is looking for dot page, but
[00:57:12]
I you know, this module doesn't export it, you get this really like nested error in a
[00:57:16]
file that you're not supposed to see.
[00:57:18]
So what I had to do, I think is what Dillon's alluding to, which is like, check what's being
[00:57:23]
exposed and give them a nice error.
[00:57:25]
Yeah, exactly.
[00:57:26]
You have to intercept it.
[00:57:28]
So you can do it, but the error is terrible.
[00:57:31]
Yeah, yeah, you basically get an error somewhere else.
[00:57:34]
Exactly.
[00:57:35]
It's pointing to generated code.
[00:57:37]
That's the problem, which is extremely confusing.
[00:57:40]
And it I mean, it will prevent you from shipping the code and having users see the problem,
[00:57:46]
which is good.
[00:57:47]
But as far as like, take responsibility for users experience goes, it doesn't really hit
[00:57:53]
the mark there.
[00:57:54]
So it requires a lot of like clever design architecturally and a lot of like doing like
[00:58:03]
putting a lot of love into these little tricks to try to check things to intercept errors,
[00:58:09]
just to let the user know, oh, hey, you need to do this here.
[00:58:13]
And so when you see those messages, users just know that Ryan's put a lot of love into
[00:58:19]
giving giving you those nice errors.
[00:58:22]
We care.
[00:58:23]
We care here at LMSPA industries.
[00:58:26]
Wait, we're not all working at fruits.com.
[00:58:32]
So if you want to start an LMSPA project, you do LMSPA new.
[00:58:38]
Do you have any tips for people who already have a project that is using the regular elm
[00:58:43]
slash browser to start using LMSPA?
[00:58:46]
Yeah, that's a that's a good question.
[00:58:48]
So I mean, every I think that the trick is without the framework, it's all kind of the
[00:58:52]
Wild West of how things are structured.
[00:58:54]
I think the I'm going to assume at a baseline, people have followed Richard's LMSPA example
[00:58:59]
where you kind of have you kind of have your pages in their own modules.
[00:59:03]
If that's the case, it's really about I think the upgrade path, the easiest way to go forward
[00:59:07]
is to create that one and install the you know, Ryan NHG slash elm dash SBA elm package.
[00:59:16]
So you can start exporting these page modules before you need to call them.
[00:59:20]
So if you have your init, your view and your update, you can create those wrappers, those
[00:59:24]
page dot elements, page numbers.
[00:59:26]
And then once you've done that and gotten the compiler to be happy, there's always going
[00:59:30]
to be tricky stuff, I think, because when you give people the ability to return, I'm
[00:59:35]
going to think about like the view function.
[00:59:37]
Some people handle shared updates by extending the type of message that views can send out.
[00:59:42]
Some people handle that by extending the types of updates in it and update can do so it's,
[00:59:47]
it's really a case by case basis.
[00:59:49]
But I don't know, just using that incremental philosophy that you normally do in Elm where
[00:59:54]
it's like, okay, let's just see what what I can add before I break my whole system and
[01:00:00]
trying to reduce the amount of breakage that that one thing contributes.
[01:00:04]
But it's really hard to upgrade an existing app to it to anything like that.
[01:00:09]
And like if I wanted to upgrade something on pages, I'd you know, there'd be a lot of
[01:00:13]
work and that's just inherent to the problem.
[01:00:15]
So it's much easier to just abandon all of your code, run NPX LMSPA new and get a nice
[01:00:23]
clean project.
[01:00:25]
It's bug free.
[01:00:26]
I will say with it's bug free.
[01:00:29]
I will say LMSPA is a lot easier to go in the other direction though.
[01:00:33]
So if you decide that, you know, the routing is too constrained, I, you know, I'm not getting
[01:00:37]
the like, it was nice getting started, but now I want to have full control of my routes.
[01:00:41]
Maybe you ran into the tab situation you mentioned up there you mentioned earlier.
[01:00:45]
You can just stop running LMSPA watch.
[01:00:48]
You can move those generated files into your source and it's your custom app.
[01:00:52]
The transition from LMSPA to just a core LMAP is like seamless.
[01:00:57]
You just all of a sudden it's just LM code I'm generating.
[01:00:59]
So it's, and it's stuff that you would write yourself if you had the, basically the mental
[01:01:04]
model that the framework had.
[01:01:06]
Yeah.
[01:01:07]
Basically you don't ever regenerate it again and take the things that were previously generated
[01:01:13]
out of gitignore or move them to your source directory.
[01:01:16]
Like that's, that's the eject workflow, right?
[01:01:19]
Unlike, you know, create react app or something like that where the eject workflow is like,
[01:01:23]
okay, fine.
[01:01:24]
I'll give you the a web pack config and you can tweak it.
[01:01:27]
Like there's no secret file.
[01:01:29]
It's all yeah.
[01:01:30]
Yeah.
[01:01:31]
Zero configs.
[01:01:32]
That was another random constraint I gave myself.
[01:01:33]
I'm like, there will be no config no matter how hard people want it.
[01:01:36]
I'm like, I just won't do it.
[01:01:37]
Cause then everyone just gets the same average framework.
[01:01:41]
It's the same.
[01:01:42]
Yeah.
[01:01:43]
That is a forcing function that forces you to get those extension points right because
[01:01:49]
it would be a lot easier to hack around that with configuration.
[01:01:53]
So I'm glad you stuck with that.
[01:01:56]
Yeah.
[01:01:57]
So if you hate web pack configs, you're going to love lmspa because you don't have anything
[01:01:59]
like it.
[01:02:00]
It's not even, not even close.
[01:02:02]
So everyone's going to love lmspa.
[01:02:04]
They got to, right?
[01:02:05]
That's gotta be everyone.
[01:02:06]
That one guy out there, you know, it just starts tweeting at me after this.
[01:02:11]
I love web pack configs.
[01:02:12]
It changed my life for the worst.
[01:02:15]
That's true.
[01:02:16]
It changed all of our lives.
[01:02:18]
Yeah.
[01:02:19]
Yeah, it's true.
[01:02:20]
Yeah.
[01:02:21]
At least it was impactful.
[01:02:22]
These people know what it means.
[01:02:23]
At least people have heard of it.
[01:02:24]
You know, like lmspa needs to, it needs a few more stars to get there.
[01:02:27]
I think before lmspa can ruin everyone's lives.
[01:02:31]
That's my goal.
[01:02:32]
20, 20, 22 goals.
[01:02:35]
So where should people get started to learn more?
[01:02:39]
There's so the lmspa real world example is super cool.
[01:02:43]
Yeah.
[01:02:44]
Yeah.
[01:02:45]
It's so great when you, I gotta just like steal all these cool ideas from people.
[01:02:48]
So I stole that the real world example, Richard Feldman has the popular lmspa example.
[01:02:53]
Every bone in my body had to stop me from calling this thing lmspa sp example because
[01:02:58]
it's just so, it's so not funny, but I needed, I just really wanted to make the joke.
[01:03:05]
So yeah, there's, I will just fork the project.
[01:03:07]
I will do it for you.
[01:03:08]
Thank you.
[01:03:09]
Yeah.
[01:03:10]
I feel like internally that's what I called it, but I don't remember, but yeah.
[01:03:15]
So there is a real world example app.
[01:03:17]
Part of me wants to move that into the main repo just for ease of, you know, ease of discoverability
[01:03:22]
because there's really no reason that it shouldn't be there, but that's a separate repo.
[01:03:26]
I think it's called lmspa real world, which is under, you know, my GitHub Ryan and HG.
[01:03:32]
There's two ends in there.
[01:03:33]
The second is Nicholas.
[01:03:34]
You got to get those stars.
[01:03:35]
You got to get the lmspa real world stars in the lmspa repo.
[01:03:40]
That's true.
[01:03:41]
Yeah.
[01:03:42]
I got to accumulate the stars.
[01:03:43]
That's the model repo main benefit.
[01:03:44]
It's the star accumulation.
[01:03:46]
If you like any aspects of anything I've done.
[01:03:48]
Yeah.
[01:03:49]
Yeah.
[01:03:50]
I can tell if you split your projects into multiple repos, you don't get a lot of stars.
[01:03:54]
Yeah.
[01:03:55]
It's actually an amazing meta.
[01:03:56]
I like that.
[01:03:57]
Yeah.
[01:03:58]
There's also a bunch of examples on the core repo.
[01:04:01]
There's an examples folder.
[01:04:03]
You'll see it when you hit the GitHub repo.
[01:04:06]
It's designed to be easily navigable.
[01:04:08]
Is that a human word?
[01:04:11]
That's a human word.
[01:04:12]
Yeah.
[01:04:13]
It is a human word.
[01:04:14]
Easily navigable.
[01:04:15]
There's like docs.
[01:04:16]
The docs site is in there under the docs folder.
[01:04:18]
There's the examples, which has an ordered list of like zero, one, two, three, four,
[01:04:22]
increasing complexity.
[01:04:23]
But really I would go to lmspa.dev.
[01:04:26]
So elm dash sp.dev.
[01:04:28]
I've got guides there.
[01:04:29]
I've got examples.
[01:04:30]
Oh, you've got an Elm program test example.
[01:04:33]
That's super cool.
[01:04:34]
I do.
[01:04:35]
Yeah.
[01:04:36]
There's so many things I've made.
[01:04:38]
I get surprised.
[01:04:39]
Yeah.
[01:04:40]
Pat's rhino was good.
[01:04:42]
Yeah.
[01:04:43]
Pat's rhino is dope.
[01:04:44]
Props.
[01:04:45]
I wonder if I can use some more memory problems.
[01:04:51]
And of course the guide elm dash sp.dev.
[01:04:56]
It's a really nice intro.
[01:04:57]
Yeah.
[01:04:58]
Definitely check that out.
[01:04:59]
I have to say I really like that you made a website for the documentation this time
[01:05:03]
and not a list of videos.
[01:05:05]
Yeah.
[01:05:06]
Yeah.
[01:05:07]
I'm getting, well, it's like half and half.
[01:05:08]
Like some people are yelling at me like, where are the videos?
[01:05:09]
And some people are like, oh, I love the...
[01:05:11]
Yeah.
[01:05:12]
So there's no winning.
[01:05:13]
I think I need to make both, but then that just takes a bunch of time.
[01:05:15]
Yep.
[01:05:16]
A part of me wants to make videos again.
[01:05:18]
Because I think there's a certain type of person that learns really well.
[01:05:20]
Like me, I learn really well from videos.
[01:05:22]
Yeah.
[01:05:23]
But it's important to have those accompanied with words that people can read throughout
[01:05:28]
the train.
[01:05:29]
Yeah.
[01:05:30]
Oh yeah.
[01:05:31]
And we got search on the website.
[01:05:32]
So it'd be very, very hype.
[01:05:33]
That's exciting.
[01:05:34]
Woohoo!
[01:05:35]
You can type.
[01:05:36]
That is a local search index that I've made up.
[01:05:40]
That's not even...
[01:05:41]
It's just a thing.
[01:05:42]
Don't worry about it.
[01:05:43]
That's awesome.
[01:05:44]
But yeah, I would definitely go there and check it out.
[01:05:45]
Yeah.
[01:05:46]
Just run npx elm sp anew.
[01:05:47]
It's really easy to get started.
[01:05:48]
There's three files.
[01:05:49]
You're going to feel smart and you're going to make some cool stuff.
[01:05:52]
That's what I'd say.
[01:05:53]
And at this point is like, is elm sp a v6 mostly what you're hoping it to be?
[01:06:00]
And until you get further feedback that there's something really important or that's a really
[01:06:05]
good idea, this is pretty much it?
[01:06:07]
Or is there something like that you're kind of itching to clean up or improve in some
[01:06:13]
way?
[01:06:14]
Or where does it stand?
[01:06:15]
What do you want to break?
[01:06:16]
Yeah, exactly.
[01:06:17]
What should we be afraid to use?
[01:06:21]
So personally, I feel like this is the first release.
[01:06:24]
It took six of them, but this is the first release where I feel really good about the
[01:06:29]
overall architecture.
[01:06:30]
And there were so many pain points from the beginning that I had been eliminated with
[01:06:34]
each version.
[01:06:35]
And I feel like having access to the URL and the shared model everywhere, the save load,
[01:06:41]
not doing the caching stuff.
[01:06:42]
A huge driving motivation for me releasing v6 was how bad I felt about that caching problem
[01:06:47]
that I created.
[01:06:49]
For all these wonderful people using v5, the community is so kind and uplifting and encouraging.
[01:06:55]
Anytime I do anything, they're always like, hey, Ryan, you're killing it.
[01:06:58]
Thanks for all the free code you shipped.
[01:07:02]
So there's all these nice people out there that I was like, hey, cache all your data.
[01:07:06]
Lol.
[01:07:07]
I felt horrible.
[01:07:09]
So I feel good about v6.
[01:07:12]
There are some tweaks, but they would be minor tweaks.
[01:07:15]
If there's anything that I'd be even remotely considering as a breaking change, it would
[01:07:20]
be adding a variant, actually, to the protected stuff.
[01:07:24]
But I'm not convinced that's going to solve problems.
[01:07:27]
So I'm not sure if that's going to be released.
[01:07:29]
Would that be a breaking change?
[01:07:31]
It would be because there's a case expression.
[01:07:33]
It would be an incredibly easy breaking change to fix because you'd have one line of code
[01:07:37]
that you'd have to add saying, in this case, do x.
[01:07:40]
Wait, did you expose that custom type?
[01:07:42]
I definitely did.
[01:07:43]
Or maybe I didn't.
[01:07:44]
Maybe I'm a good guy.
[01:07:45]
Oh, wait, hold on.
[01:07:46]
I'm going to take a peek.
[01:07:49]
Maybe I'm a genius.
[01:07:50]
That's why you don't expose custom types.
[01:07:51]
Oh, I totally exposed the custom type, man.
[01:07:55]
Not a genius.
[01:07:56]
I needed it.
[01:07:57]
You didn't do the lower case.
[01:07:58]
I needed it because the generated code needed to switch off of it.
[01:08:00]
It's not my fault.
[01:08:01]
Oh, yeah.
[01:08:02]
That's another tricky thing with meta frameworks in Elm.
[01:08:07]
People don't know the pain.
[01:08:08]
They don't know the struggle.
[01:08:09]
And hopefully they never have to.
[01:08:10]
Exactly.
[01:08:11]
We'll hide it.
[01:08:12]
We'll take the pain.
[01:08:13]
Exactly.
[01:08:14]
But we'll also take the stars.
[01:08:17]
So don't forget.
[01:08:18]
We'll gladly take the stars.
[01:08:19]
We accept GitHub stars as currency.
[01:08:23]
It's actually funny how much we care about not introducing breaking changes or about
[01:08:28]
not introducing a major version.
[01:08:32]
I have some breaking changes planned for Elm review that have been...
[01:08:35]
Yeah, I've got some functions that are deprecated for a year now already.
[01:08:38]
And I just don't want to break anything for people.
[01:08:41]
Yeah.
[01:08:42]
But I really respect the rich hickey mindset of if you don't like break your code, just
[01:08:47]
give it a different name.
[01:08:48]
So, for example, it doesn't have to be a break and change.
[01:08:50]
What I did with the auth thing, I could just say, hey, if you want to use the new thing,
[01:08:54]
expose a different function with a different name that returns this new type.
[01:08:57]
And all of a sudden, no one's angry.
[01:08:59]
So if I go that route, I don't want a version bump.
[01:09:03]
The Elm package is 6.0.0.
[01:09:05]
That's so pretty.
[01:09:06]
If I make that 7 and then it's Elm SPV 6, I'm going to be the saddest man in America.
[01:09:11]
You should release a new package, a new tool called Elm SPA 7.
[01:09:18]
That's just the name, but it's V1 and then it won't be a breaking change.
[01:09:22]
That sounds like the opposite of what Microsoft did with their consoles.
[01:09:25]
We're going to call the new one, the first one, Xbox One, everyone.
[01:09:29]
Buy them today.
[01:09:30]
Yeah, that's an idea.
[01:09:32]
Yeah.
[01:09:33]
Well, awesome.
[01:09:34]
This was so fun having you on, Ryan, to walk us through these changes and kind of your
[01:09:39]
thinking on these topics.
[01:09:40]
But thanks again so much for coming on.
[01:09:42]
I still have one question that I really need to ask.
[01:09:45]
If you didn't have the other package taken, the other package name taken, would you switch
[01:09:51]
between Elm pages and Elm SPA?
[01:09:54]
Like who would have the right to Elm SPA and who would have the right to Elm pages?
[01:09:59]
Fight.
[01:10:00]
Okay, to the death.
[01:10:01]
I think there'd have to be negotiations in place.
[01:10:06]
Mine does have a lot to do with pages.
[01:10:08]
SPA is a horrible name.
[01:10:10]
It's not even accurate.
[01:10:11]
It sounds like SPA, which it isn't.
[01:10:15]
It is refreshing.
[01:10:16]
Yeah.
[01:10:17]
There are no cucumbers.
[01:10:18]
A single page app.
[01:10:19]
Well, so here's what it is.
[01:10:20]
A single page app is just an app that has multiple pages.
[01:10:23]
Yeah, it's like inherently a bad name.
[01:10:25]
But when people are looking for how to do single page apps, I'm like, okay, maybe that's
[01:10:29]
the right thing for them to Google.
[01:10:31]
Yeah, I'm glad Dillon had Elm pages.
[01:10:33]
So it was an easy decision to not use that, I guess.
[01:10:37]
So you would go for Elm pages?
[01:10:39]
I would have to choose, which would be tricky.
[01:10:42]
I mean, there's no real conflict.
[01:10:43]
It's a Ryan Elm pages, Dillon Elm pages, choose your favorite.
[01:10:47]
You could do Ryan Elm pages.
[01:10:48]
Exactly.
[01:10:49]
I would not.
[01:10:50]
There's so much confusion already.
[01:10:51]
It's like, what do I use Elm pages for?
[01:10:53]
I'm like, this stuff.
[01:10:55]
If they're both the same name, that would just be cruel.
[01:10:58]
Exactly.
[01:10:59]
What about you Dillon?
[01:11:00]
I actually think Elm SPA is such a commonly used term SPA for describing how do I do X
[01:11:08]
in Elm.
[01:11:10]
X is SPA, right?
[01:11:11]
It's not pages.
[01:11:12]
So I think it's perfectly named.
[01:11:14]
And then we both get to have our own unique package name.
[01:11:18]
So you're saying Elm pages is the best name?
[01:11:20]
Elm pages is the best name.
[01:11:22]
Thank you Dillon.
[01:11:23]
Elm pages is good.
[01:11:25]
I'm on team Dillon for this one.
[01:11:28]
Ryan, you could do Elm pages under your name, V1.
[01:11:32]
V1.
[01:11:33]
Ooh.
[01:11:34]
And then it would look like I never made a mistake.
[01:11:36]
That would be good.
[01:11:37]
I like V6.
[01:11:38]
V6 shows like what happened.
[01:11:41]
It's like, you think you get it and then you think you get it and then you really think
[01:11:44]
you get it and then you didn't get it and then you thought you got it and then you nailed
[01:11:48]
it.
[01:11:49]
So that's where we're at here with V6.
[01:11:50]
I think that's our intro cut right there.
[01:11:53]
That would be epic.
[01:11:55]
I hope it is.
[01:11:59]
All right.
[01:12:00]
Well, thanks again, Ryan.
[01:12:01]
So if people want to keep up with what's going on with Elm SPA, with you, we haven't mentioned,
[01:12:07]
but you work at Blissfully.
[01:12:09]
If people want to find out more about Blissfully, where do they go to find all that?
[01:12:13]
Yeah.
[01:12:14]
So Blissfully, you go to blissfully.com.
[01:12:15]
That's the job I work at.
[01:12:17]
I get to work with Matt Griffith, the guy that made Elm UI.
[01:12:20]
We're hiring.
[01:12:21]
So come through.
[01:12:22]
Wonderful, wonderful people there.
[01:12:25]
Are hiring Elm developers too?
[01:12:27]
Hiring yeah, we've got back end developers particularly, but yeah, we're definitely hiring
[01:12:31]
developers in general.
[01:12:33]
Yeah, if you, yeah, we've got an office in New York.
[01:12:36]
I work remote.
[01:12:37]
A lot of folks work remote.
[01:12:38]
So don't be afraid if you don't live in New York to apply.
[01:12:42]
But yeah, you can get a hold of me.
[01:12:44]
I guess the only thing I'm on is Twitter and I just unfollowed everything because I just
[01:12:49]
gave up on social media completely.
[01:12:51]
I only follow Elm just because I thought that would be cute, you know, just to have the
[01:12:55]
one, I saw like Jon Stewart's following like Arby's and I'm like, I need that with Elm.
[01:13:01]
Just the one following.
[01:13:02]
But yeah, you can follow me there if I ever share any social media updates that will be
[01:13:07]
Elm related.
[01:13:08]
I will not be posting gifs of like puppies or anything.
[01:13:12]
I've given up.
[01:13:13]
But yeah, elm dash sp dot dev is the number one place to go.
[01:13:16]
Check out the GitHub repo if you like it.
[01:13:19]
The Elm SPA Slack channel as well.
[01:13:22]
Elm SPA users.
[01:13:23]
That's your social media.
[01:13:25]
That's my social media.
[01:13:26]
Yeah.
[01:13:27]
And if you're using Elm SPA, we do have a channel in the Elm, the official Elm Slack.
[01:13:31]
Elm dash SPA dash users.
[01:13:33]
And one day we'll be official enough just to be Elm SPA because there'll be no confusion.
[01:13:38]
It'll be the Elm pages channel.
[01:13:39]
That'll be V9.
[01:13:41]
Cool.
[01:13:42]
All right.
[01:13:43]
Well, thanks so much Ryan and Jeroen.
[01:13:48]
Until next time.
[01:13:49]
Until next time.