kwicherbelliaken / bad-reviews-make-good-movies

0 stars 0 forks source link

[FIX]: page load time between entry and watchlist #62

Closed slackermorris closed 9 months ago

slackermorris commented 9 months ago

I mean the page is generated server side.

slackermorris commented 9 months ago

I should read this article to better understand client directives.

I also think that WatchlistMovies needs to be converted into a React component so that I might have a loading UI.

slackermorris commented 9 months ago

See how quickly the page loads without the WatchlistMovies component being introduced.

slackermorris commented 9 months ago

What are the demands of the Watchlist list of movies component? It will eventually need client interactivity because I will update.

Think about having a sort of scratch pad to write thoughts down on and when you hover on the movie it shows all these different scrawls and that.

slackermorris commented 9 months ago

This component renders server side. Data fetching is serverside.

Screen Shot 2023-11-20 at 8 23 43 AM
slackermorris commented 9 months ago

React too will be rendered on the server and passed down? Will the loading state be respected? I am little confused.

slackermorris commented 9 months ago
  1. We land on the page.
  2. WatchlistMovies component is server rendered. It makes a fetch call to get all the movies.
  3. WatchlistMovie component is server rendered. It makes a fetch call for the Movie Poster it needs.

At this point we have a waterfall. I am not taking advantage of any part of the islands architecture.

slackermorris commented 9 months ago

THIS IS WORTHWHILE WRITING UP IN CONJUNCTION WITH OTHER NOTES

SSR data is fetched and then passed to the component, cannot do check to see if the code is running in the browser like:

Screen Shot 2023-11-20 at 8 38 10 AM
slackermorris commented 9 months ago

Is it necessary that I SSR this component. Or can be it statically generated? The content will change because the user can add and subtract stuff from the Watchlist. I think I need to whiteboard this out.

slackermorris commented 9 months ago

I quite like this when a user loses internet connection.

Screen Shot 2023-11-20 at 8 52 24 AM
slackermorris commented 9 months ago

If my page is rendered on the server then why is there a delay?

slackermorris commented 9 months ago

It just feels like the WatchlistMovies loads after the Search Panel. You can notice the jump between the loading of the two things here:

https://github.com/slackermorris/bad-reviews-make-good-movies/assets/35620369/4ad4d0aa-2e08-48c6-bce9-0770a727f80e

slackermorris commented 9 months ago

It seems like the fetch for retrieving the movies is causing this component to render more slowly. Perhaps something to do with the islands architecture?

slackermorris commented 9 months ago

☝️ Yeah, this does have to do with Islands Architecture:

These placeholders/slots contain the server-rendered HTML output from their corresponding widget. They denote regions that can then be "hydrated" on the client into small self-contained widgets, reusing their server-rendered initial HTML.

All notes can be elaborated upon here.

slackermorris commented 9 months ago

From this search:

Astro allows you to choose on-demand rendering for some, or all of your pages and endpoints. This is also known as server-side rendering (SSR): generating HTML pages on the server when requested and sending them to the client. An adapter is used to run your project on the server and handle these requests.

slackermorris commented 9 months ago

I should definitely sit down and watch this: https://www.youtube.com/watch?v=2ZEMb_H-LYE

slackermorris commented 9 months ago

OMFG I think I found it. I wonder why they don't advertise this:

Astro with server mode it is a little different. When you make a await async call on the server in an Astro component, all the components and markdown underneath that Astro component making the async call will be blocked until the async call is finished. While with NextJS server components you can have a server component that can make a await async call on server and it won't block components from rendering underneath it till it's finished.

James says as much here.

Astro ships the initial page load to the browser and then streams the results of asynchronous calls in the front matter, asynchronously as it receives it.

James says more information can be found from this stream.

slackermorris commented 9 months ago

It's almost like because it is streaming I would like to make use of something like we see with Suspense and be able to declare a loading component.

slackermorris commented 9 months ago

OK. So, one step at a time.

  1. Refactor so the image component requests the image itself.
  2. I know I need to figure a way to have a placeholder for the image as it is being fetched.
  3. Figure out a better way to handle loading state for the WatchlistMovies astro component.
slackermorris commented 9 months ago

I introduced the Astro Image component.

Screen Shot 2023-11-22 at 8 38 30 AM

This is the Image Docs I am looking at.

slackermorris commented 9 months ago

This is why I need to add dimensions.

Screen Shot 2023-11-23 at 8 27 18 AM
slackermorris commented 9 months ago

It seems as though the poster is delaying the rendering of the Watchlist content proper.

I want the WatchlistMovie to render. It has a bunch of content written about it. I then want the image to render.

Does Astro not support this?

slackermorris commented 9 months ago

Fuck it. What does it matter. The picture and remainder of the content should appear at the same time.

