State of the Sitecore Docker + Next.js Starter Kits
At the time of writing these lines, whether you create a project from the XM starter kit or the XM Cloud starter kit, both are affected by the same issue: CORS errors in the browser console in the Experience Editor. This only occurs on development environments on Docker. This does not happen on hosted XM Cloud environments. This could also happen on hosted XM environments.
In this blog post, we will cover the Docker development environment scenario.
How Do I Know if I Have CORS Errors?
In Experience Editor, open the browser developer tools in the console tab. If you see CORS errors similar to those, you are affected by this issue:
- Access to fetch at 'https://www.mysite.localhost/_next/static/development/_devMiddlewareManifest.json' from origin 'https://xmcloudcm.localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
- GET https://www.mysite.localhost/_next/static/development/_devMiddlewareManifest.json net::ERR_FAILED 200 (OK)
- Access to resource at 'https://www.mysite.localhost/_next/webpack-hmr' from origin 'https://xmcloudcm.localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
- Access to fetch at 'https://www.mysite.localhost/api/yourApi' from origin 'https://xmcloudcm.localhost' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
- This can happen if you call a Next.js API route from the client-side code.
Why Are There CORS Errors?
When running the Experience Editor, the page domain is the Content Manager (CM) domain: https://xmcloudcm.localhost/
However, the HTML in the DOM of the Experience Explorer is coming from the rendering host. The Experience Editor asks the rendering host to return the server-side rendered (SSR) version of the page in edit mode: https://${RENDERING_HOST}/api/editing/render
The HTML page returned by the rendering host contains many absolute URLs with the rendering host domain as the rendering container PUBLIC_URL
environment variable is by default set to "https://${RENDERING_HOST}"
. For the XM Cloud starter kit, it translates to https://www.sxastarter.localhost
.
As the Experience Editor HTTP response does not specify any Access-Control HTTP headers, the requests to the absolute rendering host URLs are blocked by the browser CORS protections.
How to Get Rid of the CORS Errors?
This solution consists of adding the required HTTP headers to all the responses of the rendering host Next.js application. One way to achieve that is by configuring the Traefik HTTP proxy to do it.
- Edit your project
docker-compose.override.yml
file. - Locate your
rendering
service. -
Locate the service
labels
. You will usually find these:labels: - "traefik.enable=true" - "traefik.http.routers.rendering-secure.entrypoints=websecure" - "traefik.http.routers.rendering-secure.rule=Host(`${RENDERING_HOST}`)" - "traefik.http.routers.rendering-secure.tls=true"
Yours may be slightly different.
-
Add the following labels just after your last one.
# BEGIN CUSTOMIZATION - Add CORS headers to fix CORS issues in Experience Editor with Next.js 12.2 and newer - "traefik.http.middlewares.rendering-headers.headers.accesscontrolallowmethods=GET,POST,OPTIONS" - "traefik.http.middlewares.rendering-headers.headers.accesscontrolallowheaders=Content-Type" - "traefik.http.middlewares.rendering-headers.headers.accesscontrolalloworiginlist=https://${CM_HOST}" - "traefik.http.routers.rendering-secure.middlewares=rendering-headers" # END CUSTOMIZATION
-
You will end up with the following configuration:
labels: - "traefik.enable=true" - "traefik.http.routers.rendering-secure.entrypoints=websecure" - "traefik.http.routers.rendering-secure.rule=Host(`${RENDERING_HOST}`)" - "traefik.http.routers.rendering-secure.tls=true" # BEGIN CUSTOMIZATION - Add CORS headers to fix CORS issues in Experience Editor with Next.js 12.2 and newer - "traefik.http.middlewares.rendering-headers.headers.accesscontrolallowmethods=GET,POST,OPTIONS" - "traefik.http.middlewares.rendering-headers.headers.accesscontrolallowheaders=Content-Type" - "traefik.http.middlewares.rendering-headers.headers.accesscontrolalloworiginlist=https://${CM_HOST}" - "traefik.http.routers.rendering-secure.middlewares=rendering-headers" # END CUSTOMIZATION
These labels are used by the
Traefik
container to:- Create a new
rendering-headers
Traefik middleware. - Define 3 HTTP headers on this middleware:
- Access-Control-Allow-Methods:
GET,POST,OPTIONS
- Access-Control-Allow-Headers:
Content-Type
- Access-Control-Allow-Origin:
https://${CM_HOST}
- The
CM_HOST
variable is usually defined in the main.env
file. - On an XM Cloud project, its value is most of the time
xmcloudcm.localhost
. Thus, the allowed origin becomeshttps://xmcloudcm.localhost
. - On an XM/XP project, its value is usually
cm.<your_project_name>.localhost
. Thus, the allowed origin becomeshttps://cm.<your_project_name>.localhost
.
- The
- Access-Control-Allow-Methods:
- Attach this new Traefik middleware to the existing
rendering-secure
Traefik router.
- Create a new
- Save the file.
- Assuming your solution is already initialized, and your containers are already running: In a PowerShell terminal running as administrator in your solution folder, restart the
rendering
container by running thedocker compose up -d
command.- This will compare the running containers with the Docker compose configuration, and recreate the containers with a modified configuration.
- Wait for the containers to be ready.
- Monitor your
rendering
container logs to know when it has compiled the next.js project and it is ready to receive requests. - Access the Experience Editor and enjoy having no CORS errors anymore.
Wrapping Up on CORS Errors
I hope you better understand the cause of Experience Editor CORS errors and this solution worked for your project. Other solutions might include configuring Access-Control HTTP headers directly in the Next.js application next.config.js
file or as a Next.js middleware.
Happy Sitecoring!