When you create a Sitecore Next.js project you will notice there is a configuration file generated, called next.config.js
. This config holds different Sitecore related config entries, but in this post I would like to focus on the async rewrites()
method. This is a Next.js feature, to handle rewrites in the app. Rewrites can be useful for several things. By default Sitecore uses rewrites to proxy the media and some Sitecore API requests.
async rewrites() { | |
// When in connected mode we want to proxy Sitecore paths off to Sitecore | |
return [ | |
// media items | |
{ | |
source: '/-/:path*', | |
destination: `${jssConfig.sitecoreApiHost}/-/:path*`, | |
} | |
]; | |
} |
You need these rewrites when your Sitecore CD servers in private network and not exposed publicly to serve media files. To use these rewrites are good enough until you develop locally or you rebuild the application for each stage (e.g. DEV, QA, UAT, PROD).
Problem
The problem is not related to Sitecore at all. After few hours of troubleshooting with Benjamin Gyuro we found how Next.js rewrites configurations are working. Here is the GitHub issue which explains it in detail. The problem in a nutshell, that the rewrites needs to be generated in build time (in the routes-manifest.json
) instead of runtime, therefore we can’t use environment variables which differs on each stage. If you use Docker or Kubernetes you don’t want to build different Docker images just because a variable is different on each environment.
Solution
I would like to point out, this solution only works/tested for media items. The idea was to implement an API in the Next.js app which then requests for the media item from Sitecore and responding with content served by the Sitecore CD server. For this I used axios
with forwarding the request headers. The following index.ts
should sit in the /api/rewrite-sitecore-media
folder in my example.
import axios from 'axios'; | |
import { NextApiRequest, NextApiResponse } from 'next'; | |
/** | |
* Custom API implementation for rewrites to support runtime rewrite config | |
* https://github.com/vercel/next.js/issues/21888 | |
*/ | |
export const handler = async (req: NextApiRequest, res: NextApiResponse): Promise<void> => { | |
const newPath = req.url as string; | |
if (newPath) { | |
const url = `${process.env.SITECORE_API_HOST}${newPath}`; | |
const { data, status, headers } = await axios({ | |
url, | |
responseType: 'arraybuffer', | |
}); | |
// map headers | |
Object.entries(headers).map((h) => res.setHeader(h[0], (h[1] as string) ?? '')); | |
res.status(status).send(data); | |
} else { | |
res.status(400).json({ error: 'Request URL was not provided.' }); | |
} | |
}; | |
export default handler; |
Then the rewrites
should be adapted a bit, like the following:
async rewrites() { | |
// When in connected mode we want to proxy Sitecore paths off to Sitecore | |
return [ | |
// media items | |
{ | |
source: '/-/:path*', | |
destination: '/api/rewrite-sitecore-media', | |
} | |
]; | |
} |
You probably notice, that the destination
does not contain the :path*
token anymore. This is because it’s a rewrite, which means there is no extra request called so I can just use the req.url
in the API implementation.
Thanks guys, this saved me a day. Good job.
LikeLiked by 1 person