slice-machine icon indicating copy to clipboard operation
slice-machine copied to clipboard

RFC: Port the `routes` resolver to Next.js

Open arnaudlewis opened this issue 4 years ago • 8 comments

Part of the port of SliceMachine to Next consists in porting the routes resolver.

What is routes

To use prismic with your application, you need at some point to be able to resolve the URL of a prismic document. To do so, in Prismic we have the concept of linkResolver but with SliceMachine, we introduced a new way that is called routes. It's a declarative way of configuring your routes and it's send to prismic so the API returns the URL of the document right away without having to compute it on your application.

Context

Today a typical routes configuration would look like this:

[{
  path: "/posts/:uid",
  type: "post"
}, {
  path: "/",
  type: "homepage"
}]

But in Next.js, when you build a link you need two things, the url and the href. It would typically look like this:

<Link href="/posts/[uid]" as="/posts/myFirstPost" />

This href property is specific to Next.js and we need to make it easy to build from the routes configuration.

Implementation

We could create a specific model dedicated to Next.js that would generated from the routes and it would look like this:

{
  post: {
    path: "/posts/:uid",
    href: "posts/[uid]"
  },
  homepage: {
    path: "/",
    href: "/",
  }
}

That model would be exported in a module inside the user project so it could be used at any time to build links.

A Link would have this form considering that you have a docLink that represents a content relationship:

import Routes from 'routes';

<Link href={Routes[docLink.type].href} as={docLink.url} />

It also mean that anytime you want to add a route, you only edit this module and we would have some kind of lib that automatically convert it back to the original format so it can be send to Prismic and automatically resolve the URLs in the API.

arnaudlewis avatar Jun 15 '20 13:06 arnaudlewis

That's really good. My only consideration is that Next Link props should not be passed inside components directly, as it would prevent library creators from creating cross framework components. In a same fashion they should not import a framework specific Link in their components.

Something more suitable would be for the SliceZone to pass something like LinkComponent and resolveLinkProps props (or via context) to each slice. Library creators would then use the Link this way:

<LinkComponent {...resolveLinkProps(docLink)} />

while the Next resolver would look like:

import routes from '../my-routes'

return ({ type, url }) => ({ href: routes[type].href, as: url, passHref: ... })

hypervillain avatar Jun 15 '20 13:06 hypervillain

Do you think that we should have some kind of module for next that automatically convert back this specific model to the original one that we can send to prismic through the JS kit @hypervillain ? I don't know how yet but just to prevent people having to edit two different models that represent the same thing.

arnaudlewis avatar Jun 15 '20 13:06 arnaudlewis

I tried to implement a converter like this some weeks ago, unfortunately I could not access the routes list programmatically. But if you implement the new model I guess that would work fine. Of course, an optimal solution would be for Next.js router to expose the routes parsed at build time.

hypervillain avatar Jun 15 '20 13:06 hypervillain

import routes from '../my-routes'

return ({ type, url }) => ({ href: routes[type].href, as: url, passHref: ... })

Not sure but aren't Next users already using an hrefResolver? We could just use it here instead and have the Next slice-zone provide itself the right link component to slice (similar to what we're doing with Vue prismic-link component at a framework level)?

import { hrefResolver } from 'path/to/hrefResolver'; // provided to slice-zone

return doc => ({ href: hrefResolver(doc), as: doc.url, passHref: ... })

lihbr avatar Jun 15 '20 16:06 lihbr

I guess some of them do, if they come from this starter: https://github.com/prismicio/nextjs-blog, I don't really know otherwise.

If we want to keep using resolvers, that would be perfectly fine to me. But as we removed the linkResolver in profit of routes, we probably want to ditch the hrefResolver too. A difference between routes (JSON) and hrefResolver (js) is also that we may be able to access your routes from inside the SliceZone, which makes it possible for us to write a default resolver there

hypervillain avatar Jun 15 '20 16:06 hypervillain

<LinkComponent docLink={docLink} />

while the Next resolver would look like:

import routes from '../my-routes'

return LinkComponent: ({ docLink }) => {
  return <Link href={routes[docLink.type].href} as={docLink.url} />
}

Proposed by @sadache

arnaudlewis avatar Jun 16 '20 10:06 arnaudlewis

Just some thoughts about that link issue with React, but I feel like we're trying to solve this issue at a Slice Machine level when it should be solved at a SDK level :thinking:

Have we tried to implement a PrismicLink component in React just like we did with Vue?

I get it that APIs of Next.js and Gatsby are differents for links but since people will have to setup React SDK on their project anyway (and providing an hrefResolver according to the doc for Next.js usage) I don't see an issue with them having to import a prismicLinkNext function which takes their hrefResolver as an argument and then returns a component extending the Next.js Link component, creating their PrismicLink component this way that they can export and use wherever they need to handle links coming from Prismic this simple way?

// ./PrismicLink.js
import { prismicLinkNext } from "prismic-reactjs";
import hrefResolver from "./hrefResolver";

export default prismicLinkNext(hrefResolver);

// Then anywhere on the project (SliceZone getting this component as a prop,
// allowing slices libraries developers to use it)
import PrismicLink from "./PrismicLink";

return <PrismicLink field="menuLink.link">...</PrismicLink>;

As a benefit this will prevent users from having to maintain both an hrefResolver and a resolveLinkProps (only existing hrefResolver will remain) while still allowing them to use framework-specific props on their PrismicLink? (since we'll also have a prismicLinkGatsby function (or just straight up a PrismicLink component for Gatsby since it doesn't need more resolvers) returning a PrismicLink component extending Gatsby link).

Hope that makes some sense~

lihbr avatar Jun 16 '20 12:06 lihbr

Update 02/17/2021:

  1. I'm not sure what's the status of Next regarding that, if that's resolved we can close.
  2. Having PrismicLink components for Next and Gatsby just like Vue is still a nice idea imho.

lihbr avatar Feb 17 '21 17:02 lihbr

Closing, Next.js is now fully supported, get started now: https://prismic.io/docs/technologies/nextjs

lihbr avatar Sep 22 '22 12:09 lihbr