Giter Club home page Giter Club logo

nextjs-prefetch-with-rewrite's People

Contributors

ericmatthys avatar

Watchers

 avatar

Forkers

sinanbekar

nextjs-prefetch-with-rewrite's Issues

Discussion: Fix Pre-fetching

On the website (watch.plex.tv), I've realized that link pre-fetching is not working so on every routing the page is fully refreshing which slows down the browse experience. I came across the Plex Engineering Medium article by chance and I found this repo also viewed the open issues on Next.js.

I forked the repo and implemented some demos with no pre-fetching issues.

GitHub forked repos:

Rewrites with X-Vercel-IP-Country header: https://github.com/sinanbekar/nextjs-prefetch-with-rewrite-country
Rewrites with cookie: https://github.com/sinanbekar/nextjs-prefetch-with-rewrite-cookie
Rewrites with header (host): https://github.com/sinanbekar/nextjs-prefetch-with-rewrite

Vercel Deploys:

Rewrites with X-Vercel-IP-Country header: http://nextjs-prefetch-with-rewrite-ip-country.vercel.app/
Rewrites with cookie: https://nextjs-prefetch-with-rewrite-cookie.vercel.app/
Rewrites with header (host): https://nextjs-prefetch-with-rewrite-host.vercel.app/

Here are my opinions:

The errors occurred in both development and production so I don't think that is related to Vercel deployments.

Next.js rewrites with has worked well for me except header type. I tested the cookie type you can see in the production demo above and there was no problem so I thought that it may be the header parsing-related issue because as we all know the cookies and custom headers are available in the same HTTP Request header (but we can't access all of them by native ways in the client-side).

Interestingly, when I specified the header key to host it worked well except for one thing:

Client-side router behavior was different compared to server-side and it's possible because of the separated routers.

Fully refresh Client-side transition

I dived a little bit deeper.

It looks like they are passing the header only with host as a req param to matchHas method for the client-side router.

--continues--

https://github.com/vercel/next.js/blob/0355e5f63f87db489f36db8d814958cb4c2b828b/packages/next/shared/lib/router/utils/resolve-rewrites.ts#L38-L59

  // packages/next/shared/lib/router/utils/resolve-rewrites.ts#L38-L59
  const handleRewrite = (rewrite: Rewrite) => {
    const matcher = customRouteMatcher(rewrite.source)
    let params = matcher(parsedAs.pathname)

    if (rewrite.has && params) {
      const hasParams = matchHas(
        {
          headers: {
            host: document.location.hostname,
          },
          cookies: document.cookie
            .split('; ')
            .reduce<Record<string, string>>((acc, item) => {
              const [key, ...value] = item.split('=')
              acc[key] = value.join('=')
              return acc
            }, {}),
        } as any,
        rewrite.has,
        parsedAs.query
      )
  .
  .  
  .

https://github.com/vercel/next.js/blob/0355e5f63f87db489f36db8d814958cb4c2b828b/packages/next/shared/lib/router/utils/prepare-destination.ts#L12-L48

// packages/next/shared/lib/router/utils/prepare-destination.ts#L12-L48
export function matchHas(
  req: BaseNextRequest | IncomingMessage,
  has: RouteHas[],
  query: Params
): false | Params {
  const params: Params = {}

  const allMatch = has.every((hasItem) => {
    let value: undefined | string
    let key = hasItem.key

    switch (hasItem.type) {
      case 'header': {
        key = key!.toLowerCase()
        value = req.headers[key] as string
        break
      }
      case 'cookie': {
        value = (req as any).cookies[hasItem.key]
        break
      }
      case 'query': {
        value = query[key!]
        break
      }
      case 'host': {
        const { host } = req?.headers || {}
        // remove port from host if present
        const hostname = host?.split(':')[0].toLowerCase()
        value = hostname
        break
      }
      default: {
        break
      }
    }
   .
   .
   .

We know that there is no native way to get request headers except available in document (host, cookies), and it seems that they don't want to pass the headers to the client-side.
https://stackoverflow.com/questions/220231/accessing-the-web-pages-http-headers-in-javascript

My Suggestions

Except for modifying core behavior, I think cookies can be used. On every request, Next.js middleware will get the X-Vercel-IP-Country header and set the cookie. Also, I use header type rewrite for fallback. But not sure if it is the best practice, currently works well even deleting the cookie manually. It fully refreshes and sets the cookie when the cookie does not exist then continues with prefetching. But reconsideration is needed for spoofing etc.

https://github.com/sinanbekar/nextjs-prefetch-with-rewrite-country
http://nextjs-prefetch-with-rewrite-ip-country.vercel.app/

At rewrites#header-cookie-and-query-matching, We can see that there is an example with the HTTP GET queries (searchParams) but I think there will be no problem because it does not includes a dynamic route.

      // if the header `x-authorized` is present and
      // contains a matching value, this rewrite will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },

I believe that there should be also a warning on the documentation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.