DAVID EAST: Hey, everyone, welcome back to the--
I shouldn't really do this.
I know how to do it.
SPEAKER: Episode 6, take one, marker.
DAVID EAST: Hey, everyone.
Welcome to the preact episode in the Server Side Rendering
with JavaScript Framework series.
So in a previous episode, we built a server side
rendered React app.
And in this episode, we're going to take that same app,
and we're going to switch it on over to Preact.
So for those of you who don't know what Preact is,
it is a very small alternative to React.
So it has the same API service level as React,
but it does all those things in just three kilobytes.
And also in the previous video, we
had this problem where even though we
were server side rendering our app,
we still were making this extra network request.
So in this video, we're going to switch to Preact and fix
that extra request.
So let's dive down into the laptop and get started.
So here I have my editor up, and it's the same app
that I had before.
And what I want to do now is I want
to go into my package.json.
And you can see that my dependencies are react
and react dom.
I actually can go and get rid of these.
I want to keep isomorphic fetch, though.
So I'm going to install from Preact,
and I need to also install from Preact render to string.
And I'm going to save that as a dev dependency.
So you can see I have Preact and Preact render to string.
So now what I need to do is I need to CD into my functions
folder and then also install Preact render
to string and Preact.
So now when I deploy I'll have those dependencies ready
on Cloud Functions.
So when you go into my Functions folder, open the package.json,
you can see that we have react and react dom still
so we can delete that.
But we still have Preact and Preact render to string.
So now in index.js, I'm going to remove the import from react.
And then right here I'm going to change
this to import from Preact.
So Preact has a render method that we're going to use,
but it also has another method called h.
And h is its representation of JSX.
When we're building React apps, we
import from React even if we don't use React on the page.
And while it seems like we're not using it, we actually are.
Because when the app is compiled to plain old JavaScript,
you'll see that React is referenced in that JSX code.
So that virtual dom app tag actually
gets converted to a React function.
And the same thing happens in this case with h.
So now I'm going to copy this, and I'm
going to open up the app and paste it in.
But in this case, I don't need render.
I only need h.
So here we're using lots of virtual dom pieces.
So with this list item, h would be
called after the component is compiled out.
And the same with UL down here.
So now that I have my imports switched to React,
I need to set up Babel to use Preact as well.
So I'm going to go in my Babel RC
and specify an array of plugins.
And then this will also take in an array--
I'm going to say use the transform react JSX plugin.
And then provide a config object--
we say, for pragma, use h.
And this means use preact for JSX.
So now that my client side code is switched to Preact,
I need to go and switch to Preact on the server.
So in index.js, I'm going to get rid of the React import,
and I'm going to import from Preact.
So now instead of importing React dom server,
we're going to import from Preact render to string.
And this method is now just called render.
So we'll change that down below.
And now that this is fixed, we can go and run our build.
So open up the command line.
And I'll run webpack, and that works.
So now I'll run Babel, and that runs without any problems.
So now I want to go and serve this app locally.
And you can see that we have our page loaded,
but there's a bit of a problem.
There's actually two versions of this list.
So if I inspect the elements, you
see we actually have two unordered lists.
And these are two duplicated versions.
And if we go into the network and we throttle and do
a profile, you can see the first one loads because it's server
side rendered.
And then Preact boots up and then renders it again,
which is not necessarily what we want.
So you can see right around 1,500
milliseconds it paints a new version of the list.
So we actually want to go and fix this.
So the first thing I want to do is
we're going to get rid of that extra network request.
So we are getting facts on the server.
There's no reason you need to go ahead and get facts again
on the client.
So the trick we can do is we can open up index.html.
And just like how we're using this comet
to render the app inside of root,
we can use a similar trick to avoid this extra request.
So I'm going to make a script tag.
And inside of the script tag I'm going
to create a variable on the window
and call it dunder facts--
dunder being that it's wrapped in two under bars.
And then from here I'm going to create a comment,
and I'll use the same style as before and say,
this is where the facts are going to be rendered.
So I'm going to copy this.
I'm going to go back to my server.
So now on my server I'm going to create a variable called
facts.html, and I'm going to set that to be
what replaces the app comment.
So now that I have this window variable in place,
what I want to do is I want to embed the JSON
data in this script.
And that way when the app boots up this data
will be available hanging off the window, which
means we won't have to make an extra network request
if it exists.
So I'm going to go back to my server,
and I'm going to create a new replace function.
So I'm going to move the original replace where
we replaced the HTML to the top, and now I'm
going to replace the facts comments
with a stringified version of the facts array.
So I'll use json.stringify, and now
I just return the final HTML.
And we will have our data available on the client.
So now we're going to do an if statement.
And we're to say, if the facts exist off the window,
then we want to render the app with these facts.
Else we'll do a network request because the data
isn't available.
Now I'm going to create a function called renderApp
where I'm just going to consolidate this render code.
And now I can just refactor this and call renderApp
with window dunder facts.
And the same thing inside of this promise--
I can just pass through renderApp.
So now I fixed the extra network request.
What I need to do now is fix that double render.
And I can do that here in this render method.
So down here in render I can pass through a third argument.
So in the middle I'm going to pass
through a parent container.
So in this case, the parent root is body.
So now what this will do is it will tell Preact
that it needs to insert the facts into the body,
but it wants to merge it with the root element.
So Preact will know not to create another container
and to instead merge it with the existing server side rendered
app.
So just to recap, we created this
if statement to render the data off the window if it exists,
and we refactored into this renderApp function that
allows us to avoid that double render by specifying
the parent and the element to merge with.
So now I'm going to run webpack and also go out and run Babel.
And from here I can serve locally.
So now I have my app running on local host 5,000,
and you can see we have just one version of it up and running.
And if I go and view the page source,
you can see we actually have this window data in the script
tag.
So this is all the data we need to server side render.
Our app is embedded right in our document, which
means we won't have to make a network request to go and get
it.
So now all I need to do is go out and deploy my app.
And I'm going to use the same server code.
So I named my function SSR app.
And in my firebase.json, I have the rewrite
which specifies all requests that are not static
will call the SSR app function.
So with that I actually can go out and deploy.
And what I'm going to do, though,
is I'm going to create this little deploy script.
And I'm going to use the node module binary for the Firebase
CLI.
I'm going to use Preact, because that is the alias for my Preact
project.
And then once it's used that, I can go out and deploy.
So NPM run deploy, it will switch to Preact
and deploy it out successfully.
So now I'm going to go and open up
this deployed app in the browser.
So I have my app.
I'm going to go and view the page source.
We have window data.
We have HTML.
But now let's go to the network.
As you can see right here, when we request the bundle.js,
its size is just 6.1 kilobytes.
So this is all of Preact.
This is all isomorphic fetch and all
of our app in just 6.1 kilobytes.
And if we actually go back to the React app
and we inspect that, we can see that that was 45.8 kilobytes.
So almost 40 more kilobytes for the same functionality.
So in this video, we switched from React to Preact.
And we also avoided that extra network request
by embedding the JSON data in the document.
And we saw that with Preact that we dramatically
reduced our bundle size all the way from 45 kilobytes down
to 6 kilobytes.
So in the next video, we're going
to take the server side rendered version of React app
and profile it and compare that against the server
side rendered version of the Preact app.
So make sure to subscribe to get notified
when we release that video.
And if you enjoyed this video, please make sure to hit that
thumbs up button.
Otherwise, that's all for today.
I really hope you enjoyed this video,
and I will see you next time.
Now I'm going to go and do a--
now I'm going to go and simulate a real car.