So while that's running in the background, let's talk about what is a remix?
[LAUGH] So remix is a web framework with a laser focus on the web fundamentals or
the foundation of the web, web standards, and modern UX.
And throughout this workshop, hopefully, it will become clear to you that remix is
a remix of the mental model of the easy web of the late 90s or early 2000s.
With the user experience, the users expect of the modern web.
That is the idea, that's why it's called remix.
You're remixing that.
How simple it was to build apps years ago with how complex apps
are today from the user experience standpoint.
So let's talk about a couple of things about remix and what this means.
Really quick, I guess on this,
remix is a server-rendered web application or web framework.
So there's no static site generation with remix, and that is extremely intentional.
The best UX is impossible with SSG, that's it.
Your best UX is only possible if you're server rendering your application.
So there are very few exceptions to this,
but they do exist, so I should acknowledge those.
But the best possible UX for 99% of cases is to server render.
So one thing that remix has that I think that you're really going to love and
we'll have exercises for this is nested routing.
You might be familiar with nested file system based routing from NestJS or
Gatsby, and remix has a convention as well for this.
But remix also has layout nested routing,
where the UI is associated to the URL segments.
And so you can have multiple routes on the page active
at the same time actually similar to the hierarchy of your URL.
So we have route modules in remix, each file is a route.
And then that route can actually have child routes.
And so here's our root route, and it's responsible for
everything between the opening HTML and the closing HTML.
And then somewhere in there, it says, if I have any children, this is where they go.
And in this case, we say, I'm in charge of the left nav,
and if I have any children, they go on the right.
And the child here is the sales route.
And then sales says, I'm in charge of the header,
and if I have any children, they go below the list of links.
And then we're at the invoices route.
And invoices says, I'm in charge of calculating this bar chart or whatever.
I don't know what kind of chart that is, this chart.
[LAUGH] And then if I have any children,
then the invoices is also responsible for the list of invoices.
And then if I have any children, this is where they go.
And this is amazingly awesome to develop with.
So if you don't have layout UI routes, then what you're left with is,
because most of your routes are gonna be using a lot of the same layout, right?
So for other or non-layout route conventions,
if you have the invoice id.tsx that you've got for
Gatsby or Nest, that route is responsible for
the entire page when that route is active.
So if we're on this page or on this URL,
then the entire page is the responsibility of that one route.
That means that it has to render the left nav, it has to render logo, it's got to
render the top nav, all of that stuff is the responsibility of that one file.
And so as is the invoices index route, or the sales index route, or whatever, like
sales/subscriptions route, all of them are gonna be responsible for the entire page.
And what do we do when we have a lot of duplication?
We try to move it into an abstraction, right?
So this is why you have a layout component in most of these other frameworks,
is because we want to reduce that duplication.
But the problem with that now is that if you wanna server render this,
each one of those routes is also responsible for
loading the data that you have to pass as props.
And so every one of the routes has to load the data for that.
So what inevitably is gonna happen, and
especially in an app with a large team, is you'll have a lot of or
different teams who are responsible for different parts of the app.
And at PayPal, where I was working, we had a team at PayPal that was responsible for
the header and the footer, and we had to call into their service and
get their HTML and then stick it in our stuff.
It was kinda weird.
But in a React component type of app, you're going to have the team that's
responsible for the layout component in there.
They say, hey, we need these props.
And let's say that they decided,
hey, we're gonna put the currently logged in user's avatar up here.
So they have a choice, they can either say, hey,
all 30 teams that are responsible for this app, you have this new
data that you need to request at server render time and pass that as a prop to us.
That probably is not awesome, so maybe they'll try to update it themselves and
they may pull requests for all of these.
And then they'll have to have maybe a fallback in case that a team doesn't merge
it in time or whatever, which also sounds like a lot of work.
So you know what normally happens is they say, the heck with it,
we're not going to server render this, we're just gonna go load it on the client.
And so that's why when you go to a lot of sites,
they'll have a little spinner in place of your avatar because they just gave up.
And then they decide it's also such a huge burden,
we're gonna start doing microfinance and stuff like that so
we can have complete isolation from each other because it's hard to work together.
With nested routing though, you don't have this problem at all,
because the team that's responsible for this left nav or the header or footer,
they're gonna be in charge of the root route.
And they take care of loading the data for their route and all of that,
and all they care about the child is to say where the child goes.
This is a dysfunctional family, parent-child relationship.
They don't care about each other.
And so the child doesn't think anything about the parent,
it's totally in isolation.
So any data that it needs, it can get itself.
It's like these children have grown up, I guess.
And there doesn't have to be any parent-child communication at all.
There can be, breadcrumbs is a good example, where the parent needs to know
what children are being rendered so I can render out the breadcrumbs and whatever.
So it is possible, but it's not necessary.
And most of the time, it's totally not.
So in a remix context, you'd have to run into a lot of problems before you
start thinking about going into the complexities of microfinance.
Just because the team isolation is just so nice and
works well with the nested routing.
So this is why nested routing is so cool, and we've got some exercises about that.
Okay, so another thing that remix focuses on is thanks to
the fact that it's server-side rendered,
we hate this loading spinner experience that we've all become accustomed to.
So check this out.
Chase.com, sorry if you're Chase engineers,
look at how many spinners there are, I'm not even logged in.
Look at that.
And this is totally a normal experience for users of the web.
Yeah, I go to my banking website, I go to my power company website,
my kid's school website, all of them just have bounced around junkiness.
Even youtube.com has a bunch of bounce around
junkiness as you're loading that initial page.
I do not think that's awesome.
Personally, I feel like we've been conditioned to accept this, but
it does not have to be this way.
You can have a server render that renders all the HTML that the user needs.
And the first thing that they see is the finished thing with the no content
layout shift.
Now, of course, there are some situations where loading or
server rendering might be a little bit of a challenge.
And so we're not gonna put our foot in the ground and say,
you cannot load any data on the client.
Take, for example, a product listing page that has reviews, and
maybe the review stuff, it's not that important, at least for
the initial render, maybe that backend is really slow, whatever.
And so yeah, we can defer that, wait for that to come on the client.
We don't need to server render that piece.
And remix gives you really great levers for
controlling what's gonna cause the content layout shift versus
what's gonna make the response take a little bit longer on the outset.
And we'll talk about that in the advanced remix workshop.
We'll have an exercise for that.
But the key thing here is that remix gives you really nice levers
to choose between the content layout shift nonsense that we are so accustomed to and
the really nice user experience of something that progressively enhances.
Amd we've gotten an exercise on that as well, so look forward to that.
We say, goodbye to spin, again, with remix.
Another really cool aspect of remix is that it is your bundler,
your compiler, your data fetching library, and your router.
It's all of those things.
And because it's all of those things, it can do a lot of awesome things,
also because it has nested routing.
So what we're able to do is we know all of your data requirements and
your code requirements just by looking at the URL.
And so what that means is we don't have to render any components
before we know what data to load.
So we can actually prefetch stuff when the user is interacting with your application.
So when your component is rendered, we can go prefetch the data, or
if the user hovers over your link or however you configure this.
And so that actually makes the whole experience feel really fast for users.
So as soon as the user says, hey, I'm gonna go over to this invoice,
we can actually start requesting the CSS, the data, and
the JavaScript that we're going to need when the user gets there.
And so by the time they click, it's already loaded.
It feels like the entire application was downloaded the instant that they showed up
to the app, which of course, it wasn't because most apps we wanna split up
on route boundaries so that the initial load is much faster.
So, that's another thing.
And what's really cool about this is we're just using the platform for this.
This isn't just some JavaScript in memory cache that gets blown away when you close
the tab, and then you open the tab again, you're like, never mind,
I do wanna go there, and you got to load up the cache again.
You don't have to do that because we're just using link tags with prefetch.
And this couldn't be easier, and we've got an exercise for
that too that you can look forward to.
Data loading is an interesting thing that frameworks typically nail,
it's easy to load data.
What's tricky is what to do when a mutation needs to happen,
when somebody needs to change the data.
That's where things get complicated, accepting remix.
In remix, we just use forms, the way the web was designed from the beginning,
where you're just like, if you need to make a mutation, you use a form.
Now, the regular forms are not quite as powerful as a fetch request because
you have to do a full page refresh, and so now you've got all the problems
with accessibility and various things in that way.
But the mental model was sure nice.
And so remix brings that mental model that's
really simple with the UX that we expect in modern applications.
And you literally just have a form, and then in the same file,
you have an action, that's your server side code for handling this form.
And away you go.
And remix will take care of everything including form resubmission or
revalidation of data.
So as soon as the post request is finished,
we'll revalidate the data just the same way that the web always works, right?
When you submitted a form, you get a full page refresh, and
the new HTML you got was all up to date.
Remix simulates the same thing, we call it a browser emulator.
And so you get a successful post requests.
Remix is like, okay, all bets are off on the data I've got,
so let's just go revalidate all that data.
Now, of course, there's a way to fine tune some of that if you need that
optimization, but the point is the default is correct, and I think that's valuable.
Remix also handles resubmissions, so if the user posts again,
then the data that was coming back doesn't matter anymore,
because it's gonna be wrong, so we just cancel that automatically for you.
And then we'll revalidate the data when that one's finished.
And this is great because remix also handles race conditions for you as well.
Something that we typically don't think about, because when you're on your laptop
and everything's running locally, you're not gonna have race conditions.
But in the real world, that traffic went the wrong way or
something weird happened, and race conditions happen all the time.
Hard problems to replicate and actually real problems for
our users, so remix manages all of that for you as well.
And then because remix is managing that for you, it gives you hooks, ways to hook
into what remix is doing so that you can give some really nice pending UI.
This is where we go from, well,
the web could do that forever ago to, that's actually quite nice.
This was actually pretty difficult to do before being able to just use
JavaScript in the browser.
And so yeah, really nice way to do pending UI, and
even nicer ways to do optimistic UI than anything you've ever seen.
I promise, I've done optimistic UI in every framework.
And remix makes it the easiest of anything I've used.
The last thing is, I love this, [LAUGH] what happens when there is an error?
I've been meaning to update this to a rick roll, so I need to do that but.
[LAUGH] I think it just takes you to our error docs or something.
But error boundaries, this is something that we're gonna be talking about today.
React error boundaries is something that some of you might be familiar with.
It's a way to wrap up part of your component tree, and
if any errors happen in that component tree, it'll replace what errored out with
a fallback that you provide, so you can say, hey, this part of the app is busted.
The problem with React error boundaries is they don't work on the server render.
So if you're doing a server render, something blows up,
React can't reconstruct anything cuz it was in the middle of rendering.
So it's just like it blows up and now you're just left with let's try to render
the header and the footer with a little koala in the middle with a tear running
down this face saying, I'm sorry, that's what we do, right?
In remix, we have route error boundaries, and so
you can export an error boundary component say, hey,
if this route experiences an error, then let's render this instead.
And what's really cool about this is it's not just what happens in the component but
also what happens in some of your server code as well will result in rendering
an error boundary.
And then we also have catch boundaries, which we will talk about.
So if things blow up, I love that.
Then we get contextual errors.
This actually has impact on your business, because the difference between this
experience and koala with a tear running down its face is the user calls up and
says, hey, support, I'm getting the koala with a tear down its face,
or I'm getting the unicorn GitHub, or I'm getting the sad whale, Twitter.
Twitter, they do?
I don't know what they do anymore.
But that's not very helpful for the support team,
they don't know who to direct that to.
But if you have contextual errors, then the user can say, hey,
this invoice is busted, right, the rest of the app still works.
So if I go to this invoice, everything's fine, it's just this invoice.
And so now their support is like, let's go talk to the data team,
there's some messed up data, probably a bad migration or
something for that particular piece of data.
So, impact on your business, also, it's conceptually simpler, so better UX for
you, too.
So there's a lot more stuff to talk about with remix, but
we want to actually do some exercises, I think.