Server-side Rendering React from Scratch! (Server-side Rendering with JavaScript Frameworks)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
DAVID EAST: Rolling. Hey, everybody. Oh, I kicked the thing. Sorry. [MUSIC PLAYING] Hey, everyone. Welcome to the React episode in the server side rendering with JavaScript framework series. React is a really great fit for server side rendering because it was designed with the virtual DOM. And the virtual DOM is like the DOM in your browser, except it's not in your browser because it's virtual. And it means it can go anywhere, like on the server. So you can take your same React app and create a virtual version of it, and then render that out to a string, which is just HTML. Send that down to the browser. The browser will render that pretty quickly, as we've learned. And then it will create a virtual version on the client. Now, what's really cool is if this virtual version on the client matches up with the HTML we sent down from the server, React will know not to re-render it. And this means that we will have a much faster time to interactive. So let's get started and dive right down into the laptop. So I have my code editor opened up. And I just have my VS code, preferences to make the screen really big in this case. I have my source folder, which I will use to create all of my React code. And I have my packages.JSON, which is full of the dependencies I need for this app. I have Isomorphic Fetch which will allow us to request data, not only in the browser, but also on the server. And then I also have React, which is the Core React library and React DOM, which is the rendering layer. And below, I have all these dev dependencies. And I'm going to be using Babel because I can use new ES 2015 features. And also I can write JSX for my virtual DOM. So we'll be setting up Babel here in a little bit. I also have Express for my server. I have some Firebase tools to host my server and Webpack to bundle my clients. So we'll set Webpack in just a little bit. But for now, let's actually go and build our React app. So in source, I'm going to create a file called index.js. And then from here, I'm going to import React from React. And then I'm going to import from React-DOM. And I'm going to import this render method. So render takes in a top level app component. So I will name mine app, but you can really name it whatever you want. And the second parameter render takes in is the place to attach this component to. So we're going to use a querySelector and attach it to a root element. So now I need to go and actually create this app. So I'll create a new file, and I'll call it app.js. So just like before, I need to import React from React. And then now I'm going to create a function and call it app. And going to pass this parameter of props into this function. So this function is known as a stateless functional component. And React has multiple ways of creating components. And this is a really simple way because you don't have to use a class, which is concerned with life cycles and all this other stuff. It's just the function. It takes in some properties. And it returns the JSX. So essentially, if you've created a class component that uses the render method, this is just the render method. So right here, I'm going to return something like a UL. And inside of this UL, I'll have a list of facts. So to get these list items, I'm going to iterate through my props. And my props are going to expect an array of facts to be passed to it. So I can map over these facts. And I can create a list item from them. And so just interpolate facts.text. And then now that I have my fact, I want to also get the index and set that as the key. Now, this isn't really important, because it's not going to be helpful to have the index as the key because it's not really unique. And if things get rearranged, it sort of loses its meaning. But it will keep React from throwing an error in the console, which is kind of unsightly. So we're is going to get rid of that for now. So now that I have these list items, I can take my facts down here inside the UL and just past them in the middle. And so the last thing, I just need to export this as my default export. And then now I'll go and import it in my index. So now I've created this component, but I actually haven't retrieved any data. So to do that, I'm going to create another file called facts.js. And this is where I'm going to use Fetch from Isomorphic Fetch. And then I'm going to export a default function called get facts. And what get facts will do is we'll call fetch. We will pass in a HTTPS end point, which is SSR.React.Firebaseio.com/JSON. And then this returns a promise of a response. And from this response, I can call response.JSON to get back the actual JSON data, which is what we'll need to render out our facts. So now, I'm going to import get facts. And from here, I'll call get facts and resolve the facts from the promise. And I can just copy this, paste it inside, and then I'm going to pass facts as a prop, which is effectively calling this function with the facts as the parameter. And you can see right here that the function app takes an object of props, which we passed facts into. We'll iterate. And we'll create an unordered list. So now that I have this app written, I need to take this code right here and transform it into something that the browser can currently understand. So to do this, I'm going to use a combination of Babel to take these ES 2015 syntax and this ES 2015 imports, convert them to either a common JS require for the server or for a Window export for the browser. And then I'll use Webpack to take all these files that we're referencing with these import statements and bundle them into one file for the browser. So I'll set up Webpack. And I'm going to create a file called Webpack.config.js. So Webpack is ran on Node. And so we'll have to say module.exports to export out a configuration. So there's multiple parts of Webpack. But the three we're going to focus on today are the entry, the module, and the output. So the entry is the entry file. This is the first file to look at for Webpack to know how to bundle up all of the files together. In our case, this is going to be our index.js. Now, the module section is what Webpack is going to do in the middle of this process. And in our case, we want to transform the ES 2015 code and all the JSX to browser code that the browsers of today can understand. And this last part is information about the output. So where do we want the final product to be saved to? So for entry, we just need to provide a string and say our entry file is source/index.js. And then with module, we need to specify an array of loaders. And so effectively, what we're saying here is when you load this file, transform it in some way. In our case, we want to say find all the JavaScript files and use the Babel loader. And the Babel loader will contain the configuration that we need to change the import statements to something the browser can understand. And then compile the JSX to regular JavaScript. And then we want to make sure to exclude no modules because it has all sorts of crazy stuff in it. And now, we're going to paste this below. But instead of testing for JavaScript, we're also going to test for JSX just in case you create any files that use the JSX extension. Now, lastly, we're going to do the output. We're going to specify that the file name is called the bundle JS. And the path is the current directory plus public. And so this will be deployed out to Firebase Hosting as a static file. So now that I'm my config setup, I actually want to be able to run it. But to do that I need to make sure that my dependencies are installed. So real quick, I'm going to do an NPMI. And now that all this is done, I'm actually going to peek into my Node modules. And I'm going to open up this dot bin folder. So this dot bin folder is really cool because it contains all of these binaries that we can run from the command line. And usually you would have to install these as a global module. And if you're doing any collaboration in the open source community or just in general, it can be kind of frustrating to know what global modules you need installed to run this project. So instead, we can actually use these local binaries to run these commands. So we have Babel. We have Webpack. We have the Firebase CLI. Everything we need is in this nice little folder. So what I'll do is I'll create a script section of my package.JSON. And I'll make one to run Webpack. So I'll go into the dot bin folder. And then right there, I can just call Webpack as if it was a global module. So I'll write NPM run Webpack. And we have an error. And this unexpected token comes from the JSX. So what we need to do is we need to create a Babel RC file, which tells Babel that it needs to transform this JSX. So now, in my files, I'm at the root level. I'm going to create a Babel RC. And this is going to come with two presets-- ES 2015 for our ES 2015 syntax. And then React for our JSX. So now that this is done, we'll run Webpack again. And just like that, we don't have any problems. So if we go into our public folder, we see if our bundle.js created. It contains React, React DOM, and even our code. So if I search for get facts, we can see that that's transformed. And it's just the transformed version of our get facts code that we wrote in index.js. So now that we have our JavaScript written, we need to deliver an HTML document. So I'll create a new file called index.HTML. and I'm going to paste in a little boilerplate HTML document. You can see that we have our title, our style sheets, and our bundle. And we also have this div where the ID is root. And that's where we're going to attach our React app to. And here in the middle, we have this little comment of app. And this will come in really handy soon when we try to do server side rendering. So now, I'm going to create my CSS just so we have things organized a little. So at this point, I have my app built. I have my configuration done. So all I need to do now is set up Firebase. And to do that, I'll open up the command line. And I'll use the local binary for Firebase. And say Firebase init hosting. So I'm going to select the project called non-SSR React because we haven't server-side rendered yet. And now that our initialization is complete, we can actually serve this app locally. Si I'll use the local binary again and say Firebase serve. So right here, we have our true facts app. And if I inspect the page source, you can see it's just the boilerplate HTML. So our app is working, but it's not server side rendered. So to server-side render, we need to create our server. So in the root of my project, I'm going to create an index.js file. From here, I'm going to import from Cloud Functions. And then I'll also import from React. And then, like before, I'm going to import from React DOM, but I'm going to import from React DOM/server because this will give me the method render to string. So using render to string, I can pass in my top level app. And it will create a static HTML version of my app. So now, I just need to import how we're going to get our data with get facts. And then, lastly, I'm going to import from Express. Now I'll create an Express app and create my [? SCLOB** ?] handler so I can intercept each request. So whenever a user sends us a request, we want to go out, fetch the facts, and then create a server side rendered version of our app. So I'll call get facts. Resolve the promise. And then using that, I can call render to string pass through my app, and then pass through the facts. So render to string returns a string. So I'm going to store that as a variable called HTML. So now that I have my HTML, I want to set a caching layer. So I'm going to use Firebase Hosting's CDN caching power. And so to do this, I'm going to set the cache control header. I'll say that the browser cache time is 600, but the CDM level is 1,200. So this means that when the user makes a request for the server side rendered app, it will first generate it. But then it will store it in the CDN edge for 1,200 seconds, or 10 minutes. And in that timeframe, everyone who makes a request for that app in the area will be read from the CDN and not from the server, which results in much faster load times. And it's great for the server because it doesn't have to keep generating the same thing over and over again. So now that I have this set up, I'm going to send back the HTML. And then the last thing to do is just to export my Cloud Function. I'm going to call it SSR app. And then an onRequest pass through the app. So let's do a quick recap. So we imported from Cloud Functions and then also React and React's render to string. We imported our app-specific code, being our top level app component and our get facts method. We imported Express so we could create our Express app with our HTP handler. Whenever someone makes a request, we'll get the facts, render that to string, set some caching, and then send back the HTML. So now that we have our server code set up, we just need to initialize Cloud Functions. So using the local module, I'll Firebase init functions. And it's going to ask us if we want to install dependencies now. And I'm actually going to skip this. So in the source folder, this is where all of my app level code is. And it all uses JSX and ES 2015 imports. So what I want to do is I want to create a server version of this app. And to do that, I can actually use Babel to transform this code into a common JS version and store that into the Functions folder. And I also can do the same thing for the index.js file as well. Because if we go into app.js, you can see that import React from React. This is ES 2015. Node currently does not understand this. So we need it to be transformed into a common js require. So to do this, I'm going to create a new script inside of package.JSON and call it Babel. So I'm going to use the Babel CLI. So I'm going to call Babel from my Node modules. And I'm going to take the source folder, and I'm going to convert it into the common JS version and store it in the functions folder/source. So now when I run Babel, you can see that it converted the files. And if we open function/source, we have all of our files. And up here, you can see that we're actually requiring React rather than using an ES 2015 import. So that is our source, but we also need to transform our server code. And real quick, I've noticed right here that if I say import star as Express that will cause an error with Babel. So I'm just going to use the default import instead. So now, I'm going to chain another command onto the Babel script. So I'm going to call Babel again, but I'm going to transform the index,js and just store that into the Function folder. So now I'll run Babel again. And this time, it compiled our source app.js to the Functions folder. And then also the index.js is at the top level of the Functions folder. And you can see right here we have our common.js requires. So we're really close to being able to deploy this to production. The last thing we need to do is we need to make sure that we have all the needed Node modules specified in the Functions folder for deployment. So if we go to our main package.JSON, you can see that we have three dependencies-- Isomorphic Fetch, React and React DOM. So I'm actually just going to copy these. Open up our functions packing.JSON and paste them in. And the last thing we need to do is we need to specify Express as a dependency as well. So now that I have all of my dependencies specified, I'm going to open up my terminal and CD into the Functions folder and then install all the needed dependencies. I'll CD out. And now I can set up my deployments. So I'm going to go into my Firebase.JSON, and I need to specify my rewrite. So the source is going to be the greedy star star GLOB. And my function name, if you remember, is SSR App. So if we go into index.js, can see that we named it export let SSR App. So now that I have my rewrite set up and all of my dependencies installed, I can do a local serve. So I use the local binary for Firebase. Say Firebase serve only functions and hosting. So here in the browser, we have our app, but it doesn't look like the app that we made before. It's just this unstyled unordered list. So if we go and inspect and view page source, you can see it's just the UL. There is no HTML. There's no body. There's nothing. It's just this unordered list. Because you can see on our server we're just rendering are app to a string. We're not actually embedding it into an HTML document. So to do that, we need to import from the file system. And we're going to read the index HTML, which I'm going to read file sync. In real life, you would want to use the async version. I'm going to get the index.HTML as UTF8. And then, now, what I want to do is I want to create a final version. And I want to replace the comment that I showed you earlier. So if you remember, in index.HTML we had this app comment. So what I can do is I can paste in this comment. And we can replace it with our final HTML. And then pass that back from the server. So now I'm going to run Babel, since we made some changes. So now that I've run Babel, I'm actually ready to deploy. I want to deploy to a new project. Because I deployed a non-server side version, now I want to deploy a new project that has the server side rendered version. So I'll use the Firebase CLI and call Firebase use--add. This will list out all of my projects. And what I want to do is I want to find the SSR React version. And it's going to ask me what it alias is. In this case, I'm just going to call it SSR since it's the SSR version. And now, I can deploy. So I'm going to deploy out. And now that I'm successfully deployed, let's go open it up in the browser. So here in the browser we can see our app. And if we view the source, we can see all of our HTML because our app is server side rendered. So that's all it takes to get started with server-side rendering with React. And in the next video, we're actually going to take the non-server-side rendered version and the server-side rendered version and then profile them using the Chrome DevTools and Webpagetest. So make sure to subscribe so you're notified when that video lands. So that's all for today. If you have any questions, make sure to leave a comment. And if you like this video, we'd appreciate you hitting that Thumbs-Up button. That's all. And I will see you all in the video. Hello. I'm here because the mike is not agreeing with the shirt. So if you don't see any neck movement, that's why. I hope this doesn't creep you out. [MUSIC PLAYING]
Info
Channel: Firebase
Views: 120,449
Rating: undefined out of 5
Keywords: server side rendering, server side rendered apps, rendering, firebase, fast rendering, fast render, html, fast first render, javascript, css, app.js, server-side rendering, angular, react, rendering code, javascript frameworks, javascript framework, firebase hosting, firebase developer, developer, dev, time to interactive, product: Firebase, fullname: David East, Location: MTV, Team: Scalable Advocacy, Type: DevByte, Other: NoGreenScreen, Reach DOM Server, DOM, GDS: Yes;
Id: 82tZAPMHfT4
Channel Id: undefined
Length: 21min 0sec (1260 seconds)
Published: Thu Oct 05 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.