slice-machine
slice-machine copied to clipboard
RFC: Port the `routes` resolver to Next.js
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.
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: ... })
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.
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.
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: ... })
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
<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
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~
Update 02/17/2021
:
- I'm not sure what's the status of Next regarding that, if that's resolved we can close.
- Having PrismicLink components for Next and Gatsby just like Vue is still a nice idea imho.
Closing, Next.js is now fully supported, get started now: https://prismic.io/docs/technologies/nextjs