I don't think that Astro supports nested routes like how Remix does in offering parts of its page rendering before others.

slackermorris commented 9 months ago

Remixs' nested routes allows for:

In some web applications, the sequential loading of data and assets can sometimes lead to an artificially slow user experience. Even when data dependencies aren't interdependent, they may be loaded sequentially because they are coupled to rendering hierarchy, creating an undesirable chain of requests.

Remix leverages its nested routing system to optimize load times. When a URL matches multiple routes, Remix will load the required data and assets for all matching routes in parallel. By doing this, Remix effectively sidesteps the conventional pitfall of chained request sequences.

slackermorris commented 9 months ago

I think the main feature that I am missing is nested routes. Meh.

slackermorris commented 9 months ago

I hate how we get the momentary flash of the bounding box before everything loads.

slackermorris commented 9 months ago

It's like the HTML renders for the WatchlistMovie, which is just a bounding box, and then we load what is needed for the MoviePoster.

slackermorris commented 9 months ago

It is blocked by the MoviePoster loading..... The MoviePoster depends on the WatchlistMovie being resolved first.

I hate the little flash when there is no content and we get this empty bounding box.

https://github.com/slackermorris/bad-reviews-make-good-movies/assets/35620369/070e39e1-6445-458f-aa30-c50f5baa7beb

It's like it renders the minimum content and then knows it needs to also make a fetch call for the Movie poster and so then delays further rendering of the component. But I am sort of wondering why it does not render with the remainder of the content and then just zip the Movie poster in.

Same weirdness is that it only does this for the first entry in the Watchlist....

slackermorris commented 9 months ago

I don't want anything to render until I am ready for it. Is it possible to split them into siblings?

Fuck this is starting to annoy me.

What do I want as a solution?

I don't want the bounding box to show. I want things when they are actually ready.

slackermorris commented 9 months ago

It's like Astro renders the first component because it anticipates that we will stream results.

slackermorris commented 9 months ago

What happens if it does not need to fetch the Movie?

Even if the Movie Poster url is hardcoded we still get the momentary bounding box before anything else shows.

So, it is as though the image component itself has a certain height associated with it.

slackermorris commented 9 months ago

Why does the p-4 cause there to be an empty bounding box:

<div class="flex justify-center w-[50%] p-4">
        <MoviePoster posterPath={movie.movieDetails.poster_path} />
  </div>

Just the fact that something exists above is enough for it to anticipate something to render.

It is entirely because of the fetch that is happening in the MoviePoster component. This delay means that everything else is delayed from rendering, which does not seem right at all.

slackermorris commented 9 months ago

Interesting if you swap the order of the content from the movie poster then you sort of get the rendering behaviour that we expect.

https://github.com/slackermorris/bad-reviews-make-good-movies/assets/35620369/76d547c0-d206-49f5-b21a-ee6bc09d3161

slackermorris commented 9 months ago

It's as though with SSR it is reading the HTML chronologically. It gets to the closing <div> above the MoviePoster and sends it to the page and then sees the MoviePoster and so stops because it as async data requirements and this blocks everything else from being rendered and so this is why we see this momentary flash of the bounding box because SOME HTML has been rendered:

<div class="flex bg-grey-50 justify-between rounded-lg border p-4">
    <div class="flex justify-center w-[50%] p-4"> 
        <MoviePoster />

I definitely need to write this down somewhere. How can I solve for this?

This is the HTML that results in the flashing content scenario.

---
import MoviePoster from "./MoviePoster.astro";

const { movie } = Astro.props;
---

<div class="flex bg-grey-50 justify-between rounded-lg border p-4 gap-4">

  <div class="flex justify-center w-[50%]">
        <MoviePoster posterPath={movie.movieDetails.poster_path} />
  </div>
  <div class="flex-col w-[50%]">
    <h1>{movie.movieDetails.title}</h1>

    <h2 class="font-afterAllBoldSerif font-bold text-2xl tracking-wide">
      {movie.movieDetails.release_date}
    </h2>

    <p class="indent-7">{movie.movieDetails.overview}</p>

    <div class="py-10">
      {
        movie.movieDetails.cast.map((cast) => (
          <p class="indent-7">
            {cast.name} as {cast.character}
          </p>
        ))
      }
    </div>

    {
      movie.movieDetails.genres.length > 0 && (
        <div class="border-t-[1px] border-b-[1px] border-black flex flex-row gap-4 justify-center py-6">
          {movie.movieDetails.genres.map((genre: string) => (
            <p class="">{genre}</p>
          ))}
        </div>
      )
    }
  </div>
</div>
slackermorris commented 9 months ago

The solution is to move the request for the imageUrl required by the MoviePoster into the front matter for the entire WatchlistMovie component. This way we don't get the WatchlistMovie component unless we also have the image.