Episode Transcript
Transcripts are displayed as originally observed. Some content, including advertisements may have changed.
Use Ctrl + F to search
0:00
Welcome to syntax today. We have Tim
0:02
note cans on from Vercel. Next.
0:05
Yes. Co-author of next. She has to talk
0:07
to us all about everything that's
0:10
going on with React with next. She
0:12
has 15 with server components with react
0:14
compiler with turbo pack, kind of a
0:16
lot going on in the whole, this
0:19
whole space recently. So I thought like,
0:21
let's bring them on to talk about
0:23
it. So welcome, Tim. Thanks so
0:25
much for coming on. Yeah. Thanks for having me.
0:28
Where should we start this off? Um, yeah,
0:30
well, I mean, we could start off with
0:32
some of the, the hottest new stuff, which
0:34
I guess compiler. So, you know, I guess
0:37
first and foremost, I know,
0:39
I know, you know, this is a react thing and not
0:41
a next JS thing, but I'm sure
0:43
you all are very tightly integrated into
0:46
this, what does the react
0:48
compiler do for those people who might not be aware
0:50
of what it is and what it does? Yeah.
0:54
So, um, if you
0:56
watch the recent ReactConf keynote,
0:58
um, if you haven't watched
1:00
it, I'd highly recommend you to watch it because
1:02
it's definitely a much better explanation than I will
1:04
ever be able to do, I think. Yeah.
1:07
But in essence, it's like, um, in
1:09
like 2018 React hooks were introduced. Um,
1:11
there were a whole lot of hooks,
1:14
right? So like, uh, use state, use
1:16
memo, uh, the kind of thing. But
1:18
really like in the end, like that
1:21
didn't have the ergonomics that you want. Uh, eventually
1:23
like when you're writing this code, so they
1:25
were like created in a way that you can
1:28
like incrementally get rid of them if you were to
1:30
build a compiler, uh, at some
1:32
point, that's really what the React
1:35
team did. So they went ahead on
1:37
like a pretty long journey. I'm
1:39
not sure exactly like how long they've
1:41
been working on it exactly. Many years,
1:43
I think. Yeah. Something like four years,
1:45
which, uh, which also causes like people
1:47
to dab, like we'll ever like come,
1:49
right? Like, uh, are we ever
1:51
going to have suspense? Like that kind of thing,
1:53
right? Um, but now
1:56
in the last, you know, like two, three weeks
1:58
ago, um, they, they now. that
2:00
the React compiler is now both
2:03
open source, so you can view the source
2:05
code. And it's in
2:08
beta, so you can try it out. They
2:10
didn't recommend you to ship it to production
2:12
yet, but they are shipping it to production
2:14
themselves in Instagram and
2:17
in other places at meta
2:20
to really dog food the
2:22
system. That
2:25
gives you exposure to a lot of different types
2:27
of code, right? So it's similar to any time
2:30
you start building a compiler that transforms
2:32
the original source code into something else,
2:35
there are really edge cases and they're
2:37
trying to catch all these edge cases.
2:39
So that's why it's released early, so
2:42
people can try it out. And we're like, what is it?
2:45
That's the initial question. It
2:47
basically does memoization for you automatically.
2:51
And not just for the basic
2:53
cases, I have a value that
2:55
is derived based on some state or
2:57
some... Basically
2:59
the things that you would usually call use memo
3:01
for, that kind of thing. Those
3:04
are the things that I can, having
3:06
some re-acknowledge, I can manually add
3:08
them and make rendering better, right?
3:10
Like, don't re-render this thing. But
3:12
it goes much further than that. So
3:14
it goes into... I
3:17
was talking to someone on the forcel team
3:19
that works on the forcel website recently. I
3:21
was showing in the React compiler side
3:24
to side to what, if you don't have it enabled.
3:27
It was like, I thought this is
3:29
always how React worked already. So why are you
3:31
showing me this new thing? So
3:35
another way that I look at it is, it
3:38
makes the assumptions that you had around how
3:40
React renders a bit more the
3:44
reality with the compiler. Because you don't have
3:46
to think about, where do I
3:48
add memo? Where do I add use callback? Where do
3:50
I make sure that things don't re-render? And
3:53
instead, you can just write my,
3:55
like, project logic and combine
3:58
it and configure it. Does
4:00
this thing need to be memoized? Does
4:05
it not need to be memoized? Because
4:08
the other side of things, early optimizations, at
4:11
some point you get so into React that you get over this.
4:15
It's like this meme where you go
4:17
to peak and then back to
4:19
not memoizing anything. At some point you're like, I know React so
4:21
well. I'm
4:25
going to memoize everything. I
4:27
don't want anything to change between renders. That's not
4:29
always the best way to do it in the
4:32
end. The
4:34
React compiler can just take your
4:36
original source code, it can optimize
4:38
it in various ways by memoizing more
4:41
bits. It's not just
4:43
the state VMIs or specific
4:45
derived state as well, but
4:47
it's more like it can memoize
4:50
your JSX as well, for example. In
4:52
some cases when some input values change,
4:55
only a part of your JSX tree needs
4:57
to change. It
4:59
can automatically make sure that those
5:01
cases are also not re-rendering in
5:03
this case. That's one
5:05
question I had, and I haven't been able to
5:07
figure this out. When
5:10
people have context, you
5:12
put the context in a provider, and
5:15
when the values in context change, a
5:18
higher subtree of context will re-render
5:21
itself. That's always been the
5:23
thing, it's like, don't put context too high. Then
5:26
I tell myself, I kind of want it high,
5:29
because I just want my data where I want it,
5:32
and I want it to figure it out
5:34
for me. Is that something that the React
5:36
compiler is going to fix for us? The
5:42
lesser-known one is that, so it doesn't
5:45
fix that, I think. I'm
5:47
not 100% familiar with this, so don't pay
5:49
me down a little bit. I don't think
5:51
it fixes the context one, but
5:53
it does fix the other case, which is like prop
5:55
drilling. When you're
5:57
writing an app that is like a... in
8:00
front of you right now. Usually
8:05
you would never do yourself, or
8:10
it's like, peak, I'm going to memorize everything. When
8:15
the React compiler goes stable, once
8:20
it goes stable, you wouldn't have to think about this anymore.
8:25
You're like, by the way, this is things that
8:27
I could have done myself, but I'm actually not
8:29
doing. One example
8:31
is you define a variable, const
8:34
a is 10, like a string or
8:36
integer that you put in. That's
8:39
just constant. It
8:42
can actually reason about that and move
8:44
it into the place where it's used
8:46
instead of having it in the function
8:48
scope where it
8:50
is completely reinstantiated because of
8:52
the re-rendering. That's
8:54
one thing that I think a lot of
8:57
people don't realize is that if you
8:59
need a little function inside of your
9:01
component because you handle submit or something
9:03
like that, if you define
9:05
that function inside of your component, which a lot
9:08
of people want to do because you have access
9:10
to your state and everything else there and you
9:13
don't have to pass it all in,
9:15
then every single time that component is
9:17
re-rendered, then that function is reinstantiated. Unless
9:19
you're using a use callback and it
9:21
gets really complex really quickly
9:23
and I'm really glad that this
9:25
will do that tricky stuff for
9:28
us. Yeah. Let's
9:31
take it back to Next.js for a second too. Given
9:34
that you said this stuff's all in preview
9:36
and it's coming from the React team, does
9:39
Next need any modifications to
9:41
take advantage of this stuff once
9:43
it is launched or are people
9:45
going to be able to use
9:48
this with whatever compatible Next.js version
9:51
or the React version when it's fully released? Yeah,
9:55
for sure. It's
9:57
using some APS that are in React that are also
9:59
not available. available in React 18, for example. So you'll
10:02
have to use React 19. So today
10:04
you have to install React 19 RC. If
10:07
you're using Uprighter, you don't have to install React
10:09
itself because we ship the version of React that
10:11
you need. But
10:13
in practice, you need React 19 because
10:16
of specific APIs. There is a polyfill
10:18
for it, but journey speaking, probably
10:20
don't want to use it. Just use
10:22
the latest React instead. And
10:26
then the thing you have to do in Next
10:29
is using a bevel transform today.
10:33
The important thing to notice is it's not
10:35
a bevel transform in the sense that
10:37
you would usually think of, I'm going
10:39
to take my input and give some
10:41
output. It does generate some
10:43
output, but in between, there's a different
10:45
compiler that has a
10:47
reasoning about bevel AST, but it could
10:49
also support SVC in the future or
10:52
any other parsing
10:54
and AST transform, basically.
10:57
So on that side, it means that we have
10:59
to add bevel because we've been on
11:01
this journey to move away from bevel
11:04
for compilation for
11:06
Next.js using SVC instead,
11:08
which is significantly more
11:10
performant for individual file compiles.
11:14
But now we have to add back bevel,
11:16
for this case at least, until they
11:19
start an industry ride or something like that.
11:21
That has already been experimented with by the
11:23
team as well, by the React team. In
11:25
practice, if you're using Next.js, all you have
11:27
to do is upgrade to the React 15,
11:30
the Next.js 15 RC, and
11:33
upgrade to React 19, which
11:36
is something that they'll just tell you
11:38
to upgrade because we also depend on
11:40
that. And then you have to enable
11:42
experimental React Compiler through and
11:45
install the compiler because the compiler right now is in
11:47
beta, so we want to make sure that you can
11:49
upgrade it yourself so you can get the latest improvements
11:51
to it whatever you want instead
11:53
of being in lockstep with Next.js itself. That
11:56
doesn't sound too painful. Yeah.
11:59
Awesome. Let's talk about React
12:01
server components. I'm sure that you're
12:04
probably one of the top people in the
12:06
world who's, who's heard so much of the
12:08
feedback, good and bad from, uh, react
12:11
server component world. And also, I think
12:13
there's like a lot of confusion around
12:15
and around what it is. So are
12:17
you able to give us a quick,
12:20
your idea of what react server
12:22
components is and, and how
12:24
we should be approaching our applications? Yeah,
12:27
it's a, it's definitely a hard one. It's
12:30
been a hard one to explain to people,
12:32
uh, as you've probably seen, uh, online, so
12:34
released, uh, server components and next chairs like
12:36
one and a half years ago or like
12:39
slightly over one year ago now, um, one
12:42
half years ago for like the, the initial like beta
12:44
release of it. Um, we could try
12:46
it out for the first time. I really liked react
12:48
server components are like, like, like
12:50
it's sad in the name, but like you
12:53
render react components on the server slightly different
12:55
from what you did before. So like next
12:57
year, uh, since the very first version had
12:59
a service at rendering service
13:02
at rendering is like taking react components, generating
13:04
HTML, react server components is
13:06
more of a like
13:08
step before that. That basically replaces everything
13:10
that you did with get service or
13:12
props, get static props. Um, and then
13:15
like, it's able to render react components
13:17
as part of that. Um,
13:19
there's a much better and like deeper
13:22
and like more high level explanation of
13:24
this in a dense talk at react.com
13:26
would definitely recommend looking at that. Uh,
13:29
and that, that one talks about like react for two
13:31
computers, which is like, I'm running
13:33
react on two computers. Like
13:35
one, one computer is, uh, the, like the
13:37
server basically. And it, like it doesn't start
13:39
out there, but like, that's where I know
13:41
what's spoiled the entire talk, but it's like,
13:44
you basically end up with like, you
13:46
have a, like one computer is your server. The
13:48
other computer is, uh, the browser, and you can
13:51
move logic between them in like
13:53
whatever way you want because
13:55
everything is one rendering model. Uh, so you're
13:57
still using react. You use like, familiar
14:00
with, the only
14:02
difference is that NaRIAQ has this primitive that
14:04
allows us to render on the server only,
14:06
which is something that we couldn't do before.
14:09
That unlocks some other benefits. One of them
14:11
is that you can now do data fetching
14:13
on the server, where you don't need special
14:17
framework APIs. We
14:19
initially coined the get initial props pattern, where
14:21
you can do data fetching on the server
14:23
and on the client. Then
14:25
later on edit, get service at get static
14:28
props, get service at props, get static
14:30
props. Get service at
14:32
props was just a way to say,
14:34
before my React rendering starts, I'm going to
14:37
get, the framework is going
14:39
to call this function. Then I
14:41
as the application developer can write some
14:43
logic that gets data from anywhere. It
14:45
could be a database or an
14:48
API or anything like that. Then we
14:50
pass those props into the component. Now
14:54
with server components, that step is basically
14:56
replaced with a full
14:58
React render. That means I
15:01
can write components, those components can do
15:04
data fetching, and they can render other
15:06
components as well as interactive
15:10
components that are the ones that you wrote
15:12
before. If you're familiar
15:14
with React, it's just
15:16
an additive feature basically on
15:18
top of everything that you already
15:20
knew that allows you to do
15:23
even more than we would ever have
15:25
hoped for when we started Next.js
15:27
for example. I
15:29
can now do data fetching in my
15:31
components or deeper into the React tree.
15:34
I could share libraries
15:37
that do data fetching and provide
15:40
components for that. It
15:43
is fully portable in the React ecosystem
15:45
as well, once more frameworks
15:47
start adopting this. One
15:50
example of that is that Remix is looking
15:52
into server components, the Red Boot folks are
15:54
looking into server components, and at that point
15:57
you basically have a
15:59
React component you can write. right,
16:01
that is encapsulating both like client side behavior
16:03
as well as server side behavior. And
16:06
like one example of that is I can
16:09
build a like MySQL
16:12
admin type React component. And
16:15
that's portable between all frameworks that
16:17
use React server components. And
16:19
it can pass in like props there.
16:21
And they can be interactive as well,
16:23
right? You can add like interactions using
16:26
server actions or things like that as
16:28
well. Yeah, it's really exciting to me
16:30
that we'll now be
16:32
able to ship components that define how does
16:34
it work on the client, how does it
16:36
get its data, and how does it render
16:38
on the server, all inside
16:40
of an encapsulated component. Because
16:43
one of the things that people, like
16:46
people who build like websites for clients, they're
16:49
still saying, I want like the WordPress
16:51
plugin experience, right? Yeah, right. And that
16:53
has always been really tricky to like
16:55
move to the React world.
16:57
But now with this idea of like,
17:00
yeah, you can NPM install something
17:02
and its batteries included for all
17:04
of that, maybe pass in tokens or
17:07
auth or something like that, it's pretty
17:09
exciting to me. Yeah,
17:11
it's really cool to see. Obviously,
17:14
like when we just released it, there was like
17:16
a lot of pushback, like, oh,
17:18
things are getting more complicated. Why
17:21
do I need to know about this use client thing?
17:23
Or like what are client components even? Why is this
17:25
a new thing? And like those were not even like
17:27
the new thing, right? So they were like the thing
17:30
that you already had. Just give it
17:32
a name, basically, right? And then server components were
17:34
the fully new thing where you had to be
17:36
like, I want to use
17:38
state, right? Like, let me call you state
17:40
so that I can like click
17:42
this button and then like something is like
17:45
shown or something like that. But
17:47
you can't do that on the server. Because like obviously
17:49
the server doesn't have this interaction model of being able
17:51
to like render and
17:53
then like re-render at some point. As
17:56
part of like running on the server.
17:58
So there's like new constraints. on
18:00
that environment. Especially
18:05
confusing to people coming from, I'm
18:10
only using clients that react and then moving
18:12
to, I
18:15
can only do certain things on the server type thing. One
18:20
of the cool things that we're seeing now at this point is
18:25
that I provide RSE-enabled features.
18:30
One great example is Payload CMS
18:32
is building their entire editor as
18:35
React Server components with server actions and all
18:37
that. What
18:40
they allow you to do is they
18:42
allow you to bring the entire
18:44
CMS as a React component. Those
18:52
can adjust behavior in the CMS
18:54
itself. You can build override
18:57
particular fields in the CMS, which is
18:59
really cool to see as well. So
19:05
many like Sanity is doing something like
19:07
that as
19:09
well. We're finally at the stage where people
19:11
are coming around to it and
19:15
they're seeing, okay, this thing actually does make sense for
19:17
my case. But
19:20
maybe only the clients and
19:22
navigation optimizations or specific features
19:25
of React that are enabled by this, transitions
19:28
and things like that. It
19:30
definitely feels like the ReactConf, if
19:33
you're into React, I highly recommend watching
19:36
literally all the talks in the entire
19:38
livestream, which is eight hours long. All
19:42
of them are super high quality. I did it myself.
19:44
Don't do it in one sitting, I would
19:46
say. I'm not speaking.
19:51
The talk that Dan gave clarified server components click
19:53
for me now. It
19:55
was the general thing I heard from people. Similarly,
19:58
you're seeing other... Like,
20:00
uh, like explanations of like, how is this
20:03
like making sense to me now in, in like my
20:05
particular case. So even if you're building like an SPA,
20:07
you can still leverage like suspense
20:10
and transitions and like async transitions,
20:12
for example, to make
20:14
it easier to like schedule work and things like that. What
20:17
does that look like for somebody who
20:19
has built an entire application that is
20:22
maybe a next JS and it's
20:25
client client hydrated, right? And they say,
20:27
okay, well now I want to start
20:30
opting in to, to server components. Um,
20:32
I think that's where a lot of the frustration from
20:34
people go because they go, yeah, oh yeah, I'm going
20:37
to start using server components and then you import something
20:39
that has a hook in it or
20:41
is met for the client and you get all these,
20:43
these errors and people get really frustrated with it. Right.
20:46
What, what's the path? Like, what do you recommend
20:48
for somebody when they're moving over? Yeah.
20:52
So it's, it's kind of like, um, the
20:55
misconception is like where you start migrating, so like
20:57
the, the, the, where you start migrating is like,
20:59
usually people are like, I'm going to use this
21:01
for this small component on the page. That is
21:03
like, like a button that
21:05
doesn't need interactivity, right? Or something like that.
21:08
However, the, um, the entire model is
21:10
built on the other way around,
21:12
like you're introducing server components at a place where it
21:14
gets service. I props walls. So that's like before
21:17
the actual like, like client
21:19
components rendering. What that means
21:22
is that if you want to start migrating
21:24
the first place where you start is not
21:26
so much at this
21:28
like granular level per se. It's
21:30
more the outer layer of the
21:32
app. So when you start migrating,
21:34
the first thing that you do, um, and there's
21:37
many ways to do this, but like the first thing
21:39
that you usually do is like you go into like
21:41
page.dzax or page.js. Uh,
21:44
usually people like TypeScript nowadays, but like you
21:46
can still use JavaScript as well if you
21:48
want. Um, the first
21:51
thing you do is like you, you add, uh,
21:53
because you already have this page that's ex or
21:55
like maybe you're using pages, right? Or ends like
21:57
index that you asked or something like that. Yeah.
21:59
So you. create this page with TSX and you
22:01
don't add use client there. What
22:04
you do instead is you write a component and
22:06
import another component and in that
22:08
component you add use client. That's
22:11
what that means is that now the outer
22:13
layer is a server component and
22:16
the inner component you're rendering in that server
22:18
component is a client component. Okay,
22:21
so basically you're taking your page and
22:23
you're saying this page is server rendered.
22:25
Now I'm going to opt in
22:28
everything to client right? You say use client that's
22:30
kind of I was moving my own website over
22:32
to it and I was like alright I just
22:34
need it to work. I made
22:36
everything use client and then
22:38
you can keep going on that but I started
22:41
chipping away at it. Yeah, yeah. That's
22:43
a great when you're migrating anything
22:45
to get the versions up
22:47
and then get the site at least back to
22:49
where it was before opting into the new stuff
22:52
I think is always a good strategy. For me
22:54
it was like a mental hurdle where I was
22:56
like no I don't want it. I want it
22:58
all to be server rendered. Then I was like
23:00
telling myself Wes the whole
23:02
freaking website was client rendered previously.
23:05
Yeah, it's okay to go back
23:07
to the whole website being client
23:09
rendered incrementally. You opt into to
23:12
each of them. So like once
23:14
you're at a page server rendered then what do
23:16
you how do you handle that page? So
23:19
yeah like migration story you
23:21
already have a website like syntax for
23:24
example which was built on on the
23:26
next before you
23:28
basically just take that that like page you had in
23:30
the pages writer and usually that
23:32
one had to get static props or get service or
23:34
props. So the way to think about is that the
23:36
component you're adding as like page that these acts that
23:39
one is the one that is doing to get service
23:41
or props or get static props that you previously did.
23:44
So instead of like having the specific like
23:46
export function get service or props what
23:49
you do now is you move all that logic
23:51
into this async server component that
23:53
is the page itself. So you
23:55
move all that logic down and then you
23:57
create a separate component that is just the
23:59
theme that was rendering before. And
24:02
that separate component, you add useClient, and
24:04
you pass all the props in, same way that
24:06
getServiceProps passes them in. That
24:09
we do in like Nexus internals, basically, right?
24:12
Which is just like you pass the props. Literally,
24:14
you just add a props object there. You spread
24:16
on to the item. Then
24:19
the next step there is, there's many
24:22
ways to do this. But you can say maybe
24:25
that first component that is using the
24:27
props is also not interactive. It doesn't
24:29
have useClient, or it doesn't need useClient
24:31
because it doesn't have useState. It doesn't
24:34
use effects or anything like that. So
24:36
what you do at that point is you say, I
24:39
move it done one more level. So
24:41
now we're down to maybe
24:43
if that page was like the shell
24:45
of the page, like header, the content,
24:48
and then the footer, maybe
24:50
only the content
24:52
doesn't need it, but the header and
24:55
the footer do need some interactivity that
24:57
is like useState or useEffect. So
25:00
what you do at that point is you just move the
25:02
useClient deeper and deeper until the point
25:04
where you're like, it doesn't really make sense anymore to
25:06
do this. And then for
25:09
the first iteration of it, you're done at that
25:11
point. At least
25:14
that's my opinion on migrating these
25:16
Nexus apps. The
25:18
misconception that people have is my Nexus app in
25:20
PageSrater is bad. I need to move to AppRider
25:22
to then move everything to the server. You
25:25
don't have to do that. You can just use
25:27
client components. Client components are fine. I
25:31
think when
25:33
we released server components in Next.js, we
25:36
talked so much about what server components can do. It
25:40
was lost that client components are fine and
25:42
they're part of the same model, and you
25:44
should be using them still. There's no reason
25:46
that the interactivity of clicking
25:48
buttons or opening menus or popovers or
25:50
anything like that is
25:52
server-side behavior. You
25:55
can still use all the features of React. Client
25:58
components are totally fine. Basically,
26:00
right. So at that point, you're done
26:02
for now. And then what you can do from that
26:04
point on is like you can say, maybe
26:08
some of the things that are in my header are actually
26:11
things that can render on the server and they need data from
26:13
the server. So what you
26:15
do initially is you're passing like maybe
26:18
you're fetching all the data for the page, which is what
26:20
you did in the get service with props, get static props.
26:22
You're passing all the data from the page, like done
26:25
into these like other components,
26:27
right? So you're passing into
26:29
your header component, hey, this
26:32
is the data for the header, for example. So
26:35
what you can do at that point is you can move the data
26:38
fetching further down or like
26:40
if that is at all possible, doesn't have to be
26:42
that way, right? You can also say, I'm still going
26:44
to do all my data fetching at the top. But
26:47
you do get some benefits from moving them down
26:50
at that stage. So at that stage,
26:52
you can say, I'm going
26:54
to introduce suspense boundaries to show more like loading
26:56
states in my page, for example, my content can
26:58
come in later than the header, for example, that
27:00
kind of thing. So
27:02
what you can do at that point is you
27:04
can introduce suspense boundaries, like slightly deeper in the
27:06
tree, while the rest is still
27:08
a client components. Then you
27:11
already get a slightly better experience because you can
27:13
get the header, the footer, but then like the
27:15
content has a loading stage, like a skeleton or
27:17
like some kind of like spinner and anything you
27:20
want really, you can provide your own
27:22
loading stage there. But at that
27:24
point, you've already improved the
27:26
experience of your app. It streams in like
27:29
faster. You get like faster times first byte,
27:31
slightly better core web titles, that kind of
27:33
thing. And then you can
27:36
say, maybe I need to start moving some
27:39
of my other like parts of the header, for
27:41
example, to be partially
27:43
server components, partially client components.
27:46
So one of the very interesting things
27:48
is that it's a one way street.
27:50
It's like a door, which
27:53
is like a hole to the other side
27:55
of the, to the
27:57
other machine, to the other computer, which is
27:59
the client. So now
28:01
you can say in my server components, I
28:05
can pass data to my client components. I
28:07
can pass data to the browser, for example,
28:09
even though there's still like rendered HTML on
28:11
the server. I can just like
28:13
pause these props that I pre- it's similar to
28:15
what Get Server Props did, right? So you just
28:17
like do some data fetching and you pass it
28:19
to the browser as well. And
28:21
if you ever looked at the connections app, you
28:24
would see like underscore underscore next data. And
28:27
that would have like a large blob of like all your data
28:29
for Get Server Props. Server components are
28:31
client components. Yeah, sorry. I want to talk about that
28:33
for just a little bit because I think that's really
28:35
neat. For the longest time,
28:37
I was like, I really wish Next.js
28:40
would come out with like a state
28:42
management or like a data fetching library
28:44
or some opinionated way to
28:46
fetch data and pass it to the client.
28:49
Yeah. And for
28:52
the longest time, I was like, can they please do this? And
28:54
then server components came
28:56
out and Next.js had this
28:58
like revalidate tag, revalidate path,
29:01
cache API. And I thought
29:03
like, I'm not sure
29:05
I need that anymore because you can
29:07
make a server component fetch the data
29:09
and you can pass it to the
29:11
client component via props. And
29:13
you can clear that data with
29:15
revalidate tag. And I
29:18
went from wanting this like Redux
29:20
type store on the
29:22
server or on the client server to
29:24
it's just a fetch request with props.
29:27
Yeah. Was that the... Do you see
29:29
a lot of people saying that? Yeah,
29:31
I think that started with the get
29:33
static props, get service or props already
29:35
a bit. There was like a lot
29:37
of like cases that
29:39
you can model in this way. The only thing that
29:42
was missing was like a primitive for what
29:44
do I do when I do interactions. So like
29:46
interactions could be like client
29:48
set interactions like state and like effects and
29:50
like on click and kind of thing. Or
29:53
it could be interactions that involve
29:55
the server. So like things that are like submitting
29:57
a form or things like that. on
44:01
Express middleware. And I'm
44:03
thinking to myself, all right, I'm going to
44:05
move off Express eventually. And
44:08
what happens is I'll have a middleware
44:10
where I'll attach a user ID or I'll
44:13
attach a country, and then I'll move
44:15
on to the actual handler. And then
44:17
you assume that data is in the request.
44:19
So I moved a lot of that
44:21
out of sticking it into the request and
44:23
then pulling it out. I moved that
44:25
into the async local storage API because then
44:27
it's just as long as it's in
44:29
the call stack, right, it's available to
44:31
you. And Next.js uses that as well for
44:34
what, cookies and headers? You simply just
44:36
call? Yeah. What's the API? Yeah,
44:39
it's literally cookies and headers. So you
44:41
call cookies or you call headers and
44:43
you got a cookie store, header store,
44:45
back header object. React
44:47
uses it for the cache
44:49
API as well, like the new, like the
44:52
one that you can call to
44:54
dedupe in the same rendering on
44:56
the server. I think it's like
44:58
part of that actually. The React
45:01
cache doesn't work in
45:04
the same way across
45:06
this rendering basically. So
45:09
that might be one of the buckers. Because otherwise, if
45:12
you do data fetching and you want to dedupe it
45:14
in some way, you just can't because it's just not
45:16
tracking that in this way. So
45:19
maybe something like that. Yeah, OK. We
45:23
got 10 minutes left. I got a lot I want to
45:25
ask you about here. That's what I was looking through here.
45:27
Our questions were like 10% of
45:29
the way through the ones that we had
45:31
written down before. I think if we could touch
45:33
really quickly on Turbo Pack, like what it
45:35
is and what problems it's going
45:37
to solve, I think that would be probably useful.
45:40
And if we want to have an entire
45:42
show on Turbo Pack at some point, I'm
45:45
sure we could open that up as well.
45:47
So Turbo Pack obviously is the, or maybe
45:49
not obviously, it's the rewritten web
45:51
pack in Rust or it's the
45:53
succession to web pack. And
45:57
Next.js has been running on web.
46:00
for very long and what problems
46:03
have you hit so
46:06
that you need to build Turbo Pack? Yeah,
46:09
it's definitely a long journey on
46:11
a web pack. When
46:14
we released Next.js, it was initially built on
46:16
web pack and this is quite
46:18
some time ago, it's 2016. We've
46:22
been around, as they say, in
46:24
the framework lens, like we survived for a
46:26
long time. It's similar to the
46:28
rest of the industry. Basically what
46:31
is happening over these seven years
46:33
is that people start building larger
46:36
and larger and larger apps on
46:38
these frameworks. So it's not just
46:40
on Next.js, it's also on Next
46:42
and other frameworks. So
46:44
what we see is that people just end up pulling in
46:47
more modules, more NPM packages,
46:49
more larger UI libraries. So
46:53
like UI libraries, you might think of like, they're
46:57
probably shipping like 100 components, right? But if you
46:59
look at some of the newer libraries,
47:02
like I'm not
47:04
going to destroy anyone here actually, like
47:06
some of the new libraries are shipping like 10,000 re-exports,
47:09
right? Like they're shipping like 10,000
47:11
different components that you can import.
47:14
But in order to process those, we need
47:16
to compile all those 10,000 modules and then
47:18
say which one is actually used and like
47:20
skip, like if you can't really skip over
47:22
a bunch of these. And
47:25
sometimes you do like import star as like
47:27
some library name and that means we have to
47:29
compile all of them, right? Like that kind of
47:31
thing. So as
47:33
a complexity of like JavaScript applications
47:36
keeps growing, we're basically like hitting
47:38
these limits of Webpack
47:40
itself, of like some of the newer
47:42
vendors even. So
47:45
what we started out with is like, we were
47:47
basically evaluating like, does it even make sense to
47:49
keep like running a Next.js or
47:51
like running Next.js on Webpack or should
47:53
we use some of the like
47:56
newer vendors that came out or anything like that. And
47:59
then, when we looked at the complexity
48:01
of the apps that we already
48:03
get with Nexus today, as well as
48:06
all the complexity of extra
48:08
bundling for server components, client
48:11
components, multiple passes, maybe you
48:13
want to deploy on the
48:15
Edge or Node.js, and then
48:17
there's just a complexity in
48:19
the amount of modules that
48:21
get processed. One example of
48:23
that is if you have
48:25
a client component, like
48:28
as you probably know, and maybe not even knows, client
48:31
components render on the server as well to
48:33
render HTML to basically speed up the initial
48:35
render. In
48:38
order to get there, we need to take your
48:40
module, and your module is importing,
48:43
say, a large icon library that is the 10,000
48:45
React support, for example.
48:47
Now we need to process those 10,000 modules for
48:49
the server as well as for the client
48:52
because they're in different conditions. They
48:54
get different optimizations, they need to
48:58
maybe those, for the browser, need to
49:00
be ES5, for instance, the server can
49:02
be whatever, like Node.js version you're running,
49:04
that kind of thing. That
49:06
means we have to process all of them pretty
49:09
quickly. What
49:11
it means to practice it, instead of 10,000 modules, you're processing 20,000
49:14
modules. That stacks up really quickly
49:17
as you get more
49:19
and more modules into your client components, into your server
49:21
components, that kind of thing. We
49:23
really have to build a solution for how
49:26
can I optimize these very
49:29
large graphs and make sure that everything is
49:31
processed in a way that is reliable
49:33
as well? Because for Webpack,
49:36
Webpack doesn't support running both
49:38
server and client compilation in the same compiler.
49:41
What we do for Webpack is we run
49:43
three compilers. We
49:45
run one for the server, one for
49:47
the client, and one for Edge. Edge
49:49
is the special target
49:51
where you get a slightly more constrained
49:54
environment. In order to coordinate
49:56
that, we have
49:58
to manually coordinate. You start
50:00
now, you start then type thing. This
50:02
one is done. Now we need to trigger this other one.
50:05
And we just knew that that wasn't as reliable as we
50:07
wanted it to be. So
50:09
eventually, we started building TurboPack,
50:12
or what turned into TurboPack, which
50:15
is a single. The
50:17
idea was we created a single module graph that
50:20
can span the server, client, server components,
50:22
client components, edge, whatever you run into.
50:25
And it can just process all of these
50:27
modules in parallel,
50:30
because Webpack is limited to single core
50:32
right now. You can
50:34
add some parallelization, but it's not super.
50:37
It doesn't speed up things that much. We
50:41
leverage all the latest compiler
50:43
technology or transform technology, like
50:45
SLVC. We
50:48
implement caching from the start. One
50:51
of the issues that Webpack had from
50:53
the start was that it was
50:56
a research project by Tobias. The
50:59
original story of Webpack is pretty interesting as
51:01
well. It turned into this thing
51:03
that everyone used. From the
51:05
start, it wasn't built to be this thing that everyone used.
51:08
So over time, they had to optimize
51:10
a lot, add more caches, add hot
51:12
caches into the system, add disk
51:15
caching on top of it, and things like that. And
51:18
what we did for TurboPack is we started out with the
51:21
caching layer. We need to
51:23
have a task runner caching layer
51:25
that is as solid as
51:27
it can be, so that you basically get
51:30
reliability from the start
51:32
across parallelizing across many
51:34
CPUs, caching for
51:36
disk, that kind of thing. And
51:39
then we can build any tooling
51:41
we want on top of that. So we basically
51:43
built a library called TurboEngine. TurboEngine
51:46
is the thing that is powering
51:49
all of TurboPack. And
51:52
potentially in the future, also part of TurboRepo,
51:55
because they recently rewrote everything in Rust.
52:00
works is that anything she writes
52:03
in Rust, you can basically
52:05
annotate with this function directive from
52:07
Turbo Engine. And that
52:09
makes it cached by default automatically. It
52:13
knows when to rerun when you do disk
52:15
IO, for example. And it just automatically works
52:17
out of the box with that. What
52:20
you get with having this caching layer is
52:22
that now, anytime you make a change, we
52:24
can quickly recompute what thing changed and
52:28
what thing needs to be recomputed. And we
52:30
only recompute that narrow part of the graph. So
52:33
that means that any time you make an
52:35
initial compile, it still compiles all your
52:38
modules, right? But then when
52:40
you make a change, it can just recompile
52:42
only to CSS. So it can recompile only
52:44
the tiny part of the JavaScript that needs
52:46
to be recompiled and then apply it on
52:48
the server, apply it
52:50
on the client through Fos Refresh or
52:52
anything like that. One
52:54
of the goals was
52:57
also to bring Fos
52:59
Refresh down to sub 100 milliseconds
53:01
or so. Oh, yeah. Oh, that's
53:03
awesome. For like pretty
53:06
much all changes, except for server components, because
53:08
server components also need to render on the
53:10
server. So we re-render the entire page. In
53:12
that case, if you're
53:14
changing client components, it's near instant, basically,
53:16
right? The problem we had with Webpack
53:18
was that it's not near instant when
53:20
you have these 20,000 modules or
53:23
30,000 modules. Because
53:25
that graph of changes
53:27
is massive in the Webpack case.
53:30
So it would take one,
53:33
two seconds before you see anything on the
53:36
screen. And if you were unlucky, you would
53:38
get a much larger recompile, and it would
53:40
take much longer than that, even. So
53:43
that was one of them. And then the
53:45
other is that most of the things that
53:47
people are complaining about are not recompiled times,
53:49
actually. It's the initial compile. So
53:52
it's just like, I boot up the server. I
53:54
go to a page. How long does it take
53:56
me to show that page? And we're combining those
53:58
on demand, right? So that means. And
54:01
we're basically shifting the rug from you boot up the server
54:03
and then you wait
54:05
for five minutes, which is what you
54:07
would get with some of the initial
54:10
versions of confiders that were
54:12
built on top of Webpack, for example. Instead,
54:14
what we do is we only start
54:17
compiling where you actually request a page and
54:19
we only compile the stuff for that page.
54:21
For that, the parallelization
54:23
is a big optimization,
54:26
as well as having persistent caching. Yeah.
54:28
For parallelization, we have kneel down and that
54:30
works. What is really interesting is that for
54:33
the for cell website, what we saw is
54:35
that on some of the slower pages,
54:38
Webpack with a
54:40
cache, like this caching, would actually be 10%
54:42
slower than Torupak
54:44
doing everything from scratch. So
54:48
that was like one of the interesting wins
54:51
that we had. And comparing it to
54:54
running it against cold Webpack would
54:56
be even better, obviously. But
55:01
that was one of the things that I was really interested to
55:03
see. And this is without us having persistent
55:05
caching in Torupak yet. So that's what we're
55:07
working on right now, to have persistent
55:10
caching so that if Scott starts to work
55:12
on the syntax website, he
55:14
makes some changes. He might not
55:16
be working on it every day. So
55:19
you make some changes, you push
55:21
them to production, and
55:24
then you wind
55:26
on the server. So you control C and you
55:28
just go ahead with your day. And
55:30
the next day you come back and you start up
55:32
again. You have to wait this initial compile time again
55:34
because there's no discussion yet. Now
55:36
when we have this caching, you can just go
55:38
from the point where you left off. So
55:41
the last time you run the
55:43
compiler. And now you might
55:45
be thinking, oh, but this might make sense for
55:47
builds as well. Because my builds are in the
55:49
cloud. And maybe they can
55:51
store all that and then restore it and
55:53
make my builds almost instant. Because you just
55:56
told me about this smaller graph
55:58
that can just recompile changes. sick
58:01
pics and shameless plugs. I'm not sure if
58:03
you came prepared with those. I
58:06
think I have like one kind of
58:08
into a sci-fi series. And
58:11
if you're into sci-fi series, I highly recommend
58:13
Apple TV Plus, which
58:16
is like, for some reason,
58:18
they keep putting out more sci-fi series.
58:21
We don't have particular like here in
58:23
the Netherlands, because I'm not from the
58:26
US, like they don't have like specific
58:28
like sci-fi channels like the sci-fi channel
58:30
itself, the kind of thing. So
58:32
like a lot of that is like on Apple
58:34
TV. So I don't
58:36
think I realized how many different sci-fi
58:38
shows they had, because I guess is
58:41
silo considered sci-fi or foundation
58:43
for all of mankind? It's like
58:45
wow. Yeah, it's it's pretty crazy.
58:47
Like overall, I had never thought
58:49
of like after before and like
58:52
I opened it once accidentally, I
58:54
was like, huh, this is interesting.
58:56
There seems to be like quite
58:58
interesting like series
59:00
on there. So like silo is pretty good. That's
59:03
like it's all I think they made
59:05
a lot of deals with like book authors as well.
59:07
Yeah, just based on the books a lot. They're
59:11
now also getting like into the like
59:13
documentary about controversial thing
59:15
that happened like like
59:19
the Hollywood Conqueen started watching recently, which
59:21
is by the
59:23
by the creators of the fire
59:25
festival. Oh, really? documentary and things
59:27
like that. Yeah, those are
59:30
there's some pretty good stuff there. So if
59:32
you're interested in in sci-fi, foundation is really
59:34
good as well. It's definitely like they keep
59:36
bringing out like more of those. Not
59:39
sure. Like there must be someone like
59:41
uploads cute. It's like I love sci-fi.
59:43
Yeah, I bet. Yeah. I
59:45
wonder if they have serious data on
59:47
on podcast because I know
59:50
that Hollywood Conqueen podcast is really,
59:52
really hit. So I wonder if they saw that and were like, oh, this
59:54
would be a good doc. You. Huh.
59:57
Cool. Awesome. And shameless plugs. Well, would you like.
59:59
to plug to our audience. Vape Toropec
1:00:02
RC, or like the, yeah, the Toropec RC.
1:00:04
So we have the Nexus 15 RC, which
1:00:07
is like new features using
1:00:09
React 19, some caching
1:00:11
improvements as well. If you didn't like
1:00:14
the previous caching, we
1:00:16
disabled most of it. And
1:00:18
it's all obtained now. We're
1:00:20
definitely listening to feedback there. It
1:00:24
was just too complicated from the start. We
1:00:26
tried to make it very similar to Pages
1:00:28
Rider with automatic
1:00:31
static generation. But
1:00:33
it became complicated in the cases where you
1:00:35
do want to be dynamic. So there are
1:00:37
just better defaults now. You
1:00:39
can opt into more static behavior once
1:00:41
you want to optimize more, basically. It's
1:00:45
purely based on feedback and
1:00:48
just giving people the thing that they
1:00:50
want to build better websites. Besides that,
1:00:52
yeah, Toropec is an RC for development
1:00:54
now. So that means please
1:00:57
try it out. If you have any issue,
1:00:59
like literally any issue, if it's slow, anything
1:01:02
like that, tweet at me or open
1:01:04
an issue on GitHub. We're actively working
1:01:06
on it. We have like
1:01:09
30 open issues left
1:01:11
so far before like development
1:01:13
is fully done. And then
1:01:15
we'll shift to working
1:01:17
on builds as well and bring
1:01:19
you that persistent caching and FTP
1:01:22
builds and things like that. I'm excited
1:01:24
for that. I have
1:01:26
one more shameless plug as well, which
1:01:28
you'll like. There is. It's
1:01:32
about Sentry, actually. Oh, OK. Let's hear it. I'm
1:01:34
not sure if you know. I
1:01:36
think its name is Luca. So
1:01:38
Luca on the Sentry Nexus
1:01:40
SDK team has
1:01:43
been doing some contributions to Next to basically
1:01:45
allow Sentry to reason about server side errors
1:01:50
that are then sent to the client with
1:01:52
a special digest. I'm not sure if you've
1:01:54
seen that in Next. We need
1:01:56
to hide all the data because we don't
1:01:59
want you an error, you don't want
1:02:01
that to end up in the client, because in some guys
1:02:03
it contains anything that could be
1:02:05
secret. But now
1:02:07
Sentry can actually reason about that
1:02:10
particular error that happened on the server, as
1:02:12
well as the thing that happened on the
1:02:14
client, so the thing you saw on the
1:02:16
client. So it can actually mark
1:02:18
the session as like, this is the error that
1:02:20
was related to that particular digest. So you can
1:02:22
search for the digest in the UI as well,
1:02:24
which is pretty neat. Oh,
1:02:27
that's awesome. Yeah, we'll link
1:02:29
that up as well. Sentry
1:02:31
is doing a lot for that. I
1:02:34
know you guys did some work on the
1:02:36
hydration stuff. Sentry has been constantly working
1:02:38
on getting better hydration issues. And
1:02:42
what is the source maps? It's one thing Sentry
1:02:44
is spending a ton of time on pushing
1:02:47
forward in JavaScript in general. So
1:02:50
love to see it. Awesome. Well,
1:02:52
thank you so much for all of your time for coming
1:02:55
on. Thank you so much for Next.js, working
1:02:57
on it, as well as coming on today to
1:02:59
school us on all of the stuff that's going
1:03:01
on with React and Next.js. Appreciate it. Thanks
1:03:03
for having me. Thanks, Dan.
Podchaser is the ultimate destination for podcast data, search, and discovery. Learn More