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]