Live coding a lazy loaded comment system with Firebase | Firebase Semi-Live Ep.1
Firebase. RC. So its dot firebase, RC you, can see that vs code gives this nice little icon with it so that's like a really good way of knowing that you typed it in right and then. There's also firebase. JSON. Which, we also get the, nice little icon for. So. With firebase RC, this is how you configure which projects, you're going to deploy to so, in this case I can write projects. And then. I start, with a default, project so you should always have a default, Park to deploy to and in, this case I think I call it fire. Semi. Live or. Maybe it's fire. Semi, live I, can't, really remember me. Check the console, which ways the console. I. Called. It fire semi, lives so I'm gonna copy that I. Did. Get it right nice but, the cool thing about this is this is just one type of project you can have you could have multiple you could have a staging. Alias, and you, could have a production. Alias. Or, you know just own whatever you can keep going on this and then in the. Command, line to switch you, would just say firebase, use. And. Staging. Or whatever the name of this key is and then that way you can deploy out to that after you, use that so, it's a nice little way, to manage multiple environments, but. In this case I just have my default. Project and this, is used, by default, so I don't have to say firebase use default in this case. So. The second is for are based on Jason and firebase. That JSON actually manages more than just, hosting, firebase JSON, can manage deploying your database rules your storage rules, it, can manage, your fire, store rules it does a lot of really cool things and. So we're gonna use it for primarily. Right now is with hosting, so we'll give it a hosting, key cuz it's the product we're using and then. The main thing you have to tell it is what. Folder. Do. You want to deploy your files from and we refer to this as the public. Folder so. You say the public folder is and, in this case I'm actually using.
URL. Of the page something, that I know I can key off of, so. This document, would be article. Data so maybe it would have like the article title, the. Author or, whatever pertinent, information this is something that we're not really gonna be doing right now in this specific, video but, what we care about are, the comments, so. Firestore. Has this concept of sub collections and that's a collection. At, the same path of a document, it doesn't, particularly. Belong. To the document so if you read the document, you're not going to pull back all these sub collection data but, they share the same path which makes it really easy to, organize. You, know it, makes, it easy to organize your data structure, so. Way. The way we're going to read comments is through articles. The, article. Key or ID and, then, the comments sub collection. So. I'm going to do that now let's say this dot comments, ref is this stuff firebase app dot. Firestore. Dot. Collection. Of articles. And, let, me put this on a separate line so it easier, to read so dot collection, of articles. Of. Actually. Instead of saying that collection of articles I guess, again you can do it two ways you. Could say doc collection, of articles dot doc of article, 1. Dot. Collection. Where's. That, BS. Code doesn't want to find the right type here, sometimes. If I just can't it keep hitting dot. It. Will listen to me dot I want you, there. It is dot. Collection. Of. Comments. So. I could do it this way and just keep chaining, or, I. Could. Do it like this, dot. Collection. Of, articles. Article. One. Comments. So. Whatever way you prefer I prefer to kind of doing the chaining, because it just. Feels like it's easier to maintain than just one string but you know whatever is your preferred method is totally fine. You have these comments, and what, we want to do if you look at the page is that we're gonna add an event listener, to this button and when, we click we're just going to read back all the comments and so, right now there aren't any comments in the database so we will, seed them after we write this code. So. What we need to do is we need to get more Dom elements, and in this case if we go to the HTML, we can see that the button, ID for. Load. Comments, is called. Load comments, it's. Pretty easy to remember so we'll, create our button, property, which is an HTML. Button. Element, and, we'll. Say this dot. Load. Comments. Is document. Query. Selector. Of. Hashtag load, comments. As. HTML. Button element, and if, there's any like super advanced typescript, user out there watching this telling. Me hey you don't have to do this as thing. Let. Me know because I would like not to do that. It's a big pain of mine, alright. So. Now that we have this button we're, going to do. What, calm if they call this dot add. Listeners. This. Is a good place to add. Listeners. So. I'll create a method add listeners. So. That's now happy, and, what. We'll do is we'll say this dot. Load. Comments. That add event. Listener, click. I'll. Name it the full thing event. So. Whenever someone clicks we're. Going to want to tap. Into this reference and we're gonna want to stream back comments, but, we're also going, to want to take this button, and make it go away because if they've clicked on it it's gonna load you know the button doesn't need to appear anymore but we will only do that after, the data has, appeared. Actually. Now that I think about it you, should probably take it away immediately because, if you click on it and. Nothing. Has happened yet, because it's downloading, over the network, you might just keep clicking on it because you're like why isn't anything happening and, if you're on a slow can section and you got a really, click happy user that, could be bad so let's remove the element immediately. And. So. To do that I'll say this dot load comments, class, list. Dot. Add and, then I have one called hidden, which sets its displayed, to none. All. Right let's. Run that real quick oh yes. Of course that's gonna break at times. And. So, it's refresh, if, I click load comments, doesn't. Like it. Must. Provide project, ID that's. Interesting. I thought I am, providing, project, ID no, I'm not actually passing any of that information I said I would pass all right let's.
Document, Changes but that means. It's not the actual sorted. Information. That, or your state of your collection, it's what happened, so if, something was deleted, you would get an omission of a doc change saying okay this was deleted, and then you could use that toast. A little pop up that was like this got deleted or do an animation based on that so these are actual events. That happen, in your app and then. We have Doc's Doc's. Is the actual, state of your application so, in this case for my comets and is the actual list, of comments, so if something is deleted, that. Doc's will have that removed, where's doc changes, will be that actual, document. That was removed, and, then. There's testing, for empty there's a for each method to, loop through things is equal, we, can check out some metadata which is useful if you're doing offline. Changes. The. Query is the underlying, reference and, then the size so, how many documents. Are in the snapshot so. Doc's comes back as an array so one thing that I can do is I can actually map over, it so, in this case I can turn. It and then doc, has, a couple, of properties itself, it has data, which will return you the JSON representation, over the JSON object, that is not, the string form you. Can check to see if it exists, which is nice helpful method. There's get which is a promise, of getting, the data because it's also, shares. The same as the reference we, can see the ID we, can check, to see if something is equal we can see metadata and then also get the underlying reference which is helpful if you want to do any mutation. Operations, like set update, delete, so. In this case I just want to map the, data over, and actually. One thing the, data will do does will just return you the data but as you can see the ID is. On the document, not the data itself so. Right here this is sort of a you, know whatever you want to do kind of thing you can either store. The ID in, the document, itself, so that way you don't have to worry about getting, it from the. SDK, but, through this mapping method or you. Can just do it like this where you say okay let's return the ID. It says dr. Eide and, then. Mix. That in with the actual object. So. In this case this will be all of our comments. Let's. Bring that out to a separate line so. Now our comets is going to be an array, and it's. Gonna have an ID and, then, other properties, that come down from the server and from. Here I can call this dot render. With. My comments. So. This isn't gonna do anything iswhat a console, dot log my. Comments. Make. Sure that rebuilds. Do. A refresh. So. You. Didn't get anything and, that's probably because we did not yes. We did call that listener so let's do some debugging see. What I missed. All. Right so, I don't want this, file I want. This, this is my type, script file which is using a source map so it looks the same in the browser than it does in my editor and what. I want to do is I want to add a breakpoint at add listeners, and, then inside, and just kind of refresh and see what happens, so. Calls add listeners, and. Oh, cuz I have to click the button now that that is why it's the whole point of this so, I click the button and. The. Button goes away so that's good and, then. We're going to call on snapshot. And. I'm gonna wait and then. We. Get this message, that says could, not reach cloud firestore, back-end connection, fail two times most recent, error is this this and that and that's, because I just recently created this project right before I started like I mean like right. Before I started so, what I didn't do was, I didn't go into the console. And enabled, my fire store because, that way you only, want to create these resources, if you need them so I'm gonna go quickly go in and create that alright. So I'm in my console, and as you can see I have everything, up and running now and just, as a note I started in test, mode. And. So that means everyone, has read and write access to my rules which is bad which, is very bad, not so bad while you're developing but, it's nothing, that you should ever go to product so if you're gonna deploy this database out to production, you need to write rules and we're not going to cover that in this video but I plan on covering it and the very next one so it's gonna have its whole video. Dedicated, to doing this but, for now we're just gonna get things up and running, so.
I Want to add a collection we're. Going to have articles. And. We're. Going to have article. Underscore. One and, then. Field, we'll just call it name some. Article. And then, I will save. So. Now I want to add a sub, collection so in this case this article one is going to have comments and then. We'll have an auto ID. Here. And we'll, say the text is first. Because. That's what every comment ever. Is alright, so save. And. Then. Look at that all this stuff just went crazy, we, get in, the good way we, got our sub. Collection with our data and firestore responded, immediately and. We, can see if we finish mapping. Right. Here and just get rid of these break points. If. You go down get, rid of this error message you can, see that we got an empty omission at first then we got that when we actually enabled. Our API and then, we got this other one was when we added our data so, now that we have these comments, let's sexually try to render them. So. To render them I want to create a div. With the class of comments and then it just that's a P tag that's gonna be something simple for now and, probably. The next video and we do security I'm, going to do authentication as. Well and so we'll be able to kind of display a user avatar, or something like that but for now let's just get it so it's displaying text. So. To do that I want to, be. Able to create, a method called like create, comment, or something like that or actually even better what. If we just create a class college, comment, so, comments. Is the. Actual, comment list so it could probably call it comment, list, instead, of comments, that actually sounds way better so, I'll rename that symbol, comment, list. And. That didn't work out super, well as a comment. List. New. Comment. List okay and then, we'll have a single, comment, and, so. For, this we'll say the constructor. Of comment, and, we. Can pass in some data or something but. Really all I want to do I think about it just, do, one where it's like create, or something like that actually, you know it will. Just make it a function we'll, get to that later I was trying to build into some, custom elements which you'll see in a future video so. We'll, create a comment, so create create. Comment. And. This. Will take in a comment, which right now we'll just type to any. So. I'll create the parent, div so, that's, document. Dot create. Element. Div. Take. The div and. Class. List, dot, add and, we. Will add the class of comment, and, then. We will create ap tag so document, dot, create element. Of P, tag and. Actually it really bothers me not to have my, variable. Initialization, initialization. Statements, next to each other and then. We'll say P dot. Text. Content. Equals. Comment, dot, text, and then. Lastly, we'll take the div and append, the P, and. Return. All. Right so. Now what, we want to do here, I'll, say creative. Create. The actual, elements, so, we'll create Const. Fragment. Is. Document. Dot create. Document. Fragment, so. If you're not familiar with document. Fragments, they're a really good, and efficient, way of updating, the Dom and they, are a detached. Fragment. Of elements. Where you can append children. To modify, them and once you're ready to insert it into the Dom somewhere, you, can just append, the fragment, so it's a really nice way of a, nice performant, way of doing, Dominus, versions, so. What I can do is I can loop. Through my comments, and say comment dot for each, comments. And. Inside. Of here I can, create a comment, there, comet, elements. So it's a cost element, is this dot create comment. I'll. Pass in the comments and then. I can call the fragment, say fragment, dot, append. Child. Comments. And. Then. The last step of render, is I want to go to this comment. Placeholder. Which is sort of the container, for all the comments and I. Want to create a property, for it so I can append to it. So. The comment placeholder, is. HTML. Div, element. That's. Right it's a div it's a div and then, right here, and. Say this dots, comment. Placeholder. Is document, query. Selector. Hash. Tag, comment. Placeholder. As, HTML. Div element. All. Right so. Now that we have that, we can append, to it so. We have created our fragment, like, this dot comment, placeholder, dot append child of.
Module, Stop in firebase, deploy. All. Right so refresh, and. We. Can see right here that, this is a little, smaller and the, fact that it's ninety four kilobytes, so that's all of this web pack code that's all the firestore. Code and all of our app code, and right. Now we don't see any problems, but this is a pretty good connection so, let's see, where this can be an issue, so. I'm going to go to a site called webpagetest.org. So. Here I'm at webpagetest.org. And, one. Of the things you can do here is you can enter in a URL, and then set how you want, to test it with all these crazy options, but, you can kind of feel overwhelming, so there's actually a, page. On the site you can use code easy mode so all you do is paste, in the URL that you want to use and then you, just, start the test, now. This can take a little bit depends on how many people are using this service how, long it takes to run the site in this case I'm hoping, that it doesn't take too long so, while, this is working, alright I'm gonna fill the time because otherwise it could be sitting here for a minute or two. So. What I want to do is is I'm, trying. To showcase that when. We're doing these two imports, here at the top these, have to run, before all this other code does and what I'm really trying to show here is that this animation, isn't, going, to happen until this. Code is, executed. And if you think about it that doesn't really make sense like, I should be able to run my animation, before my, comets, are loaded because my comments, don't have to be loaded until I click that load comments, button so. What I want to do is is I just don't. Want these imports, at the top level I want, to do them dynamically. And so, the way that webpack. Lets you do that is through this dynamic. Import. Function, where you can say import, firebase. Slash app and then. It returns it as a promise, and so, inside, of that promise we have access to the firebase module, but, what's great is is that it's not in our critical path and, webpack. Actually goes out and splits. That into a separate, file and that file. Is only loaded when, we click that button. So. Let's go down here to the, add. Listeners. And. What we want to do is one that's clicked we. Want to import. Firebase. Slash, app and. Then. We. Could do, this through. An async. Await, so. I'll say constant. App is, firebase. Import, firebase app, I'm. Sorry firebase. And. Then. We. Could await, fire store as well awaits. Port. Firebase. Slash fire store. And. This is giving me an error because there's. Some issues, with it right, now and. The package is a little bug that we, need to fix so I'm, going to hack into my new modules, to fix this really quick and. It's, not a good solution but. It will work and this. Is something that will probably have fixed by the time this, project. Goes out so. If I go into. The. New modules, follow, my alphabet, ABCD. Firebase. And, then. Go, into fire, store and kind of package JSON. I'm. Gonna do here is I'm going to add a, typing. Folder. And I'm. Going to say it's dot, slash. Index. Dot. DTS. I think. That will do it. And. Then I'll restart, the TS server and. Then. Here in a second it should stop complaining, awesome. Ok so you, shouldn't have to do that but. This, is basically, what I did was is that we have some miss configuration, and the or, we don't have it perfectly, set up for, these dynamic, import types and so I'm basically tricking. Typescript, but it's not really of any consequence, because we're not importing, any types from this all. The types come from the top-level, firebase, so. It's just something that we need to tweak. So. Now that we have a firebase loaded, we can actually see something pretty interesting here if. We do a. Is. It yarn. Watch to start rebuilding our, web, pack. Web. Pack is watching the files you, know I got, a save I think to trigger it there. We go and we. Can see that now we have. Zero. Dot bundle a bundle, a two bundle a three bundle and those, are actually the asynchronous, chunks. So all of our codes not just in one bundle we, only we. Only will get those pieces of code when we click that button. So. Me. So. To prove this it's, reaiiy, got, to run the server. Let's. Do that real, quick. In. Firebase. Serve. Let's. Refresh, and, we're, getting an air about firebase, not being defined, let's see why that is.
Well. Formats, it's hard to oh yes, because we haven't reflected our code all the way yet so, that's kind of why we're we, still have some typescript, errors we still have some we, have some issues but we'll, fix that here in a second let's take a look at the page load so, you can see here that our first view comes in four seconds, and this is on a slow 3G, connection and. The load time is 6.5, seconds, so, that and, then this first you is at 6.5, seconds, in 6.2, so there's some variations, because it's a mobile network so, let's do this middle, one so, we don't know the filmstrip view and, I can see that at 4 seconds. The, page was, first loaded, and. What. I want to do actually is I want to check out fully loaded and I, want to create a video of this which is also going to take a second, and, what I want to show is is that that, animation. Just, sat there and it couldn't actually happen, until firebase, loaded. And. So. When we split it out that animation, will be able to load so, four, seconds. And there it is see look right here. The, animation, didn't run it just set there set there set there set there and then it, ran around six point three, six. Point two seconds, and, if we look. Back that, should be yep, like, I thought that's exactly. When our bundle, kind of ran and then executed. So all of our Java scripts, had to be downloaded, for animations, to run which is you know which, shouldn't be the case so that's what we're fixing. Now. So. Let's go back here, and. Let's. Figure out what's going. On so if this firebase, and so all this. Nice. Type scripts not working, right now but. Basically all this code isn't going to work and that's because. We. Have as. Because we're loading it asynchronously, now so. What, I'm going to do is I'm just going to copy, it right here, and. We're. Going to paste it right in, here. And. So the config, now we need to create us a script. A private. Property. And. They. Want it to be in the, constructor, so we're going to get, rid of that because it no longer will be a property, since being asynchronously, loaded but there's some cool stuff we, can do with observables, for that. So. We'll turn these into variables, for now. All. Right, look, look look look everything, looks, fine now so let's refresh, it let's. Check out our build. There. It is all right so now let's go back to, this refresh. Actually. I want to go back to using the development, build so I can read the code and have, source Maps. So. Refresh, I need to wait till rebuilds. So. That's just, safe, so it does its thing. Gonna. Build. Why. Aren't you building, so. The clip X is betraying, me. Just, gonna run the watch command, again. All, right it's, not refresh. We. Have our source maps back and. What. We can see right here if we go into the network is. That. We just have this bundle jeaious but it's even, with source maps this bundle is. 27. Kilobytes, which if we got rid of source maps if you identified it and compressed it it would probably only be a couple of bytes, which. Is really great and if we refresh, we can see it's the same and, now, when I click this load comments.