Build web standards-based sites with Enhance
with Brian LeRoux
Enhance is “designed to provide a dependable foundation for building lightweight, flexible, and future-proof web applications.” Maintainer Brian LeRoux will show us how it works.
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone. And welcome to another episode of Learn with Jason and I'm just realizing now I've pointed my camera in the wrong direction. So we're going to fix that so I'm standing in the middle of the frame. Today on the show, we have Brian LeRoux, how you doing?
BRIAN: Good, how you doing?
JASON: I'm doing great. I think this is going to be a lot of fun. We are doing one of my favorite things which is like playing with new tech that is old tech. And that's my favorite kind of tech. And so, I'm really, really excited to talk about that. But before we dive into exactly what we're working on today, let's talk a little bit about you. Do you want to give a background for folks who aren't familiar with your work?
JASON: Yeah, I think this is going to be a lot of fun. And as a fellow grizzled, we've got a lot of the same battle scars and the same formative experiences which always makes for a fun like back in my day kind of conversation. [ Laughter ] :totally, and we're in one of those moments right now. It's cool to talk about the resurgence of maybe older practices are coming back.
BRIAN: There's so many forces at play here. So to understand why not using the platform became a thing. I think we've got to rewind all the way to mobile.
JASON: You know and I even saw somebody was sharing there's like an intent to ship about multi page transitions. So it's now like in motion. It's coming.
BRIAN: Yeah, and that's great, right? I love that this is something that's been very consistent in the last decade. But not always where we see the browser really driving. There was a dark period where there was no innovation in the browser and looked like it was going to be a dead platform. Thankfully, FireFox held on long enough for other browsers to emerge like Chrome and change that story, and now Chrome's really pushing other browsers into the future whether they want to go there or not. [ Laughter ] And it's not going to name any names on that one. But it's nice to see. And everyone is you know pushing that innovation really hard. I never thought I would say this, but Microsoft is now a leader of the web. And it's great.
JASON: You know, it's funny because they you see these sort of shifts and everything in terms of innovation and I think when in the days of Internet Explorer, Microsoft was one of the reasons web was hard to work with.
JASON: Once they shipped Edge and put Edge on chromium, and you could tell the ethos shifted and they're interested in the web and open source and the acquisition of GitHub with the maintenance of VSCode it's clear they've shifted their strategy. They're making a community based.
BRIAN: Usually when you see a company on the back slide, that's kind of a that's really hard to correct, it's an avalanche and tens of thousands of people's inertia pushes in this anti open source direction and that company couldn't be any more different today and reflects in the market cap.
BRIAN: They listen and they responded and they're creating really great products for the web.
JASON: It's been really impressive to see. Yeah. I've been super impressed by the just the full about face in the presentation, like, you know the positioning of Microsoft, one, has been incredible to watch shift. And also, the actual ethos, when you talk to Microsoft employees, it's different from my experience in the early 2000s.
BRIAN: Oh, big time. And you know, it's not just talk, they're shipping all the time. We're getting new versions of just about every part of the stack now from Microsoft and some of them are even really good. And I don't know, like, between GitHub Visual Studio code typescript, I think they probably have a strangle hold on something like 90 million developers. So that is an incredible achievement considering that, like, not that long ago you would not have associated Microsoft with this level of innovation and contribution to the web and open source. So, it's cool.
BRIAN: Yeah, back then V script was valid, too.
JASON: Yeah. I was writing Flash, I was doing all sorts of interesting stuff trying to make anything dynamic on my site.
BRIAN: Sand down the rough edges.
JASON: You reach for a framework because you knew you had to smooth over the inconsistencies, this that's how you end up with the synthetic events in React and all of the different pieces that were basically like a lot of code to make sure things behaved consistently across the different platforms they'd be deployed to.
BRIAN: Yeah the browsers were their own worst enemies, evergreen is a nice way of saying the browser updates itself. And we take this for granted. Yeah, latest version of Chrome, yeah. That did not used to be the case. You would have whatever version came with the OS and likely that was 95 or something. And your parents weren't downloading a new version of IE, it was you Christmas morning. And that was horrible. And so as a web developer, our hands were tied. If we were going to support a feature, we would have to basically go to the lowest common denominator.
BRIAN: And a lot of the things we used to complain about are actually just built in and sometimes we don't even realize it and take it for granted. And this all happened kind of messy, like, it wasn't like here you go, beautiful ES, you know, 6 syntax. It was this slow, painful, incremental browser by browser rollout. I remember it wasn't that long ago where I had errors in Node because somebody wrote a module that used const. And couldn't update that version of Node because it was running on a server. And it was a mess. Now I've got to go compile this other thing to have a let because const isn't here.
JASON: And this was the magic of that age, like, you know, you had so J Query, right? Got this undeserved bad reputation as being an unnecessary tool or whatever. And
BRIAN: That's the question. And I love that encapsulation of it. I think it's a perfect way to look at it. And this isn't there's another aspect that's really important for people to understand and that computing isn't this zero sum thing. So J Query's success, you know, didn't mean there couldn't be a React. It precipitated the React.
BRIAN: And likewise, you know, other technologies becoming successful won't make the existing ones go away. So it doesn't like, you know, this isn't some death for Next.js and React. It's worth asking, just worth asking, maybe can I do this without these tools? And in a lot of cases, it's very possible. Probably for most cases, you can get a lot of these without any third party tooling, without a transpiling step or without having to wait for a build, which is worth looking at it.
JASON: I'm going to use that as if least the least subtle transition of all time. But let's talk about Enhance. [ Laughter ]
BRIAN: Yes, it was a good build up to it. And I think it's perfect. So this was the sort of question we were asking with Enhance. I've been focused mostly on how do we make backend dev better for the past few years. And we have a framework called Architect that lets you build with Cloud functions. We have a very specific way of building that we call functional web apps, which is essentially building apps clearly out of CloudFunctions, so servers here. And what does that mean? How does that change our development world? But the whole time you're doing that, everyone kept asking us, like, OK, cool, backend CloudFunctions, how should I do my frontend? And we would say, however you want. And people would say, well, did you just tell me to go eff myself? [ Laughter ] And we're like no, man, you can do whatever. Public folder's sitting there waiting for you to compile something or not. And they're like, how do you do it? Well, we return HTML and we progressively enhance it. They look at me like I was a lizard. Like, no, I'm serious. They're like, you can't do that. Why not? You can return JSON text, you can return HTML, it's the same thing. And that idea was generally considered a little bit nuts, but we persisted with that line for a lot of years and then, actually, I think we were talking to Matt Dillon here a little while ago, what are you going to do? We think we're going to do a frontend framework. And he was like, that's a terrible idea. [ Laughter ] And I know where he's coming from. So like, in my former life on the phone gap project, we were like don't pick a framework because there's a new one every week. And if you go into that fight, then you're going to die in that fight. And that was, you know, pretty common knowledge. And generally, I think this is the philosophy of Netlify where it's like create a big tent, don't get involved in that drama because it's an ever changing thing. And people will always claim, well, now it's stabilized. But there's another six frameworks behind that last one. That's OK. We want diversity, we want selection, we want options, lots of choices. That's a good thing. We're not trying to create a monoculture. But we did keep running into the same question. And so, eventually, we were like, OK, cool, we're going to package it up and we're going to show you how we would build the frontend for the functional web app and what that looks like. And that became Enhance. And so, the fast bullets of what Enhance is, it's file based routing built on Cloud functions using web components and web standards. And that's it. If you want to try and build an application today, most people are going to reach for a component library of some kind. Might reach for a React or Sveft. We're suggesting make HTML can do that job. And it's worth exploring and maybe it'll fall apart on you and you'll have to jump into React. But at least for the first step, you should try and build it with HTML and see what happens because you'll probably be pleasantly surprised. And you know what, you will run into a situation where you're going to need to update that DOM and that's the moment to grab React rather than starting with it.
BRIAN: Yeah, there's a quote by, the quote goes the chief cause of problems is solutions. And I love that because it's so true. And like, I have a pinned Tweet on my profile that builds on that idea where I say, you know, the best solution to a problem isn't a solution, it's to eliminate the conditions of that problem. And so, it's a subtle thing, but as we add tools, solutions, dependencies, tools dependencies, we're creating vectors for new unforeseen problems because we're creating a more and more complex system. And we get taught early on it's like, oh, you use this tool for that problem and this tool for that problem. And we just sort of think and learn that our industry likes to pretend we're doing engineering, but engineering is not picking the most popular thing. That's not how this works here or else we'd still be building stone castles because those were popular. So everyone builds a stone castle. We don't do that. Engineering is identifying the problem. Either trying to eliminate the conditions of that problem or solving that problem in such a way that is better than, than before and not adding to the big problems that you didn't know you had. So, you know, if we were objective, we would do bake offs more often, measure performance and latency, wouldn't look at the marketing material. GitHub stars. You know, those aren't going to solve your problem. And there's safety in numbers, so I understand why people do this, like, you know, what's the most popular thing? And that's usually a pretty safe way to act. But if you're trying to be an engineer, you'll probably want to invite some rigor into your selection criteria and treat this as an engineering exercise and not a big deal. And especially, not a part of your identity. You attach your identity to a framework, you're going to be prototype JS guy, what the hell?
JASON: And I think the other thing, too, if we're talking about being in for the long game, right, there's short term success to be had by jumping on the next trend and becoming the premier expert in the next thing. But that sort of sets you up for a series of sprints where you're going to figure out the new thing and you're going to learn the new thing and you'll ride that wave. And that wave dies down. And then, you've got to run to the next thing and do it, again.
JASON: And there's a marathon approach that's not as flashy, but and OK, I'm going to couch this with a big old caveat because I'm not saying, I'm not implying that you have to learn things the way I say you should learn them. Please, don't take that as what I'm trying to say. What I have found in my own heavily survivorship biased experience is that taking the time to learn the fundamentals has made my career feel less panicky. Like, when I'm seeing people talk about
JASON: When React was on the rise, I was like, cool, let's find out what this is all about. And now people talking about, I don't know, maybe are we looking at what comes after React? And I'm like, bring it on, I'm so excited. I can't wait to see what people come up with. Instead of worrying my livelihood is going to go away because I hitched my whole wagon to any particular tool, or any particular concept.
BRIAN: Yeah, and we should be OK with debating ideas. We should be cool with skepticism. And we should also be cool with, you know, embracing the diversity and all of the bonuses that come with that. So we can take a sprint and try it out and compare it to Svelt, look at the bugs, how are the docs, what's the licensing like? How are the cadence of releases? Do they have changes that create unplanned work? These are objective questions, not insults or anything. If you're a dev shop and you're on the hook to deliver on a fairly regular cadence, which typically most of us are. Having unplanned work due to breaking changes because one of my dependencies decided to change something is a major bummer. Hurts my cadence and my ability to get my job done and go home at 5:00. So there's and it's tricky because we also want to be stoked about all of in stuff. We don't want to be a bummer and make people feel bad about their choices. And it's a delicate line to walk.
JASON: Mm hmm.
BRIAN: And the other little bit I want to key into, there's a controversial topic around what are fundamentals? Lori Voss at Netlify has an awesome presentation about, you know about what's going on in the world. He likes to rag on there is no fundamentals, you wind down to teaching sand to think or whatever. And I get it, he's not wrong. So there's problems with say Full stack, too. I've been doing this for a long time and I can stand up a fleet of web servers, but I would hesitate to call myself full stack, which is kind of funny because you see a lot of devs out there, full stack, that's a static website. OK. And you don't want to trash on anyone, but where are we in this world? And this is a challenge because we don't know. And this makes it hard for us to understand like where to go and what to build.
BRIAN: There's no right or wrong answer here. I do think, though, even if fundamentals do or don't exist, the basics do. I would consider HTML and CSS are basics in our craft when you start learning to program these days, you most likely are going to stand a website and the first thing you'll get taught is probably a paragraph tag. And you'll do a little hello, world, and you'll see it on the screen and you'll be hooked and you'll be like, wow, thank god, I can change this screen and fix it to the page. And that is a snowballing effect that is wonderful and amazing. And we lose the plot, though, we pick tools. But I heard this the other day, I don't know about web components because there's more React developers. I'm pretty sure there's more HTML developers than React developers. You're going to have learn HTML in order to understand what JSX is. It's a bit of a facetious argument anyways. Who cares? They don't know it, teach them. Buy them some courses and learn it.
JASON: That's I think that's that has been a big part for me is recognizing that, you know, it's like anyone can learn these skills, right?
JASON: The thing that is harder to teach is pragmatism and a willingness to have knees discussions and a willingness to work with the team and not dogmatically push for I know things so we'll do thing. I just watched Scott Hansilman speak a couple weeks back. And there was this quote where he said, are you do you have 30 years of experience? Or do you have the same year of experience 30 times? [ Laughter ] And I think about that a lot because it's
BRIAN: That should keep you up at night.
BRIAN: It's a good one. Have I been spinning my tires for 30 years? Yeah.
JASON: Yeah, exactly. Right? And I think if you're out there trying to learn, trying to grow, you're not stagnant. I do think it's interesting to see where have we looked at our own career development and said, OK, I'm done, I don't need to learn anything more about that.
BRIAN: That would be horrible.
JASON: But I do think that it can be tempting, right? Like I and we do this with certain parts of our lives all the time because you there's not enough hours in the day, right? So we're always making choices on what we want to optimize for.
JASON: Sometimes, it can be really tempting to optimize for ultra deep specialization in one very narrow band. And that is a really valuable skill. I had a whole conversation at Jamstack Conf about what that means and the difference between a specialist and generalist and how that plays into different aspects of your career. I don't have the text of that, I'll Tweet it when it's out if anybody wants to hear that. It was a good conversation. I don't want to rabbit hole too hard because we are
BRIAN: It's a double edged sword, though. Something to call out on this one, there are a large amount of disaffected Flash developers and they were mad and they got betrayed and that was a disaster for them financially. And, you know, so there is a thing to lock in, there is a thing to making a bad bet and paying for it and in the fullness of time. So, you know, this is another reason for me to be really bullish on the web always because those skills are always going to be with us as long as the web is. And I'm sure it's going to outlive most of us, it's a good one to bet on. Companies proprietary compiler, there's not a great track record there.
JASON: Yeah, right? And we'll see the influencer of that compiler in the next compiler, learning the things is valuable. It's all stackable bricks to get you to where you want to go. But yeah, the more the more timeless something is, the less of it you have to re learn every three or four years.
BRIAN: You can debunk.
JASON: Yeah, and my React knowledge is super transferable as I'm starting to look at things like Solid or Preact or so forth. It's easy to step into the frameworks. I'm getting a lot of value from each of those things I learn. But OK. We are at we've got about 50 minutes left. And I want to make sure
BRIAN: Yeah. We should get into it.
JASON: I'm going to flip us over into the paired programming view. So let's do that. Here we are. Camera 2. So the first thing I want to do is I'm going to just do a quick shout out to the captioning. We have Diane with us today. Taking down all of these words and it's on the home page of the site. So you can go and check that out if you want to follow along.
BRIAN: That's so great. Thank you, Diane. That's wonderful.
JASON: And we are talking to Twitter.com/Brian LeRoux. I'm so glad I got that right on the first try.
BRIAN: I'm impressed.
JASON: So go give Brian a follow on Twitter, lots of good insights there, and you know, you can follow up on Architect framework, Enhance.dev, and we are specifically talking today about Enhance.dev.
JASON: This is the framework, it's a very web standards based framework that is as you said, your attempt to kind of pull your ideas around what a functional web app should look like into a reusable framework.
JASON: So typically, if I was going to get started, I know we would you've got a quick start here I could follow. I'm going to ignore all of that. Use you as my quick start. What should I do first?
BRIAN: So, the quick start is kind of generic. And I'm going to recommend scrolling down a little bit and clicking on Deployment in the left nav bar. And there's a begin or deploy with Begin. Yeah, the second one. And the reason I'm going to get you to do this is because it's going to give you a generator. And we won't have to do as much typing.
JASON: Got it.
BRIAN: So we we're very old school node developers and a lot of us have built things in this modular fashion, which is a double edged sword. So there's lots of ways to consume Enhance, consume it as an NPM module, you can consume it as a binary, and then, the Begin CLI gives you like all of these basically ripped off all of rails generators. So did that install for you?
JASON: Yes, and I need to move this. I'm going to take my Z shell off screen because I can't remember what's in it. [ Laughter ] I don't want to I don't think I put anything in there to worry about.
BRIAN: I've made that mistake.
JASON: All right. So I am exporting more paths. And so I remembered how to exit. We're in great shape. Bringing this back over. OK. We did that, I'm going to source my one more time. And now, I should have yeah, there it is. All right.
JASON: We'll Begin version, I'm using oh, I did verbose, I need the type out version.
BRIAN: I think it prints out at the bottom. You're on the latest. So there's a mini quick start in there. And I think it's just Begin new, give it a name of some kind.
JASON: OK, and it's going to create the folder for me?
BRIAN: I think so. [ Laughter ]
JASON: So let's do nav
BRIAN: We'll learn together.
JASON: I'm going to put it under Enhance. And it is installing my dependencies for me, and now, if I go into here, we can see it's there. I'm going to get in it.
BRIAN: Yeah. And I think you can run Begin dev in there. And you should see a little howdy happy screen. So, people always ask us, might as well get through this now. The little character it's a salamander of some kind. And he flies and farts rainbows. [ Laughter ] We're going to build a mythology around the axleauto. Maybe let's look at the source that generated. I could walk you through what the files are all ability.
JASON: All right. So I'm going to stop this. I'm going to open up VSCode and we'll pull this up here. They did this thing where they changed the way this works and it I love it and also I'm very confused by it. Here we go with we've got
BRIAN: Use your you convinced me to move my file tree, by the way.
JASON: Yes, another convert. [ Laughter ]
BRIAN: I saw I was like, actually, that would lose less space and you're like I'll show you in two seconds why. Yeah, that is better. [ Laughter ] I'm totally on board. So what do we got here? A package JSON, good old friend, our node modules. We add a lint config. There's a whopping one dependency. We have some types. From typescript if that's your gig, you don't have to use it, we find it helpful in some cases. And let's see, so you have a public folder, public folder is where static assets go. You can, you know, put whatever you want in there. We've got some silly SVGs. And we generate a utility based style system for you. And we end up inlining this in the head. If you're familiar with the tail wind, it's like that. The difference between it and Tailwind, we recommend people try and use scales. And create a responsive design based on breakpoints that are actually in your web components. We haven't written a lot about this yet, but if you embrace the utility style thing, you can max your CSS out at around 25 kilobytes which is great because you can inline it in the head and you don't have to worry about the growing because you're just using utility classes everywhere. And those get zeroed out by your CDN. So you'll always have the smallest possible style sheet while adding and growing your HTML and your components. Some people don't like that. Some people find it hard to read. That's cool, it's CSS, you don't have to use ours, you can use your own, use SaaS, whatever you want. You can put it in the public folder, happy days. We think there's really good reasons to embrace this way of working. When you combine it with custom elements, there's a ton of benefits. Especially in CSS, we've been on that project where CSS file becomes this depend only.
JASON: Right, right.
BRIAN: You're just building up this huge, massive file and becomes unmaintainable. So, yeah, anyways and then, the last, most important bit here would be there's an app folder. We, too, thought that was a cool idea. It has a pages folder. The pages folder works the way you would think. If we add an about.html, we would get a route for about.html, let's do it. Just add some rando HTML. Yeah. So and this is actually a good oh
JASON: Oh, I forgot I'm not running the server.
BRIAN: All good. Yay.
JASON: There's our about. And we go back to the home page.
BRIAN: So this is a thing. Now we have these two pages, we'd probably like to navigate between them. Wouldn't it be great to have a reusable navigation component of some kind?
BRIAN: In your terminal run Begin gen page and give it a path.
JASON: OK. In here. Right?
JASON: Control Z. Doesn't work. Why is that not working?
BRIAN: Oh, the background it?
JASON: I was going to background it. I control C' d and now I'm going to begin.
BRIAN: Begin gen page and dash dash path, I think. And then, I don't know, do like no, dash dash name. Sorry. And then do my dash header. No, begin gen element.
JASON: Oh. All right. Because we're making a shared element.
BRIAN: That's right. Yeah.
JASON: OK. So we've got our shared element. And now the app folder has elements in it.
BRIAN: Yeah, let's take a look at my header. So this is just like the most generic basic element you can get. In Enhance, you define custom elements as pure functions that receive an HTML tag template literal function and then you return that HTML.
BRIAN: That's a mouthful, but basically what you get is a pure function. And when we render HTML on the backend, we're going to call these pure functions and render out your whatever your custom element is. So in here, since this is the header, let's add some mark up to it where it's like got a couple of anchor tags, maybe anchor to home and anchor tag to about.
JASON: We'll do a home and that's going to have an Hraf of one of these.
JASON: And we'll say, neat, and then we can have, you know, nav and our nav has we'll grab this, get rid of the rel on it and this one's going to be home. And this one's going to be about.
JASON: And we can get rid of this one. I want to talk about that state stuff, though this looks cool.
BRIAN: Yeah, we'll get into that. It is cool.
JASON: Don't you argue with me your HTML element. It's fine, it's helping. So now I've got this, this is working. I'm going to leave that out for now so it stops yelling at me.
BRIAN: Yeah. And we want to go to about an index and add a my header.
JASON: Collapse the style, we've got do you do like that? Or do you have to?
BRIAN: You have to fully close them. I don't know why, I think there's a spec reason for this. This is one
JASON: We've got one of those in here. We're doing another one in here. And start server, again. And now we've got Tah dah!
JASON: That's like the name spacing to get away from potential future element conflicts?
BRIAN: Yeah, it's an interesting hack. Custom elements are naturally name spaced and built ins aren't.
JASON: Mm hmm.
JASON: I still don't know. [ Laughter ]
BRIAN: The two is how much we're going to indent it and I can't remember what null is for.
JASON: Yeah, there's something is it the serializer?
BRIAN: Something like that.
JASON: Replacer. Replacers you can
BRIAN: Custom function. That's right. That's going to come up all the time. Anyways.
JASON: I know
BRIAN: So I like to throw my de bugger at the bottom of the page. And this just makes life easier as you're developing, you're going to be able to see what's in the state object that gets passed around.
JASON: We can throw it in the bottom of both here. One of these. OK. I have a question, you in your index.html, you're not setting up the HTML, the body, the head. I did in my about HTML, should I not have done that?
BRIAN: Yeah, you should get rid of that. And we have a special function for doing head. And then, the body and all of the rest of that gets reaffied for you.
JASON: I'm in here, my header, debugger, I'm going to reload and down at the bottom, we have our setup, go to my about page, which is a little bit easier to read because it's all compact up here in the corner. Actually, make that a little bit bigger. Attributes in our store.
BRIAN: OK. Yeah.
JASON: What happens? What do I do next? I go in here I want to try something and see what happens.
BRIAN: It's a whole thing.
BRIAN: I don't know if we should get into any of this. But at the end of the day, HTML, the spec, this isn't me, this isn't Enhance, I wouldn't have designed it either. It's how it ended up. But in HTML, the absence of values is considered falsely, and the presence of values is considered truthy. But even if you have the first part of an attribute, so the name, that would be considered truthy. And so that's a long way of saying, we can't have nice things. [ Laughter ] And you've got to have fully realized string names and you have to check for the string values and I'm sorry it works that way. I know it shouldn't. Life's not fair. I don't know what else to say. It's a hard thing. [ Laughter ] We actually have a whole page in the Enhance docs about this and feels like we're apologizing, but it's just like, it's just how it works, nothing I can do. Everything's a string. Typescript's not going to save you, it's how browsers work. Yeah, anyways, attributes are a thing. And you can pass them on your elements and they're pretty good for simple things. You don't want to use them for, you know, heavy complex types. So if you have, typically our applications are going to have collections and those collections are going to be full of objects or maps. You don't want to put those in the attribute, that's going to lead to a bad time. That's what the store is for. The attributes are more for switches and values. And so, the store is now interesting. How do we populate that store? So when we first started doing this, we did this really like kind of elaborate reach around with web sockets and then we started to develop what we called API routes. And we actually went for the simpler things. API routes in Enhance are just like pages where you define function on a file based routing path and return JSON values. If we have a matching API route to a matching page route, we'll automatically populate the store with those JSON values for you.
BRIAN: That's a lot of words, let's jump into the terminal and do Begin gen API. And I think it's path. But just type help. We can see. You can do that, too, just try it. Begin gen path.
JASON: You were right.
BRIAN: Path and then let's say about so we can just try this out.
BRIAN: And jump over to the API route. And so, here's the cloud function. And actually, now that exists, I think if we refresh the about page, we should see
JASON: I've got to restart oh
JASON: OK. All right.
JASON: Export async function post.
JASON: And do post stuff.
BRIAN: All credit where it's due, this is similar to how Remix works, actions and loaders, we call it get and post.
JASON: Right, right. And does yours support like patch, put, delete? Stuff like that?
BRIAN: It does and options if you want to do that.
JASON: And options is a big one. The core stuff is such a pain if you don't have that.
BRIAN: Yeah. Yes. [ Laughter ] That is a whole thing. And actually, if you want to get a peek into the request of the object in your return on line 11 there, pop a key request, it should reflect that back. There it goes. And you have everything at this point. You've got the entire request object. You've yeah, this is all based on AWS lambda, so we just pass that straight through to you, the exact same style of parameters. And you can do with this as you will. Most of the time, the only thing people are going to be interested in here will be cookies or session. But it can be helpful to grab query string values or parameter path values, that kind of thing.
JASON: Yeah. Well, and this is I've been playing a lot with using cookies for things, you can see I've got some of my other local dev stuff.
BRIAN: I like that Edge function themes switcher. That was dope.
JASON: For folks who haven't seen that. I wrote a post on how to get away from the flash of inaccurate color. What Chris Coyer has dubbed FART. The thing that's really funny and upsetting about that, it's been referenced in the spec. So it's an actual name of the thing as cannonized by the WC3 at this point.
BRIAN: That's perfect.
JASON: Thanks, Chris. [ Laughter ]
BRIAN: You can't take yourselves too seriously. That's exactly what we need. You get everything in the API routes. That's fun. This is obviously very raw in both level business here.
JASON: I just saw a comment, too, that we can keep it running in one terminal and then I've opened a second one to run the generator and it should just pick it all up for us.
BRIAN: Hope so. OK. That's cool. I never remember what these arguments are. And I've been doing rail since it came out. If you do begin help gen scaffold, or any of those parameters. That will help, too.
JASON: OK, scaffold
BRIAN: Yeah, that's it.
JASON: Whoa. We're going to use this one?
Yeah, copy/paste that. This is the rails thing. You and this will take a second because we've got to install the AWS SDK. I wish we didn't need that to do this but we do. Your internet's fast. Right on.
BRIAN: That generated a ton of stuff. Let's go take a look at how it works before I talk about this code because there's so much of it.
BRIAN: Jump over to
JASON: It set up a whole page for me.
BRIAN: It did, page, routes, all kinds of cool stuff. We've got a Bocks page.
JASON: Wow, OK.
BRIAN: We can do the CRUD thing with the book.
JASON: OK. Sunny Mannerism.
BRIAN: I was going to say management for the rest of us.
JASON: That's a good one. Actually, I'm totally going to do that. [ Laughter ]
BRIAN: I think everybody should buy this book. I just bought it.
JASON: It's an incredible book.
BRIAN: I bought a copy for a friend right away. It's not often we get good, timeless knowledge in this industry. I think Sarah pulled it off.
JASON: Sarah is definitely one of those people who just gets it. And this is a 2022 book. We'll save it.
JASON: Now, we've got a book.
BRIAN: Got a book.
JASON: All right. We can edit.
BRIAN: Yeah, you could edit it. That reloaded the whole page, too, like a savage, you were just posting
JASON: Like a savage.
BRIAN: So we could progressively enhance this if we wanted to, but I think that whole request response like will probably complete within 100 milliseconds. You've got to ask yourself if you're adding anything or just wasting time. So let's go take a peek at the code that got generated here. Because there's quite a bit going on now.
BRIAN: Rails, this was the thing with Rails, gave you so much speed out of the box. Normally, setting up a database crud app is a lot of work. There's a whole bunch of stuff that has to happen. We need a route for each of the update deletes, we need a database, need a schema for the database. It's a ton of work. So the scaffold thing isn't going to give you production ready you know, going to scale massively code. But it's going to give you that first cut. And then, you can go in there and start playing with it and making it better. Under the hood, this uses lambda for the compute and dynamo DB for the database. It will scale really far.
JASON: Got it.
BRIAN: That, too, is a double edged sword, we were being DBOSed recently and we didn't find out until we found the bill later the month. Serverless worked, scaled right up. We're like, what's going on?
JASON: This is one of the things. I have really become like a die hard serverless fan. Because we did this thing at the beginning of the pandemic, the COVID19 tracking project, and a group, started working on that. And they built it at Netlify. And a lot of their database was API data they were scraping and serve it serverlessly. It would return the data from the API and went from 0 to 2 million uniques pretty much overnight. And the only reason they knew is they saw the analytics.
BRIAN: And there's a chance that 2 million uniques were still in the free tier.
JASON: Could have been.
BRIAN: For the compute side, it would be it's like 2 bucks for the first 2 million and then 10 cents for every million after that. Sub $10. The data can get expensive, the data is expensive and hard, so that's understandable to me. If you're if you have a big Dynamo bill, you probably have a valuable service.
JASON: I would certainly hope so.
BRIAN: Yeah, cool. Let's take a look around. Pages are just HTML usually, but they can be a custom element. And in this case they are, we're dealing with state. You're going to want to have, you know, some imperative logic. In this case, you know, it's Enhance page container and it's got really basic map. We're not doing anything special in here, no syntax that doesn't run in Node natively. This is getting that state, looping over the books and pumping out the mark up for those books. And it gets that state from that companion API route. So at slash books, we'll have a get function somewhere that is going to be pulling the books out of the database and populating that in the JSON response that comes back ultimately to show this page.
JASON: And so this is doing something we haven't seen yet for folks who have are maybe looking at web components for the first time or haven't gotten very deep. We patched in as an argument to the page container.
BRIAN: Yeah. Yep. And that is slightly different. So this page is a custom element. And I think if you look in the source of the rendered output, you'll see there's a wrapper element around all of this.
JASON: Mm hmm. Page books and we've got the page container.
BRIAN: And then it just, you know, unravels all that or expands all of that mark up for your dynamically at runtime and you get, you know, the resulting HTML, which is quite nice.
JASON: Right, right. This is great. And so, then we've got the books itself, which is the edit form. And it looks like this is also handling post, which is really that's cool. So we just submit it to itself.
BRIAN: Yep, that's it.
JASON: All right. So I want to poke into the generated the generated code here. So books itself is getting into our models. So we didn't look at models yet, should we look at those first?
BRIAN: We can look at this first and look at the models. This is a pattern that we keep seeing. If you wanted to, you could just write straight up Dynamo calls in here. But that gets really ugly and now your code's going to have all of this Dynamo all over it. I don't want to run a Dynamo.query. I want get books. Adding that by encapsulating the model is nice. Won't be exposing my HTTP business logic with my database logic. So when we're dealing with an HTTP request, we're often pulling off keys from suggestion and doing some kind of auth step. And you don't want to mix that up with the database business. This ends up being really, really quite lean. There's not a lot going on here. OK, if there's any problems, request.session.problems, we're going to display those. This is a weird pattern frontend devs might not be used to. When you're posting forms across pages and there's an error, you have to return the errors somehow to the original page. And often when we do a post, we want to follow it up with a 302 or 303 redirect. There's no way to pass that state unless we put it in the session. We call that problems? Because they're not errors. They're like, you know, you spelled something wrong or maybe the you didn't meet a password length requirement or something like that. So in the line sorry 14 there, we're pulling the problems off of the session. Pulling the book off of the session and then we're rewriting the session without either of those things on line 16 and passing the JSON problems. That's a long winded description for what's happening. But the reason we display a form with problems, we don't want that to stay there forever. We only want to show you the problems after you've had them. We pull them off of the session and re write the session on the way out. This is not natural. We're used to having everything in the browser state. But now, you've got to think about state in the browser and the server and crossing the boundary between pages and session is your tool to do that. And you absolutely introduces some complexity but gives you a lot of power, as well.
JASON: You know, this is funny because, you know, I know that everybody keeps making the call back to PHP. [ Laughter ] But in my PHP days, I remember writing this kind of code.
JASON: You had to create a session and putting stuff in and plucking it out so you're making sure the right state hits the right places at the right times.
JASON: And that is very you're right. I do think there's a reason that people, you know, turned away from PHP towards some of the browser only implementations of this. But the thing it seems like the reasons to doing that, that gap is narrowing.
JASON: With a little bit of DX syntax sugar, this becomes a thing that will get done for you.
JASON: By the framework. So I think this is the part where for anybody who is looking at this going, like, oh, this is way harder than just building it as an SPA. You're right, but that's by design. We need to feel out how the patterns work with the tools we have today and we'll build the polish on top of it.
BRIAN: Exactly. And I think as soon as you get a database involved, you'll have a session. As soon as forms, you'll have one. It's a necessary complexity. And the other frameworks will have these built into. Might not be obvious at first, but Remix has a session, so does Astro. Another knife in your boot. It's not something you have to use, but you'll probably
JASON: And I want to clarify, chat, I don't think you sound like that when you talk. [ Laughter ] All right. So what do we want to do from here? Where should we go look next? I guess we've got more. We've got our post function.
BRIAN: Check out the post. The post does similar things. We are encouraging folks to create separate path for validation. So reading, writing, updating, talking to your database is a separate activity for validating user input, you do need to do both. But you probably want to have that business logic not mixed up. So, we've got this little validate.create. And if it finds any problems, we pop those on the session and redirect back to the books form. If there are no problems, then we're going to try and do an upcert here. If it's good, we redirect back to books, going to do a fresh query and write out those books into the
JASON: Got it. And upcert is when you either update or insert if the book exists, you update whatever changed. If it doesn't exist, you create a new entry with it. It's a portmanto of update and insert.
BRIAN: Yes, and it's a handy pattern. It isn't always correct. But I think it works in trivial cases. If you get into more dynamic data, eventually you're going to have to update individual attributes on that data and you won't want to do these wholesale creator update things. But a lot of and this is just a life cycle thing. If I'm using a database for short lived access tokens, for example. I'm going to create a magic for logging in, for example, and have a token that expires in 10 seconds. Upsert's dope for that. All I need to update is probably a refresh or a timing.
JASON: Mm hmm.
BRIAN: A user account, first name, last name, birthday and a bunch of stuff that might change, now at that point, upsert is probably not as useful. You want a discreet way of doing it. Rail splash, it's back. Every framework has a brand session in its own special way and Rails, they like to call it the flash. I remember being deeply confused about that. Like, this isn't flash. [ Laughter ] Now, nobody cares.
JASON: OK. So we've got a post and then, if we look in here, we've got this other set around the books itself. So this is a pattern that we've seen before where we've got the name of the route, like,/books, but then we also have these place holders for ID so that can be the specific key of the book.
BRIAN: Yeah. And we've ripped this off of Remix. There was a lot around this. In Architect, we have path parameters are colon, we took that from Express. But colons in file names has a bunch of problems, so does dollar signs, it turns out. It felt the least problematic.
JASON: Mm hmm.
BRIAN: We don't want to end up in a situation where we have programming language embedded in our file based routing. And I think there's a lot of people experimenting with that right now. And it's probably not going to work out super well.
BRIAN: So we decided there's two use cases as far as we're concerned. It's parameterizing parts of a URL and giving them meaningful names, that's what we're doing with the dollar sign ID. We're saying in this part of the URL, we're going to pull that piece out dynamically when the route matches and give that to you as the name ID. And that's handy because then we can do, look up based on path parts. The other pattern is greedy catch alls and we decided to call that dolla dolla bill and it's two dollar signs instead of one. Those are good for the end of a URL. They're very greedy, they're going to capture everything. And you really don't want to use these unless you super need to. Otherwise, you're going to end up writing a router inside of your router. And that's a really yo dog situation. And you don't need to get yourself into that situation. It's got built in routing, use it as most you can. And if you absolutely need to get a full path part, then use a catch all at the end.
JASON: Yeah, my experience with catch alls, it's when I'm building something that is absolutely more complex than it needs to be. And I have looked I have looked myself in the mirror and I've stared into my own soul and said, you know, I'm OK with that.
BRIAN: It's a thing, we did a fancy route where it was going to reach into an S3 bucket and pull the files we never knew how deeply the path would be. It could be in a whole bunch of folders. That's the perfect moment to use a catch all. When you've got a catch all and you find yourself parsing the URL for meaning, that's when it's like, there's going to be
JASON: It's time. You've got to be like, all right, self, is this who we want to be? [ Laughter ] P.
BRIAN: Yeah, changing the semantics of how this might work. It's an avoidable pain point if you can. It is handy and you need it sometimes.
JASON: It falls into a category of programming. And really just of life in general I've started referring to as voluntary suffering. Where you for the sake of principles or interest or chasing something that was interesting, you opt into a category of pain that was definitely not required.
BRIAN: In the Rails community, I think we would call this, it's a knife but the handle is also a knife. It's a useful feature, you've got to be really careful with it. You're going to cut yourself. Like named path parameter parts are almost 99% of the time. And if you stick to that, you're going to be OK. That's catch all routes. Probably also the most advanced feature.
JASON: Mm hmm.
BRIAN: We quickly drop off into simpler boilerplaty stuff here. We've got the create and read and then on the ID path or when you're viewing it, you would get a book probably.
BRIAN: And then, we probably just reuse the upsert for the post.
JASON: Right. Looks like this is validate.update and then
JASON: Yep yep yep.
BRIAN: Line 47 or whatever. And the final boss to the crud app would be the delete. And this is all the same conventions where we've got sort of the rails flashy thing going on. Delete's the book. 30 lines of code, not too bad to get started.
JASON: Pretty excellent. And so, we've got about 4 ish minutes before I'm going to start tearing us down. Anything you wanted to show for sure before we wrap?
BRIAN: I think that was all of the major hits. They can go to the website and dig in further or join our Discord or find me.
JASON: We'll do a round at the end. We've got a couple of questions. Dev is asking about the choice in organization. There's a technical separation between elements, pages, API models, events and this is a kind of a horizontal split by type as opposed to a vertical split by feature or slices. What made I guess how did you make the decision of going over here is my books folder with all of the pieces inside of it versus here are all of the different components and there's a books piece in each one of them?
BRIAN: You can reorganize the stuff how you see fit. We're not militant about that. Actually, it is all config uroable under the hood. I think there are just different ways and I don't agree that one's maintainable and one's not. I've worked in large codebases that have strong conventions not based on feature and I've worked in ones that do. And they both have benefits and drawbacks and ones with strong generic hierarchy in the file system structure, I find personally a little easier to navigate when I move between projects. So yeah, this Architect project and this other one don't have the same domain, but if I'm looking for a route, I know where that is, looking for a model, I know where that is. So there's tradeoffs. I might not know what the domain name is for a feature or a particular expertise of what those things are. The grouping thing is more esthetics to me than practical. But there are escape hatches for you to re organize this how you see fit.
JASON: Yeah, and I would kind of agree that my experience of file structure is that file structure itself is not what makes something maintainable.
JASON: The thing that makes something maintainable is the team having the right set of agreements and social dynamics on how they manage things.
JASON: And being consistent about it.
JASON: I've definitely seen some who buddy stuff going on where the naming was so very carefully shedded over and everybody was very, very sure it was perfect and then the very first day, somebody just like YOLOs something that technically follows the naming convention but absolutely not in the spirit of why it was the way it is. You're like, this is no longer useful. Right out of the gate, we've blown this whole thing up.
BRIAN: Yeah, and I feel like we were really spoiled in the rails days by having strong conventions and we sort of lost that in the last few years. Any rails developer can move between any rails projects and be productive pretty much immediately and that's an effectively unheard of capability between React projects. Between same version of the React frameworks that are out there, like, moving between them requires understanding the domain of how that was organized as opposed to understanding the system that was being used to generate the organization. So
JASON: It's very interesting to me seeing the because there are very good reasons to do both, right. Convention of like everybody does everything the same way, it leads to I would sometimes a little bit of things become overwrought when they don't need to be. And you're like, it would be great if this was one file, somebody just shared
BRIAN: Oh, that one.
JASON: Just one file, right? And so, I love that. I love the idea of yeah, it's a little simple app, just do whatever you want. But there's definitely a threshold beyond which you're like, that was a it's like we needed some organizational structure. And everybody inventing their own organizational structure for every project has a huge amount of drawbacks. So there's this bloat up front for manageability later versus do whatever you want. But now, you really have to do it all yourself. And I don't know what the right answer is, because I think the right answer like all things is it depends.
JASON: And the thing that I always love is I will think about one of these problems and I will feel like I've reached a decision. For me, this is the right way to do it. And I'll immediately invalidate. Next project, I'll be like, that was the exception, this is not going to work. [ Laughter ]
BRIAN: I mean, and that's probably fine, right? We're all still learning, hopefully. And there's just going to be trails, I love the single file thing. We get that feedback all the time. I'm going to put this all in one file. You don't, though. You're going to hit a point where you want a second file. You're not going to put all of that logic in one place. But you want to have things that make sense to be logically grouped. It's just this constant thing. There's a Wikipedia page about this, the law of triviality. If you bring something up during the code review, chances are, you are. And you shouldn't do that because it's toxic.
JASON: All right. So we've got about 3 minutes left and I want to make sure we've got enough time to go through all of the resources. We're in the docs, we've shared the docs, where else should someone go if they want to dig in and work with Enhance?
BRIAN: We're all kicking it on Discord these days. That is probably the other main place. And I think you find our Discord
JASON: Where is
BRIAN: Top right, maybe not. Let's see. That's hilarious, it used to be in the top right.
JASON: It was on the home page. So we'll I'll drop the link from here.
BRIAN: Yeah, it's in the right hand bar of most pages. Where it says community GitHub Discord.
JASON: Do I have it in am I too yes. I collapsed it too much. There you go. So we've got the Discord here.
BRIAN: We're there a lot.
JASON: Where else? Anywhere else?
BRIAN: No GitHub and Discord, those are the main places. And I'm on Twitter still probably.
JASON: For as long as it stays up, we're going down with this ship.
BRIAN: Yeah. Yeah, man. That service, it's horrible to see it being done so dirty.
JASON: Fingers crossed this is the dark before the dawn, we'll see how it goes.
BRIAN: I think so.
JASON: Yeah, we've got Twitter, we've got the docs, we've got GitHub, we've got Discord, lots of places to go and check out Enhance. I'm going to give one more shout out to our captioning. We've had Diane with us all day taking all of this down, thank you so much. That's made possible by our sponsors Netlify, NX, New Relic, thank you for making this show more accessible to more people and helping me keep the lights on. Appreciate that very much. While you're checking out things on the site, take a look at the schedule. We've got all sorts of good stuff coming. You can follow on Twtich if you're watching now. That will let you know when things are coming. You can add on Google calendars so you get a thing on your calendar that shows where each episode is happening. Or you can follow on YouTube where we just got our now you can go to @learnwithJason on YouTube. Brian, thank you so much for spending time with us today. This was a blast.
BRIAN: Yeah, thanks for having me. I also want to say thanks for sending me this little buddy.
JASON: Yeah! We got a Corgi dog on the stream.
BRIAN: I meant to pull them up, but we didn't have any major bugs.
JASON: That's like bittersweet, right? We got the Corgi on standby and then no bugs.
BRIAN: Christmas is coming, buy these for your loved ones.
JASON: Thank you, thank you for the plug. I very much appreciate that. Marissa will be very happy if you buy these Corgi ducks because I still have hundreds of them. [ Laughter ]
BRIAN: That's funny.
JASON: All right y'all, with that, we're going to call this one a success. Thank you so much. We're going to find somebody to raid. Brian, thank you, we will talk to you all next time.