 Welcome to this Supercharged livestream. I'm Paul and I'm Surma. He's my favorite of all the Surmas. Today we're gonna build a router. Now strictly speaking a router, well it's not a UI element is it really? Typically. But it's in control of you transitions particularly in something like a progressive web app and somebody recommended this sort of suggested it on Twitter and we talked about it and we thought yeah why not let's give it a go. And actually I realized as I was thinking it through that there's plenty of opportunities to do some some fun stuff in there. Not least of which will be some custom elements. We're gonna give that a whirl today. I haven't done much with them. They have just seemingly landed for reals in a bunch of places. Anyway we're gonna give it a go. What happens? Who knows? That's why we've been watching it I suppose because anything could happen. Cool right. As usual a couple of caveats. Firstly the code will be prototype style code. It won't necessarily be like production ready always worth mentioning. There may be accessibility issues and things like that that would also need to be sort of dealt with before taking it further. But I'm gonna be mainly focusing on something that hopefully will be performance and something will be a good first iteration. Alright so that out of the way. As always I'm gonna be here in the chat and on Twitter looking for the questions that you have because as always you have the chance to actually influence where we are going with this and interrupt us and maybe confuse us and make us more bugs. Yeah you interrupt him. He interrupts me. It's all good. It's like real life. It's fine. It's fine. It's fine. I'm gonna code now. Right so what we get on the screen. Yes so one of the things I want to say is that I'm gonna be building this router as though it was a single page web app where all the content is gonna come into the page on the start and the reason for that is purely for simplicity at this stage so that this live stream doesn't run for like hours and hours and hours. So bear with me. Right so what I'm actually gonna do is I'm gonna drop in I'm gonna drop in a custom element. I'm gonna call it up. Do you know what we could have come with a like let's call it super nice. I'm gonna call it super router super root. I'm gonna call SC for supercharged. There you go. We got some branding in there. Why not? That's great. It's a really good start. Script. Why not? Source equals static. Let's do this static scrouter.js. It seems like I would want to do. Right let's drop in this file and new file scrouter.js. Just like that. I'm gonna do JS. So recently I told you about my project where I was building a router and I was really proud of it and I told you about it and how I used all these fancy techniques and you were like I totally did that half a year ago and I have new ideas so thank you for making me feel like it. I'm actually hoping I will. Now you're making this sound like a mean to you. You are the nicest. I'm the nicest something. It's fine. Anyway, you are a decent work colleague decent. You are a possible work colleague, Paul. I put up with you most days. So good. Right. Document dot register register Alan and we will gonna call that what we call it. We call it scrouter and we'll go scrouter. Now, if this works, we'll do a attached callback, which I love the name of that because that's like Don't need extends. Yes, I do. I do extends HTML element. Thank you. Extends that and we'll do console dot log attached. Look at that. All being well, let's see. So I don't myself unexpected number. What do I do a number in line two? Hmm. That's weird. Wow, we have an issue. That's that static. There we go. Let's try that. Yay, it's because I so what I've done is I just so you know, because I'm expecting that we'll have deep links like, you know, slash about slash whatever we for our different sections that we're going to root between. I want whatever URL I go to when I hit refresh. I want it to come back to the same index HTML. I'm going to root to the same index HTML. And so I've set up a an app engine, like single file Python kind of thing that just roots does that rooting for me. So what happened there was it was sending me to the wrong file. So that's good. I think the whole thing is called HTML5 rooting, which is something that on the front, it is very popular using push state and actually using proper URLs. But all the development servers don't necessarily have good support. You always end up writing like three line Python file or three line go file to actually emulate this entire behavior. Yep. Okay. So in the attached callback. So what we want to do is we're going to do let's see window dot add event listener. So we know that we're going to get a pop state. We'll do this dot unchanged, I guess. Let's see. So unchanged. We'll do that now here. Unchanged. There we go. And then we can do detached callback. So if we remove to remove this router element, do window dot remove event listener. You know what I've realized? I'm going to do this dot unchanged. But I'm going to have to do it like this. Are you going to do the poll that was special? Because otherwise, it will be it will be run against the event. So created callback. There might be but we find out created callback is otherwise would be binding over like creating new bindings every time it's attached. Right. All right. Let's do that. Sorry. Fine. You're here to help. Hello. Let's find out created callback. Now there's one. Let's do that then. That's like, see, in classes world, that would have been the constructor, right? True. So there we go. So we created so every time we create one of these, we'll create one of those. When you attach it great, detach it, we'll get rid of that. That seems good. So other thing we'll probably want to do is we'll actually probably want to call the on change. So my on change is going to be the thing that I think is going to be watching for whatever the current path is. And then it's going to be the one that decides to what to do with the views. I guess one interesting question for this is where do you draw the line? What the job of a router is? What what is it supposed to do? And what is outside of its scope? What are you planning on putting into this route in particular? Okay, so yeah, that's a really good question, because one of the things that I've discovered over doing routers for a good number of years is that, or let me let me put it another way. The mistake that a lot of people seem to make is they make their router kind of only passive. So it's only ever watching the URL change. I've done that. I've felt the pain. So then what you do is like another part of your code you're like, I'll change the URL changing here, change it again, change it here. And the router is kind of going, do I now control the view and switch, you know, switch that out? Or who's doing what here? And you get this is really uncanny valley. If everything goes through the router, it's active as well as passive. It's the one that changes the URL. And it's the one that controls everything. That one tends to work out much better. So that's the model I'm going to go with today. And I feel I agree, like, it feels a little bit weird that the router should influence certain visual aspects like changing classes or actually triggering animations. But once you get over that, it feels so good and it feels very robust. So I think it's a very valid concept for for router. Okay, look, so what I want to do is I think, let's assume we got so, like I said, this is gonna be like a single page app where all the contents in the HTML. So we're just going to switch between these views inside the HTML. A better version of this will be something that loads those views, you know, over fetch or something like that, and then populates dynamically. But for time, I'm not going to go with that today. I'm just going to do something else. So let's just do call app view, something like that. Not a super charge view. No, I felt I felt like I mean, I could was that make you happy? Let's make you happy. There are a super charged view. Let's have a few of those. And let's say this is like the about and this is the I don't know. Actually, let's make this the like the home view is going to be about contact and some kind of misk, misk, that'll do it. Right. So we've got home about contact and misk. And what we each one of these we're going to do, I suppose, is we need to have a route for each one of those views. So I'm going to put like a root attribute on here. And I'm going to be like, I'm going to make it as a regular expression, because that might be helpful. So if we say it begins with home, in fact, the home will just do is the forward slash. And then it should end with that. Yeah, so that will be fine. Root equals about it should have the slash gone. You'd sound like you're about to interrupt. Yeah, we have a question. Yeah. So which is kind of mean because I made you use the created callback. And now we're being asked no constructor, but create a callback. I know. And I think it's just in the in terms of custom elements, it feels like you should more rely on the actual lifecycle callbacks than the constructor. You know, the constructor doesn't get called at all. No, interesting. So if I tell you what we'll do is let me just finish this up contact. And we'll do a mess here. Let's do this where we do constructor at the top. Constructor console.log Hello world. And the reason is, as far as I understand it, this, the register element is going to take the prototype. And all these functions are going to be on the prototype. The constructor is the instantiator. It is going to be on the actual, as it were, the function in old school terms. So this one should never be called all being well. See, we have our thing. So since the constructor is never called, you do actually have to rely entirely on those lifecycle callbacks. So in terms, if somebody doesn't know, classes are just syntactic sugar on top of functions. So all the code that you have in a constructor is in that function that you can use with a new operator. In this case, this has never been used because we are using custom elements API. So it will take care of ripping out functions from the prototype and actually putting it onto an element that the constructor is just being thrown away effectively. Yes, at this point, SC View. So I'm going to make a new one for the view. And we'll do SC View. And then we're going to do document dot register elements. And we'll do SC View. And then we'll do SC View here, like so. And we don't want the constructor anymore. We want, let's see, we do get root. And we will say return. One of the reasons I like this, I need to extend HTML elements again, return this dot get attribute. So because it's an actual HTML element, it's actually really quite nice. Well done to Rob Dodson for suggesting that I do this Bob Dodd. The Doddinator is also known. He suggested he was like, why don't you use custom elements? Good on him. All right, so get attribute root or null. And it's actually viable to use custom elements. The polyfill is six kilobytes gzipped. Yeah. And it even works in Safari. So and it makes your app so much more structured, I think. I think it's like I 10 plus as well. Wow. So it's fairly well supported. I'll drop a link in the chat. Good. Right. So when we attach what we want to do is I think we want to do this dot create roots or something like that. Let's do that. And what we'll do is pop that there. And we'll do document. I'm going to do this kind of a decorative way. Query selector all or SC view, I do for let view of that. So because it will give me that and I can do if view dot root, that should work. If not, continue. Continue. So if we don't have a root for some reason, view dot root, I can say new regular expression, because I want to make a regular expression around that. And I want to make it case and sensitive. And then I could do let's see. So we need it. Okay, so this dot. Oh, I tell you what we'll do this dot create, create that and then view. And then we need to actually make this right, which will be the root and it will be the view. And then we'll say this dot roots dot set root view. And we can say if this dot roots, because I'm going to do a map here has look at you, I know return console dot one root already exists. Because we don't want multiple roots being handled by the same thing here at this point. I mean, again, you could an improvement to this will be something that's a lot more nuanced in terms of the roots it supports and stuff. But I'm again, I'm not going to go there. Just at this particular point. Let's do that. Actually, I made my code angry. So let's do that if we've already got the route otherwise do this. So we need to actually create one of these. So the created callback, we're going to do this dot roots equals new map. And what we'll do is when you attach it, we'll do this dot here. So we can do it in the create roots. Now this dot roots, if we do clear, let's do a clear roots function. There you go. I'll do it. Create roots. Clear roots. There we are. This dot roots. Clear should clear the map. So just to summarize this, you're grabbing all the sc view elements on the page, you're grabbing the records out of the attribute and building a map that maps from the root to these individual elements. Yes, I am exactly exactly what I'm going to do. And let's just make sure that this is actually working console, I say working, we're just going to just, I mean, you could use the debugger statement here. But for me, this might just be faster. I was going to say faster, but maybe not. I don't know if cross sector is iterable. Maybe you need to do array from, array from takes an interval as well. That should work as well. Let's do Chrome Chrome. See which version is up to date. Let's see whether it's localhost 8080. Yeah, you see it's in the it's in the new new Chrome. I wonder whether the Chrome I had there was a little bit on the older side that might very well have happened. Let's switch to canary then. Or we just do array.from, which would also work. Zoom in on all of the panels on all of the things. There you go. Good man. Good point. Well made, sir. So since that didn't actually fire, though, let's just let's just find out what's going on console.log view, because we expected something from that. We definitely get those we get all the elements. That's nice. View dot root. So let's see if Oh, I know why I know why because I have the router, but I don't have we don't have any JavaScript for it. There we go. So now they're actually they're actually being instantiated and handled and all that kind of stuff. And that's great news. So now we've got a map with all the routes and the views. What we'll do is let's throw in again, you would probably componentize a little bit better than I'm doing SC. Let's just do style, super styles, super styles.css, why not? And we'll do a link. So we have a couple of people in the chat who apparently are not that familiar with the years 2015 updates on the JavaScript language. I encourage you all to look at it and and use it because it makes JavaScript so much better of a language. Yeah, the amount of pain reduces in just addressing certain problems that you usually encounter when writing apps. It's so good. I actually love it. It's my body padding zero. Hopefully you can still read what I'm typing, you know, I know it's a bit different. But hopefully, yeah, that's what that's the old one, old Chrome, let's switch across that from there to there. Okay, so that's working. And additional information, years 2015 used to be called year six years 2016 was year seven. Yes. And now we but we have since they're planning to do a release every year, they're sticking to the year based. Yeah, yes, there'll be no yes, anything below 2015. Right? Yes, we just skipped 2000 versions. Yeah, it's good. That's fine. It's fine. There's nothing wrong with that. But it's actually really helpful. I think because it kind of puts people in the mindset of it's not just this major release version. I don't know why they chose it, but I hear and I'm like, it just kind of gives you a rough idea of when this thing actually landed, you know, unless and the support for me is amazing, like, across browser now, like it, even a year ago, it was like, Oh, you need a transpiler. Now, you know, if you're on an Evergreen, it's really good. And if you're not, you've still got the transpilers. Most bras have like 99% support very features for all of years. Yeah, it's really solid. We're right back to the code then. So what I'm going to do is I'm going to make each view. I'm going to do like position fixed, top, zero, left, zero, right, zero, I'm going to do the the right and bottom zero thing. I'm not going to do with 100%. I've improved as a human. Okay, yeah, I knew you wouldn't believe me. So that would in theory, place all the views on top of each other like that, which is fine. Let's see. So I'm going to do opacity zero. And I'm going to do, let's see, personally, I'm going to do pointer events. And I'm going to assume that we'll have some kind of visible. This is the active view class. So let's do a visible, visible. Anybody who's seen my Io talk knows what I'm doing here about using point opacity zero and pointer events non. The reason I do it is when I want something to be primed and ready for for animations. It's not always perfect. But basically, if I set visibility to hidden or display to non, they'll be removed from the render tree. This way it should be a little bit more primed and ready to actually might bring the view in. But again, this will be a trade off because you've potentially got all these views ready to go. And so if you add lots of them, again, it's I think a more advanced version and we can come back to this if you are enjoying the the router. When we're done, we can come back and we can do a another live stream where we take it on and do like the more advanced stuff that we probably won't get time to do. We'll find the entire thing. Yeah, the more features that you may have been requesting over Twitter, for example. Yes, which is why you should be on the chat doing the whole Hi, I have ideas because that helps us point about auto right. So when the view is there and when it's visible, we'll do that. So that's fine. So we'll actually have nothing on screen. Because they've all been set to hidden, which is fine. What I'll do is I'll just do like class equals home. Oh, maybe just like view home, something like that. We got view about you about you contact the MISC. That's good. So what I'm going to do is I'm just going to color code these so that it's kind of a little bit more obvious background, red, that's going to be bright. Contact is going to be a blue. Let's see what else did I have at home, my MISC. That was the last one. And about about. Okay. I think. Yeah. I hope I'm going to screw you over right now. No, I'm sure you're not. It's going to be black. We'll do color white. And background green. Wow, this is going to be really horrible. Oh, well. Paul writes tremendous code once again, 24 pixels. Let's do font family, family aerial sun. Okay, so rules kind of set, except for the fact that now we've actually got to make the router do its thing. And for that, I think we're going to have to have a nav. So I'm going to create a nav. So we can actually kind of toggle between these various sections. So let's see, you'll do it. Oh, this is the point where somebody goes use emmit because you're being so slow, Paul. It's like fair enough. And I still haven't got to doing that, you know. So we've just been asked that you very prominently keep saying as long as you do all your stuff in 100 milliseconds, it's fine if you want to start an animation or something. Yeah. So and apparently, and on desktop, obviously it works in under 100 milliseconds to just attach something new to the DOM have it resturized. Yeah. So keep in mind that this should also work on mobile. And mobile devices are not as fast at restoration. So that's why we have to resort to actually keeping it not only in the DOM but actually having to keep it painted. Yeah. And actually opacity zero might actually be there might be an optimization, I think in Chrome that basically would stop that being painted. So we might have to work around if we see a big sort of kind of a big green flash when the view first shows up. I'm hoping we won't see that today. But we might. But yes, whoever's asking that question? Absolutely. So we have this performance model called rail. If you tap something and you expect to something to sort of happen on screen in response to that tap, you want it to happen in a 10th of a second. Otherwise, it doesn't feel good. It just feels laggy. And that kind of upsets users. But whoever's saying is like, when you attach something, it takes a long time to kind of get from zero to something that you can show is absolutely right. And that's why you've got to be really tactical about kind of attaching and detaching things. And it's a trade off because you've got memory constraints and all that kind of other stuff. Right. So we have, if I'm not confused, yes, we've got a nav with a bunch of links to the various sections. And let's see, what do I want to do? I want to actually style that. I'm just going to go go ahead and just style the nav directly today. Now I'm going to do position fixed. Oh, right. 10 top 10 pixels. And I'm just going to say background. And I'm going to do a box shadow because why not? Not two pixels, four pixels, RGB, 255, 255, 255, 0.3. I enjoy that one. Padding white shadow. Oh, you're right. Zero. You've written that particular line of boxer that I think a million times. I'm just I don't know what's going on with me today, dude. Border radius. That's what I mean. Yeah, three pixels. All right, it's all being well. We ended with some kind of yeah, okay, it's not the prettiest, not the prettiest top, right, bottom left. Just do you have an harmonic device to remember in which order top right bottom left is compass? Oh, east, south, west. Why are they doing a clockwise mathematical order would be counterclockwise? Oh, I don't know. But I just remembered as never day alert, northeast, south, west. So there you go. Anyway, so it thinks done there. Now, by default, as I say, this would actually take you to these various sections, which is absolutely what we want. So you can again, in the kind of the perfect world scenario, the server would actually just respond with the HTML for each of these pages. In my case, it's responding with the same HTML, which, as I say, is just to keep things simple. So it's not very visible. But right now, it's an actual link with an actual complete site reload. Yeah, and that's really it is actually an important thing that we progressively enhance, especially if you're making a progressive web app with the kind of clues in the name. And again, part of this is like, taking real links, and then we're going to hijack them. But it means that you can actually get to the various sections if JavaScript is disabled, or there's some kind of error or just something goes wrong. You know, it should be that it's a link, and it should work. So that's what I'm trying to do, at least trying to maintain it, at least in this simple version, as I say, you could be a little bit more advanced about it. Right. So the other thing I need to do is I'm just going to, this is going to be pretty raw this bit, I think. So what I'm going to do is I'm going to say document.query, select to roll, and I'm going to ask for all the anchors, I'm going to do for let link of that, I'm going to do link.addEventListener, onClick for clicks, and onClick function onClick. This is one of the bits that is not production quality properly. We're hijacking all the links. Yeah, we don't care, we just, right, prevent the default, and then we're going to do what we need. We're going to say constRouter equals document.querySelector. So for the people, we have gained a lot more views in the meantime. So for the people who joined a little bit later. Hi. Hi. This is Paul. Hi. This is Surma. And we are building a router. So we are building the component actually handles transitioning between the different views in your app. And hopefully we'll do it in a very nice, elegant way. And we're actually using the custom elements API that's around. So we're building our own elements. I mean, it's all new to me, but that's the point of being a web developer sometimes, isn't it? You know, try new stuff. I mean, there's always new stuff to try. We're never short of new stuff to try. So far, yeah, we've basically got ourselves some views that we're going to transition between. We've got ourselves a non-visible element for the router. And we've got then some JavaScript that we're kind of working our way through. And at the moment, I'm just hijacking these anchors here. In fact, I'll tell you what I'm going to do is I'm going to grab the, let's see, the nav anchors. So it's just the anchors there. So the question I did, Tyson, with another question we had in chat. Yes. The question was, what does defer mean on a script? And I actually know the answer to this one myself. Go, go, go, go, go. So defer means that the evaluation and execution of the JavaScript will be postponed until the entire HTML document has been parsed and put into the DOM. So that this way, the script tech becomes non-blocking. So if you have script tags at the top, and you have defer, you won't block until this JavaScript is run, but it will continue parsing the HTML, put everything on screen, and then execute the JavaScript. And into that, I want to remark that you have referred your custom elements JavaScript, but not the one that executes, but you've used the API of the router. Will that work? Good point. The defer, I don't know, we'll find out. The defer also means that these should be executed in order as well. That's the other thing. That is very important to know. There are bugs in older browsers where that doesn't necessarily end up being true. So you've got to always be careful. You might need a script loader. Again, I'm just operating with a certain bunch of assumptions, but for production, you'd have to probably figure some of that stuff out. Should we find out whether it actually works? Yeah, that would actually be very interesting. Well, I don't see any errors. That is amazing. So I'm going to call that, and it says router.go is not a function because I haven't actually written it, so we should add that. So when you call .go, this would be the active part now. So I'm going to give it a URL. I'm going to do window.history.pushState, and I'm going to say null, which is the state object, or is that the title? No, it's a state object, then title. Then the URL. Yeah. So we want to do that, and then we want to say this.onChanged. So we're going to push the URL, and then we're going to basically, in the same way, when you popState here, we're going to check what the current URL is. So then we will now need to go in here, which is that onChanged, and we'll say this.roots. Hang on, what we need to do, I'll tell you what we'll do, is we'll say const path, yeah, window.location.path name. How exciting. We're going to ask that, words for words. Here we go. Yeah, yeah, that's the one. We're going to actually ask what the path name is, and then what we're going to do is we're going to, let's see, for, what actually do we want to do for? No, I'll tell you what we'll do. const roots equals array.from, and we're going to do this.roots.keys. So this will be all the different regular expressions, right? Yeah, so we're going to do that, and then we're going to say const root equals roots.find, and we give that a callback function. So if the root is, if we test it against path, so that works, that should be if we don't have a root, we can return. So basically this is if we don't find a match. Now if we did find a match, this will be the bit where we now need to kind of, kind of start toggling views and so on. So let's have a think about this. So we need to find out which view it is. So const view is going to be roots, this.roots.get, and then we're going to get the from the root, and that will give us the view back. And oh, we're probably going to want to keep a track on that, so it's the current view. So if it's the current view, there we are. Actually, no, let's tell you what we'll do. We'll do const new view. And so we can say if there is a current view, bear with me. I think this is going to work. So we know when it, yeah, yeah, yeah, okay. So there's a current view, thinking it through. Okay, let's see what we need to do. So the new view, by default, what we'd want to do is we want to say new view.in. Let's say we've got a function that's going to do that. But we know that if there's an existing view, we have to transition that out, right? So Let me guess, there's an out function. There is an out. Yeah, I'm assuming, I'm assuming, by the way, I'm going to put, let me see, there's going to be an in function here. There's going to be an out function as well. When this view has to leave, I'm going to do an update function in case you kind of go to, you're in slash about, and you go about something else. We're just going to tell the current view to like update itself. So we'll assume they all take some kind of data, which I think we can probably figure out from the regular expression. Right, so we get the roots and let's see. So we want to know if there's a current view. So okay, so let's do this. If this dot current view, why not let's do that. If there's a current view, and if the current view is the same as the new view, then we tell the current view to update. And I'll tell you what we need to do as well. Let's do to get the data data equals, let me see, it'll be root dot, yeah, be root dot exact against the path. That would then, that executes against the regular expression against the path name. So because I, in my, in my code here, I've got like capturing stuff so that in theory that can get passed through and then the view could decide what to do with that data when it's got it. So that's kind of, kind of handy. So we need to pass that in there. So if there's a current view, and if the current view matches the new one that we've tried to bring in, then the current view can just update. So we cannot, we could return there. So we can return that. Here we're going to do this dot current, current view dot out, which we're going to pass the data as well. And we need to wait for that to finish before that one comes in. So why do you need data and out? You never know. You never know. I actually get that because I, so let's, let's say for example you're going out from your current view, and let's say for example you're doing a fancy transition from one section to another. Let's say you got a fancy transition from about to to contact, and that's different from your standard one. And what you might do, the data is going to contain the new path. So you're going to be told, you're going to be telling the about view, who's incoming, which in this case would be contact. And it could go, oh, I've got a special case for that. I'll do my animation for that. That's exactly the problem that I have run into right now, that I want to have a special animation for an overlay. There you go. And it just looks stupid right now. So I might have to actually add that to my. There you go. You see, handy. All right. So we've got the this. So what I'm going to do is I'm going to say, so let's say out view promise. So I'm going to use some promises here. If you've not used promises, this might look a little bit strange. And hopefully you'll follow along. But if not, you know, there's plenty of stuff that we can read, you can read. And I'm sure if you ask the question, so I'm here will pop in some links. So we're going to say that we're going to assume that by default, there is no out animation. So we'll just resolve the promise immediately. However, if we had to do the out, we're going to update the out view promise to that, which means we'll have to code that into here. And so we'll say out view promise start then and then we can do that. And this really is the power of promises that you can just write chains of promises that will execute one after the other and it can be about transitions. It can be just loading data and you know all the steps beforehand will have continued when your code is being run. All right. So what I want to do is I want to do this thing where each view is just going to sort of kind of push back and fade out and the other one's going to pull in and fade in. I'm going to fade one out immediately like fully and then I'm going to bring in the next one. So it kind of gives us this push, push pull kind of feel for my transitions. It's just our transition. This could be anything. What I'm going to do is I'm going to do a transition on transform. People can ask in how they can be notified if we are going live. And it's, first of all, you should be subscribing to the YouTube channel because we send out notifications when we go live. That's true. And also, go to the Twitter and follow us. That's also true. It tends to be Thursdays at 2.30. Roughly speaking once a month. So I expect it from now. But you know what? We can always do more. If you like our twist at the summer, we'll let you know. That's the ones. We appreciate you asking because we're enjoying doing them. So there we go. All right. So what I'm going to do is I'm going to make these animations super slow to begin with just so that we can actually see what's happening and debug any issues if there are any. So 0.0, 0.3, 1, you know. We want to do the same for opacity. Opacity. Oh, don't take that, Paul. Take that bit there. So there we go. And we need to transform, transform, scale, 0.95. So it's a little bit pushback. And then we'll do transform none. There we are. Transforms and opacity. Super duper stuff. So in our view, what we're going to do is we'll do return. We're going to return a new promise. And that's going to resolve or reject. And we're going to say const on transition and is going to be that. I should really be, I haven't fired up this code in quite a while now. So it's, it is becoming the danger zone where it will most definitely not work. But you've written so much. You don't actually know what is the cost. Yeah. And I'm going to not believe it if it did work. So this class list, we're going to add a visible class because we know that that's going to, where is it? Where is it? Where is it? That's the visible class here that we added on. So we're going to have that added on. Okay. So we're going to do that. And we're going to ask for the transition and so this add event listener transition and on transition end. And we're going to do this dot remove event listener on that. And then we're going to resolve the promise at this point. So when the, so we're going to add the visible class and when the transitions ended, we're going to resolve the promise which would allow anything that was chained against that. And the same will be true for the out. Let's do that as well. So let's do that. And here we're going to just return promise dot resolve. One thing to keep in mind when you do these, these systems where you have promises a chain onto each other, if one of these promises fails, all the subsequent ones will not execute. So you will have to add handlers if you want the other subsequent chains to be executed anyways. So think about your error handling, which is always good advice actually. But in this case, it's even more important because suddenly you will just have a system that doesn't react anymore because it promises handle just dangling in the air, not being resolved or rejected. Okay. So let's see. So we've got in theory, we've got something when it comes in, it's going to return the promise, it's going to add the visible class, it's going to wait for the transition end. When that happens, it's going to remove that and resolve. Same for out, except that it removes that class. So we probably if we're being a little bit dry, we could remove some of this stuff here, but all the same, we've got it. And then just the update is not going to do anything immediately. I'll tell you what we'll do is we'll just console dot log data for now just so that we can see that there is some data. So let's see the view promise if the current view is the new view. Ah, the current view, we haven't done anything with the current view. So the first time through current view will be set to nothing. So let's see. So the new view, let's see, is going to be that. And we could say the current view is like there, we could just say the current view is the new view. Right? I think that will, sounds about right. It will work for probably this does. We have faded out the old one and so the new current view is there. So we're in slash misc. Now the nav has disappeared. Yeah, we don't want that. No, we don't want that. So let's see if we can just put a zindex of one on that and bring that back. Okay, so yay. So this has already started to work incidentally because we've gone to slash misc. As in we've deep linked to the slash misc, the root has picked it up. It's added the transition in on the misc view. All the other views. So if we look at the elements, you can see that misc is visible, a contact and about and home aren't. So let's go to contact. So that's going to fade that out and brings in the visible. It is literally working as intended. That is amazing. All right. That doesn't normally happen. Normally when I write code, it's normally a massive panic because we need we need a buck for this live stream. Yes, I'm going to something. I'll write some code. Don't worry. Somebody actually remarked they were like, I see you've had your custom really one bug for this episode. And it's like you're giving us way too much credit. Like I write code and there's bugs. I'm a developer. We write bugs. Don't we? We were kind of amazed or subtle. We hit like the one hour mark on the last two episodes and we're just waiting for it to go wrong horribly, horribly wrong. Very, very wrong. But it didn't. So anyway, so this is actually working as intended. But one of the things that I think we'll need to account for is this. If you go like, let's see, home about contact misc, right, we want misc to come in. But did you see in the background there? There was a weird mixture of colors. And actually, look, home about and contact and misc are all deciding that they're visible. And I think this is because of the fact that those promise chains are all kind of, we've got a few, every time you you call on change, we create that promise chain. And so it's a bit like a call order thing almost. It kind of goes there. The last one wins. But the other ones are still happening in the background. Yes. So that's that's something to fix in this situation, which is why, if you're going to do something like this, it's always useful to have your transitions run slow mimic that sort of fast click or just kind of click back and forth in the browser. The history controls. So you can kind of find that out. So we have a question. Yeah. In production, would you load each view at a later time? And I think that is something that we would actually implement in one of the. Yes. In router episode two, so to speak, if that is going to happen. Yes. If people want us to do that, if want us to come back and do like the more advanced router, I think definitely. So the fact that I've got one HTML that's always serving the same content for every deep link. I think is not what you'd want. I think you'd want each of these views here in my HTML. I think you'd want each one of those to be its own separate document. You do a fetch, treat it as a document. So what we'd probably do is we'd probably have a container element, something like that in the app that would be like, here's where that view needs to live when you've loaded it. And then when you click it, we probably do something like a race where we put up a spinner if it takes too long to fetch it in. And then, you know, get that document. Could actually write a custom element that is an SC remote view that instead of having actual contents inside just takes a content URL that it fetches and, you know, stuffs it in there and then it works. Yeah. And that, I think would be better. And certainly, as I say, what we're doing right now is we've kind of got all these elements primed and ready to go and that isn't going to scale very well. It's going to mean that you have potentially huge documents. But that kind of handling of attaching and detaching and so on can get quite convoluted. And this is the simplest possible version of a router that I know about. So that's why I wanted to do it in this so that we're not spending forever on your time as we go through it. So I'm going to try and fix this this issue with all of them being visible. And I think the easiest way to probably do it would be to add a kind of a block around around this here with the code around the promises. And I think the probably the way to think about this is that when there's an animation going on we want to store. So if I was to click, no, wrong browser. But if I was to click, you know, one, two, three, four, very quickly, when, which everyone's going out, I would want it to be the last one that clicked that kind of came back in. Yeah. Okay. So since that's the case and somebody clicked while it was coming in, it would still finish and then go back out. Right. Right. Right. Right. Yeah. Exactly. So, so let's see what we can do here. This is going to this is always a bit fiddly when I think this through. So let's say we want to do. So we're going to do um, so this one, we should allow them to do this and then we say it. So if, if it's not animating, if it's not animating, or if it is animating, let's do that. If it is animating return, so we don't let them to do anything like that. But by the default will be undefined. So we can now say that that's true. When the, when the current view that's gone out has gone. We could do. This animating is false. We can, we can reset that. So now we're going to allow interactions back in so that this code should run. I think that would that work? This is where, yeah, as I say, this is where it gets complicated. So what do I want to do? So we have this flag when we are basically in a transition right now. That is what animating is supposed to mean, right? Yes. And when we are in an animation, in the out animation, more so, we want to overwrite this view that is supposed to come in instead of Yeah. So this, so this, this sort of new view here would be no good to us. So we want to set where we've got new view. So let's get rid of that and make that so this not Yeah, it would be a class very little. Yeah. So we can store it for kind of future. So the current view matches the new view, blah, blah, blah. And then this, that new view, whatever that current value is. So let's see. So that is fine. We get, we get a promise for this, but this, oh, do we even want this? I don't know. Oh, we'll see how we get on here. Let's see what happens. So we'll do this. Did it break? It broke. Okay. We broke things. Here's our custom rebook. That is so relieving. New view is not defined. So where's new view? Yeah. No, right. And new view, new view, new view. Oh, yeah. This is current view equals this dot new view. That should do it. Yeah. Yeah. So this would only apply. Wait, wait, wait. Is that going to work? Yeah, that's fine. No, it's not going to work. It's not? No, because what we want to do is we say the new view and we want to, I think we want to do it here. No, no, no, no. We want to fade out the current view afterwards and once we arrive, I think you might want to do that in the promise, right? Oh, that's fine. Let's find out. Let's fail. So that, yeah, it is doing the right thing. Oh, no, it's not. So it's kind of closer, right? Because so what's happening here is you come into MISC and say you're going to about like that and then you click home. It'll bring in home. But when I click on contact, that should allow it to disappear at that particular point. This is always fun code, isn't it? Right. So let's do this step by step then. Right. Figure out the new view. So that's fine. And then let's see. So I have to write. Sometimes I write out my code in English so that I actually can understand because I just sometimes look at clothes. You don't have to juggle it on your head anymore. You can actually remind yourself. So if there is a current view, so if there's a current view, if it's one we already have, just update it. So that's fine. Otherwise, we animate it out. Right. Yeah. I think we're pretty confident of that particular branch of the thing. Yeah. And now this is the bit where we actually we want to, so we could we can call out potentially a lot of times here, which I don't like. That feels, oh no, it feels okay. Feels okay, but not great. Should you be setting animating there because once you actually start calling out, it will actually be faded out? Yeah. So that's what I was wondering is whether we need to, we shouldn't be blocking where we are. So we'll find out. But let's see. I'm going to move it up here for now because if there's a current view, but we're animating, we don't care. Yeah. Right. So. And then set it. Yeah. So we'll do that here. Oh, come on, Paul. There we go. So we're going to see that. So that's fine. But the only thing is now, the, oh no, the new view. That should work. Should we find out? So that goes to contact. Just contact. And then home. Yeah. Contact. See, we're still not allowing that to happen. Does that work? No. So now it's kind of locked itself out, which is never fun. Because the- Because this presumably never- This never unset. Yeah. So that's probably the problem. Let's just find out. Also, by the way, a nice thing about custom elements is that you can just inspect the state by selecting the DOM node in the inspector and look into the internals. Those are not fully- Free-floating objects anymore. Nice. Yeah. So we never get to that point. And I assume it's because of this. Which is not fun at all. Right. I'm getting myself into a bit of a pick all over this one. So take a breather. Do anybody else do this? Do you have a stop, go for a cup of tea? Well, you might not go for a cup of tea. That's probably a very British thing to do, isn't it? Let's be honest. We're all looking to go cup of tea. Yeah, I know, right? Helps to think things through. Exactly. Right. All right. So the new view. Figure out the new view. Anybody on the live stream, if they can see the bug, they'd be very welcome to say what they see. I'll let you know. Thanks. Appreciate it. Right. So I'm changed. Here we go. If you're animating, your turn. What I'm curious about is, I might actually just delete the code and write it again. No longer animating. So there you go. That's doing the correct thing, right? Well, I guess, although the message comes a little bit early because it says I'm no longer animating out. I'm not animating out. I'm not animating out. I'm not animating out. I'm not animating out. I'm not animating out. Okay. Okay. So I put a terrible debugging. I'm wondering what the semantic of that variable is supposed to be, but I guess it is about, I'm no longer animating out. It's a sort of, it's kind of like, actually, you're right. It's more like should block should not make more promises is what it really is. Quality code. Hey, there you go. Which if that's true, there you go. Should be there. Maybe it shouldn't make any more out promises. There you go. Well, you know, as I say, it's just to try and get the kind of the meaning. But the question is then, with that in place, so that goes to home. It calls out, but it's calling out. That feels like the root. I'm wondering if that is actually still true. That should not make. I think I know why. Oh, do you? I think so. I think it's that. I think it's deciding to call it out against the thing that's animating in. That could very well be true. Yeah, that is. So I think let's try that. It looks so much better. We have had our customry one bug per episode. Yes. It happens every single time. This is so not what we intended. I know this time. I was like, it's fine. It's fine. So I won't do the customry one bug. Okay. Anyway, right. Well, since that singularly failed, yeah. Here's what we'll now do. So this is. And yes, we're going to keep that variable. Yeah. Should not make more out promises. Well, okay. We know Java. It's really long, isn't it? It's called Java script for a reason. No. You just watch one, in which case you'll be like, oh, I'm going to minify this. I'll just call it this. Don't, please don't. No. So if, so, is transitioning between views, at least you should be able to read this, right? So, okay. So we don't want to create more. People are asking you to reiterate what the actual bug was. Okay. So the actual bug was that, let me move it back out here. I was doing this here. So what I was assuming was that if there's a current view, you want to, and it matches the new one, we want to update its contents. We just want to pass through. So you're on the about section and we do, we go to about slash something else. Yeah. Okay. What we wanted to do there is just update it. Okay. That's fine. That's, that's a relatively straightforward. If you're going from, say, about to contact, we want to call the out on that. But what we want to do is we want to hold on to the current view. Because if somebody then clicks again, we still want to tell the about view or whichever view that was the current view. We still want to tell that go out. You're supposed to transition out, out, out, out, out. What I was doing is I was updating that variable to be whichever one was expected to come in. But we don't want to do that just yet because otherwise we'll tell the new ones about to come in, you should go out. So we're like, we're updating the reference to the active view. Which we don't want. Yeah, we're doing it too, I was doing it too early. See, I was doing it straight away. What we want to do is we only want to point our, you know, what is the current view when the current one that's going out has disappeared. And the new one is actually coming in. Yeah, the new one's about to come in. So we could have done it here or we could have done it here. I mean, to be honest, we could just, you know. So the lesson you learn from this is when you use promise chains and, you know, to bridge over certain time gaps, think about what the state is that you're in. Yeah, and since this is a promise, we can return it here and that would then allow us to then dot then if we wanted to and be like console.log. Done. Done. Done. Right. Let me just check that's still working after me messing around. So then that one goes out. New one comes in and at the end of it, done, done. So, you know, that's a kind of useful thing about having the promise chains here. So that is working as intended, which is really, really good. So we can now speed things up a little bit like not point three. So remark from my side, actually, I have, I returned the promise in my go function on the router so that I can, external code can latch onto the promise chain and start working after everything has been done by the router. So yeah, we could totally do that. I mean, I think in this case, we would return that from there and then we would return that from there. Exactly. So we return whatever on chain, unchanged would return, which will be the out view promise. However, in this case, we'd also have to do something like that here. An empty. Like promise.resolve. Yeah. So that we're just saying you're always going to get a promise back, but it might just immediately resolve or it will resolve when the new view has come in. It resolves when the view that you're requesting is on screen, which might be immediately or later. Let me show you something else that is brand new and this actually does relate to views and the like. Since we are, we have about what, five minutes? If we want to keep this on the usual customary hour, we're doing an hour, whether we like it or not. The script says we do the brand new thing. And then this is not fair because we're actually not trying to do this. But anyway. Okay. What I want to do, here's what, here's something that often bites people. You've got these four views, right? And notionally, they're separate, right? There's in, you want to lock things like layout and styles and so on to be completely separate. But things like layout, I mean, I talk about this quite often when I'm doing performance stuff. Like layout is normally scoped to the whole document, right? So if you trigger that. Sadly. Yeah. And so people kind of go, ah, this is bad. Let's see about this. Let me show you this. So let's say, I'm in the home section. Um, what I'm going to do is I'm going to add myself a box, which is okay. It's just a box, right? So that's fine. And I'm going to do, I'll do view home. This is where I find out that I, I can't remember how to do this, but here we go. Um, so let's say, with 50 pixels, height 50 pixels, background, what colors the home? I think it's, let's just do white. And then we'll say, position, absolute. Oh, absolute. Right. And what we'll do is we'll do keyframes, slide. Okay. And we'll say from and then to. Now what I'm going to do is I'm going to trigger, um, layout. Okay. So what I'm going to do is I'm going to do an animation of something like width. And I'm going to go from 100. No, like 300. Don't do it at home, kids. Don't do this at home. Definitely don't do this one at home. I'm just showing you to, in case, for some reason, you are actually triggering there, which is there are valid times like you append child or remove child, you're going to pick a layout, for example. So let me show you this. Width from 300 to 100. And so I guess I'll do animation, animation name. We'll be slide in, not slide, slide, animation duration, three seconds, and then animation iteration count, infinite. So like, like say we've got that, how to drain your battery? Well, yeah. So if I refresh that, so you see I've got this animation, right? And let me just put a left on it. So it's like 100 pixels. Okay. Come on. Right. So we've got this. And if we do a timeline recording, and this will be fast because it's a decent MacBook. Yeah. So it's different. Do this on a phone. Things will look different. Yeah. So, but what you can see is during this animation, if I zoom in on any one of the frames, and admittedly, as I say, this is comfortably 60 frames a second, right? There's no... It's a bb. There's no DOM through it that needs to be re-layouted. Yeah. This is a small DOM. There's no issue here. But if you did have an issue, I'm just showing it for the sake of showing it really because I think it's really interesting. See the layout root here is the document. And the number of nodes that need layout is three. So you've got the box, you've got its parent, which will be the sc view, and then the body above it. So that's why, yeah. So that's why you've got those three, I think. And so you can see that effectively it's document scope. So if you think about it, you would have a navigation drawer that we wrote last time outside. That would get re-layouted even though nothing changed. Yeah. And so this is a brand new property that's coming in. Because on my view, I've got something like position fixed and I've actually set... Tell you what, I'm going to switch that across to width and height because I think it might need it width 100%, height 100%. You'll have to check the details. But if I put contain strict, now if you've not come across the contain property, basically it would let you say layout, styles, paint, or strict, and there's also content. And that will... What it'll do is it'll lock off some of the calculations. I put strict on, which is like the keyword for all of them. So styles, paint, layout, and content as well. In any case, what we should see now or being well, if I do this, stop recording, stop it, stop. Da, da, da. We zoom in. We're still going to have layout, but you can see now the layout route has actually been fixed to that particular view, which means we're no longer potentially affecting all these other views that have nothing to do with this particular one. We're saying, essentially, this is a layout boundary. It's the root of this calculation. So you can find this in the current Canary. I don't know what the support status is generally outside of Chrome. But it's something that's incoming. And I wanted to show it because, as I say, I mean, in this case, the layout time is so minuscule. It doesn't matter. But on a big app, we've got a lot of views going back and forth and you potentially trigger layout, which historically might have been really expensive to deal with. With contain strict, you're going to be a lot, a lot better off. So with that said, I mean, I've got a ridiculous animation, which I'm just going to, I'm just going to remove it after this. But what we're going to do, all right, what we're going to do, we are going to call this a day because we've hit pretty much the hour mark. We had our customary bug. Don't forget to subscribe to the channel. He can't believe I've done that. I can't believe it either. Thank you so much for joining us. Thank you for your questions. I hope you've enjoyed it. Don't forget, you can find us on Twitter. You can let us know what you want us to cover next. We can cover a more advanced route the next time, or we could do an expanding collapse view or something like that. You let us know what you want us to do. And we will try and get it done. And thank you so much for tuning in and we'll catch you next time. See you then.